feat/vtk-3d-view #7
|
|
@ -1164,6 +1164,13 @@ geopro::core::ColorScale makeStructuralColorScale(double vmin, double vmax) {
|
||||||
|
|
||||||
// 地震高对比色阶(seismic 红-白-蓝):两端饱和亮色(强正=亮红、强负=亮蓝),
|
// 地震高对比色阶(seismic 红-白-蓝):两端饱和亮色(强正=亮红、强负=亮蓝),
|
||||||
// 零附近白。比 structural 更亮、对比更狠,正负反射一眼分开。
|
// 零附近白。比 structural 更亮、对比更狠,正负反射一眼分开。
|
||||||
|
// 前置声明(实现在 polish 段):梯度幅值分位统计,供 C4 画廊的梯度不透明度标定。
|
||||||
|
struct GradStats {
|
||||||
|
double median = 0, p75 = 0, p90 = 0, p99 = 0, mx = 0;
|
||||||
|
std::size_t samples = 0;
|
||||||
|
};
|
||||||
|
GradStats sampleGradientMagnitude(vtkImageData* img);
|
||||||
|
|
||||||
geopro::core::ColorScale makeSeismicColorScale(double vmin, double vmax) {
|
geopro::core::ColorScale makeSeismicColorScale(double vmin, double vmax) {
|
||||||
geopro::core::ColorScale cs;
|
geopro::core::ColorScale cs;
|
||||||
const double span = (vmax > vmin) ? (vmax - vmin) : 1.0;
|
const double span = (vmax > vmin) ? (vmax - vmin) : 1.0;
|
||||||
|
|
@ -2803,32 +2810,45 @@ struct GalleryVariant {
|
||||||
double zoom; // 再 Zoom 填满画面
|
double zoom; // 再 Zoom 填满画面
|
||||||
double bg[3]; // 背景 RGB
|
double bg[3]; // 背景 RGB
|
||||||
const char* desc; // 报告用中文说明
|
const char* desc; // 报告用中文说明
|
||||||
|
// ---- C4 视觉调优(梯度不透明度 + 光照),默认关 → 不改既有变体行为 ----
|
||||||
|
bool useGradientOpacity = false; // SetGradientOpacity:均匀层透明、界面/异常显形
|
||||||
|
bool useShade = false; // SetShade:层界面带立体明暗
|
||||||
};
|
};
|
||||||
|
|
||||||
// 4 组视觉参数。值经离屏实跑挑出(详见报告)。
|
// C4 视觉调优:4 组对照(纯标量 / +梯度不透明度 / +光照 / 全开)。
|
||||||
|
// 同一局部段、同一 seismic 配色、同一斜穿俯视取景(El45/Az30,视线穿进体内部而非
|
||||||
|
// 只看端面)——唯一变量是「梯度不透明度 / 光照」,供肉眼直读"内部结构是否透出"。
|
||||||
|
// maxOpacity 字段:纯标量组用低峰值(0.45,避免均匀积分糊成实心);开了梯度门的组用
|
||||||
|
// 高峰值(0.6)——均匀区被梯度门压透明后,层界面的净不透明度(标量×梯度)才够高、浮成实面。
|
||||||
|
// 末项 var4(全开) = kViewDefaultVariant → 交互窗口默认走全开。
|
||||||
const GalleryVariant kGalleryVariants[] = {
|
const GalleryVariant kGalleryVariants[] = {
|
||||||
// var1:高不透明度实体感——seismic 亮配色 + V 形包络(中段 0.40/两端 0.85),
|
// var1:纯标量不透明度(基线)——无梯度门、无光照。GPR 均匀层段沿射线积分糊成
|
||||||
// floor 压到 0.04:近零层间隙近透明,亮层面浮出 → 内部层状结构可读。
|
// 半透明实心块,只外表面/端面可读,内部水平分层难分辨(对照基准)。
|
||||||
{"var1", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
{"var1", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||||
0.04, 0.40, 0.85, 8.0, 22.0, 28.0, 1.9, {0.05, 0.05, 0.09},
|
0.04, 0.30, 0.45, 8.0, 45.0, 30.0, 1.5, {0.05, 0.05, 0.09},
|
||||||
"高不透明度实体感:V形包络(floor0.04/mid0.40/max0.85)+seismic 亮配色,"
|
"纯标量不透明度(基线):V形包络(floor0.04/mid0.30/max0.45)+seismic,"
|
||||||
"半透明实心、内部层次可见"},
|
"无梯度门/无光照,均匀层积分糊成半透明块、仅端面可读",
|
||||||
// var2:高对比配色——jet 全程高饱和 + 中等不透明度 V 形包络。
|
/*useGradientOpacity=*/false, /*useShade=*/false},
|
||||||
{"var2", OpacityProfile::kSolid, ColorChoice::kJet,
|
// var2:+梯度不透明度——低梯度(均匀层)透明、高梯度(层界面/异常)显形,射线穿透
|
||||||
0.04, 0.32, 0.70, 8.0, 22.0, 28.0, 1.9, {0.06, 0.06, 0.10},
|
// 均匀雾、内部界面浮出。标量峰值提到 0.6(梯度门压透明后层面才够实)。
|
||||||
"高对比配色:jet 蓝青绿黄红全程高饱和 + 中等 V 形包络(mid0.32/max0.70)"},
|
{"var2", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||||
// var3:居中正对纵截面——低 Elevation/Azimuth 摆平、正对 X-Z 长侧面(层状反射沿
|
0.04, 0.30, 0.60, 8.0, 45.0, 30.0, 1.5, {0.05, 0.05, 0.09},
|
||||||
// X 延展最清晰)、Zoom2.0 填满 ~70%;floor 压更低让层间隙透明、层面立体。
|
"+梯度不透明度:低梯度(均匀层)透明、高梯度(界面/异常)显形,标量峰值0.6,"
|
||||||
|
"射线穿透均匀雾、内部界面浮出",
|
||||||
|
/*useGradientOpacity=*/true, /*useShade=*/false},
|
||||||
|
// var3:+光照——在梯度门基础上 ShadeOn,层界面带立体明暗(非纯平涂)。
|
||||||
{"var3", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
{"var3", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||||
0.03, 0.38, 0.82, 9.0, 10.0, 12.0, 2.0, {0.05, 0.05, 0.09},
|
0.04, 0.30, 0.60, 8.0, 45.0, 30.0, 1.5, {0.05, 0.05, 0.09},
|
||||||
"居中正对纵截面:低 El10/Az12 摆平正对 X-Z 长侧面、Zoom2.0 填满视野,"
|
"+光照(梯度门+Shade):层界面带立体明暗(Ambient0.3/Diffuse0.7/Specular0.2),"
|
||||||
"floor0.03 凸显层面,exagg9 放大薄轴"},
|
"界面起伏更有体积感",
|
||||||
// var4:最像真实 GPR 三维图——seismic + 略提背景亮 + 微立体角 + 实体包络。
|
/*useGradientOpacity=*/true, /*useShade=*/true},
|
||||||
|
// var4:全开——梯度不透明度 + 光照 + seismic 双端斜坡配色 + 略亮冷灰背景。
|
||||||
// 综合最佳,选作交互窗口默认(kViewDefaultVariant)。
|
// 综合最佳,选作交互窗口默认(kViewDefaultVariant)。
|
||||||
{"var4", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
{"var4", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||||
0.035, 0.38, 0.84, 8.0, 18.0, 22.0, 2.0, {0.07, 0.08, 0.11},
|
0.04, 0.30, 0.60, 8.0, 45.0, 30.0, 1.5, {0.07, 0.08, 0.11},
|
||||||
"综合最佳:seismic + 实体包络(floor0.035/mid0.38/max0.84) + 微立体取景"
|
"全开(综合最佳):梯度不透明度+光照+seismic+略亮冷灰背景,内部分层界面/异常"
|
||||||
"(El18/Az22/Zoom2.0) + 略亮冷灰背景"},
|
"从均匀块透出 → 交互窗口默认",
|
||||||
|
/*useGradientOpacity=*/true, /*useShade=*/true},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 交互窗口(无 flag 的 view)的默认视觉变体 = var4(kGalleryVariants 末项)。
|
// 交互窗口(无 flag 的 view)的默认视觉变体 = var4(kGalleryVariants 末项)。
|
||||||
|
|
@ -2847,15 +2867,43 @@ geopro::core::ColorScale pickColor(ColorChoice c, double vmin, double vmax) {
|
||||||
|
|
||||||
// 按变体的不透明度包络建体属性(gallery / 交互默认共用,DRY)。kSolid 走 V 形实体
|
// 按变体的不透明度包络建体属性(gallery / 交互默认共用,DRY)。kSolid 走 V 形实体
|
||||||
// 包络(floor/mid/max),kStructural 走双端斜坡(仅 maxOpacity)。
|
// 包络(floor/mid/max),kStructural 走双端斜坡(仅 maxOpacity)。
|
||||||
|
//
|
||||||
|
// C4 视觉调优:若变体开了 useGradientOpacity 且传入了实测梯度统计 gs,再叠加
|
||||||
|
// 1) 梯度不透明度(SetGradientOpacity):低梯度(均匀层)→透明、高梯度(界面/异常)→显形,
|
||||||
|
// 让射线穿透均匀雾、内部界面浮出(阈值按 gs 的 median/p90/p99 标定,不靠猜);
|
||||||
|
// 2) 光照(useShade → SetShade + Ambient/Diffuse/Specular):层界面带立体明暗。
|
||||||
vtkSmartPointer<vtkVolumeProperty> makeVariantProperty(
|
vtkSmartPointer<vtkVolumeProperty> makeVariantProperty(
|
||||||
const GalleryVariant& v, const geopro::core::Quant& q,
|
const GalleryVariant& v, const geopro::core::Quant& q,
|
||||||
const geopro::core::ColorScale& cs, double vmin, double vmax,
|
const geopro::core::ColorScale& cs, double vmin, double vmax,
|
||||||
double maxOpacity) {
|
double maxOpacity, const GradStats* gs = nullptr) {
|
||||||
|
vtkSmartPointer<vtkVolumeProperty> prop;
|
||||||
if (v.profile == OpacityProfile::kSolid) {
|
if (v.profile == OpacityProfile::kSolid) {
|
||||||
return makeSolidVolumeProperty(q, cs, vmin, vmax, v.floorOpacity,
|
prop = makeSolidVolumeProperty(q, cs, vmin, vmax, v.floorOpacity,
|
||||||
v.midOpacity, maxOpacity);
|
v.midOpacity, maxOpacity);
|
||||||
|
} else {
|
||||||
|
prop = makeTunedVolumeProperty(q, cs, vmin, vmax, maxOpacity);
|
||||||
}
|
}
|
||||||
return makeTunedVolumeProperty(q, cs, vmin, vmax, maxOpacity);
|
|
||||||
|
// 梯度不透明度:均匀层(低梯度)透明,层界面/异常边缘(高梯度)显形。阈值按实测分布:
|
||||||
|
// median 处仍 0(压住均匀积分雾),p90 升到 0.5,p99 到 0.9。无 gs(未测)则跳过。
|
||||||
|
if (v.useGradientOpacity && gs != nullptr && gs->samples > 0) {
|
||||||
|
vtkNew<vtkPiecewiseFunction> grad;
|
||||||
|
grad->AddPoint(0.0, 0.0);
|
||||||
|
grad->AddPoint(std::max(1.0, gs->median), 0.0);
|
||||||
|
grad->AddPoint(std::max(2.0, gs->p90), 0.5);
|
||||||
|
grad->AddPoint(std::max(3.0, gs->p99), 0.9);
|
||||||
|
prop->SetGradientOpacity(grad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 光照:ShadeOn + Ambient/Diffuse/Specular,让层界面带立体明暗(区别于纯平涂)。
|
||||||
|
if (v.useShade) {
|
||||||
|
prop->ShadeOn();
|
||||||
|
prop->SetAmbient(0.3);
|
||||||
|
prop->SetDiffuse(0.7);
|
||||||
|
prop->SetSpecular(0.2);
|
||||||
|
prop->SetSpecularPower(10.0);
|
||||||
|
}
|
||||||
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -3066,14 +3114,31 @@ int runGalleryVariant(const std::string& dir, const GalleryVariant& v,
|
||||||
const double vmin = m.vminPhys, vmax = m.vmaxPhys;
|
const double vmin = m.vminPhys, vmax = m.vmaxPhys;
|
||||||
const geopro::core::ColorScale cs = pickColor(v.color, vmin, vmax);
|
const geopro::core::ColorScale cs = pickColor(v.color, vmin, vmax);
|
||||||
|
|
||||||
vtkSmartPointer<vtkVolumeProperty> prop =
|
|
||||||
makeVariantProperty(v, m.quant, cs, vmin, vmax, v.maxOpacity);
|
|
||||||
|
|
||||||
auto rw = makeOffscreenWindow(winW, winH);
|
auto rw = makeOffscreenWindow(winW, winH);
|
||||||
vtkNew<vtkRenderer> ren;
|
vtkNew<vtkRenderer> ren;
|
||||||
ren->SetBackground(v.bg[0], v.bg[1], v.bg[2]);
|
ren->SetBackground(v.bg[0], v.bg[1], v.bg[2]);
|
||||||
rw->AddRenderer(ren);
|
rw->AddRenderer(ren);
|
||||||
|
|
||||||
|
// 局部段(沿线中段,同 viewSetupDefaultFrame 的取段法)。先建体 → 实测梯度分布
|
||||||
|
// 用于 C4 梯度不透明度标定(仅开了 useGradientOpacity 的变体需要)。
|
||||||
|
const int totBx = store.bricksX(0);
|
||||||
|
const int localBx = std::min(kViewDefaultLocalBricks, totBx);
|
||||||
|
const int bx0 = std::max(0, totBx / 2 - localBx / 2);
|
||||||
|
vtkSmartPointer<vtkImageData> locImg =
|
||||||
|
buildLocalLevel0Image(store, m, bx0, localBx);
|
||||||
|
|
||||||
|
GradStats gs;
|
||||||
|
if (v.useGradientOpacity) {
|
||||||
|
gs = sampleGradientMagnitude(locImg.Get());
|
||||||
|
std::cout << "[gallery " << v.name << "] 梯度幅值分布(量化域,样本 " << gs.samples
|
||||||
|
<< "): median=" << gs.median << " p90=" << gs.p90
|
||||||
|
<< " p99=" << gs.p99 << " max=" << gs.mx << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkSmartPointer<vtkVolumeProperty> prop = makeVariantProperty(
|
||||||
|
v, m.quant, cs, vmin, vmax, v.maxOpacity,
|
||||||
|
v.useGradientOpacity ? &gs : nullptr);
|
||||||
|
|
||||||
vtkNew<vtkMultiBlockVolumeMapper> mapper;
|
vtkNew<vtkMultiBlockVolumeMapper> mapper;
|
||||||
mapper->SetRequestedRenderMode(vtkSmartVolumeMapper::GPURenderMode);
|
mapper->SetRequestedRenderMode(vtkSmartVolumeMapper::GPURenderMode);
|
||||||
auto volume = vtkSmartPointer<vtkVolume>::New();
|
auto volume = vtkSmartPointer<vtkVolume>::New();
|
||||||
|
|
@ -3082,12 +3147,6 @@ int runGalleryVariant(const std::string& dir, const GalleryVariant& v,
|
||||||
volume->SetScale(1.0, v.exagg, v.exagg);
|
volume->SetScale(1.0, v.exagg, v.exagg);
|
||||||
ren->AddVolume(volume);
|
ren->AddVolume(volume);
|
||||||
|
|
||||||
// 局部段(沿线中段,同 viewSetupDefaultFrame 的取段法)。
|
|
||||||
const int totBx = store.bricksX(0);
|
|
||||||
const int localBx = std::min(kViewDefaultLocalBricks, totBx);
|
|
||||||
const int bx0 = std::max(0, totBx / 2 - localBx / 2);
|
|
||||||
vtkSmartPointer<vtkImageData> locImg =
|
|
||||||
buildLocalLevel0Image(store, m, bx0, localBx);
|
|
||||||
std::vector<vtkSmartPointer<vtkImageData>> one{locImg};
|
std::vector<vtkSmartPointer<vtkImageData>> one{locImg};
|
||||||
auto mb = makeMultiBlock(one);
|
auto mb = makeMultiBlock(one);
|
||||||
mapper->SetInputDataObject(mb);
|
mapper->SetInputDataObject(mb);
|
||||||
|
|
@ -3261,8 +3320,17 @@ int cmdView(int argc, char** argv) {
|
||||||
const double vmin = m.vminPhys, vmax = m.vmaxPhys;
|
const double vmin = m.vminPhys, vmax = m.vmaxPhys;
|
||||||
// 配色/不透明度包络取自 var4:seismic + V 形实体包络(floor/mid + opacity 作峰值)。
|
// 配色/不透明度包络取自 var4:seismic + V 形实体包络(floor/mid + opacity 作峰值)。
|
||||||
const geopro::core::ColorScale cs = pickColor(dv.color, vmin, vmax);
|
const geopro::core::ColorScale cs = pickColor(dv.color, vmin, vmax);
|
||||||
vtkSmartPointer<vtkVolumeProperty> prop =
|
// C4:默认变体(var4)开了梯度不透明度 → 从常驻底图实测梯度分布标定阈值。底图恒非空。
|
||||||
makeVariantProperty(dv, m.quant, cs, vmin, vmax, opacity);
|
GradStats dvGs;
|
||||||
|
if (dv.useGradientOpacity && source.baseImage() != nullptr) {
|
||||||
|
dvGs = sampleGradientMagnitude(source.baseImage());
|
||||||
|
std::cout << "[view] 梯度幅值分布(底图,量化域,样本 " << dvGs.samples
|
||||||
|
<< "): median=" << dvGs.median << " p90=" << dvGs.p90
|
||||||
|
<< " p99=" << dvGs.p99 << "\n";
|
||||||
|
}
|
||||||
|
vtkSmartPointer<vtkVolumeProperty> prop = makeVariantProperty(
|
||||||
|
dv, m.quant, cs, vmin, vmax, opacity,
|
||||||
|
dv.useGradientOpacity ? &dvGs : nullptr);
|
||||||
|
|
||||||
// 渲染窗口:preview/smoke 走离屏,否则真窗口。
|
// 渲染窗口:preview/smoke 走离屏,否则真窗口。
|
||||||
vtkSmartPointer<vtkRenderWindow> rw;
|
vtkSmartPointer<vtkRenderWindow> rw;
|
||||||
|
|
@ -3616,10 +3684,7 @@ constexpr double kPolishMaxOpacityGrad = 0.6; // b/c:梯度门控后可提
|
||||||
|
|
||||||
// 在 VTK_SHORT 局部体上采样梯度幅值分布(量化域,中心差分),返回有序的若干分位数。
|
// 在 VTK_SHORT 局部体上采样梯度幅值分布(量化域,中心差分),返回有序的若干分位数。
|
||||||
// 跳过 kBlank 体素及其邻居(空值不参与梯度)。返回 {median, p75, p90, p99, max}。
|
// 跳过 kBlank 体素及其邻居(空值不参与梯度)。返回 {median, p75, p90, p99, max}。
|
||||||
struct GradStats {
|
// (GradStats 已在文件上方前置声明,供 C4 画廊共用。)
|
||||||
double median = 0, p75 = 0, p90 = 0, p99 = 0, mx = 0;
|
|
||||||
std::size_t samples = 0;
|
|
||||||
};
|
|
||||||
GradStats sampleGradientMagnitude(vtkImageData* img) {
|
GradStats sampleGradientMagnitude(vtkImageData* img) {
|
||||||
int dims[3];
|
int dims[3];
|
||||||
img->GetDimensions(dims);
|
img->GetDimensions(dims);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue