geopro/docs/superpowers/specs/2026-06-23-gpr-volume-B-ful...

121 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GPR 三维体 · 方案 B全路段 int16 整卷上 GPU升级现有管线推荐
- 日期2026-06-23
- 范围:把全路段 GPR 按**物理分辨率5~10cm**插值成**单个 int16 体(~5~10GB**,整卷传成 GPU 3D 纹理,切片/体绘制都丝滑。**不做金字塔/核外**,靠"右尺寸 + int16"让单体进显存。
- 定位2026-06-23 用户定):**与 C 对等的两条已承诺路线之一,两者都做、用户运行时按需切换**。B 走"整卷进显存"路线(在现有管线上有针对性升级),适合能装进显存的体;超显存的体走 C。经同一 `IVolumeRenderSource` 接口切换。
- **✅ 评审结论2026-06-23opusGo条件式。** 体积测算、int16+结构化插值、渲染/切片复用均成立。**开工前必改 3 项**①落盘方案VTKHDF Writer 写不了 ImageData必须改裸分块见 §3②量化贯穿传递函数/色阶/反量化(见 §3.5);③一个 vtkShortArray→GPU 体绘制的小验证 spike。
- 测试数据(明星路):同方案 A。物理分辨率依据450MHz、土速 0.1m/ns → 波长 λ≈0.22m、垂向分辨率 ≈5cm网格细过 ~5cm 即过采样。
---
## 1. 设计意图
A 的瓶颈是 `double` + 400³ 上限撑不起全路段。B 针对性拆掉这两条,**保持"整卷进显存"这一最省力的渲染架构不变**
```
.iprb/.iprh → 结构化建体(仅横向插值)→ ScalarVolumeI16int16
→ vtkImageData + vtkShortArray → vtkSmartVolumeMapper整卷进显存
切片:复用 SliceToolreslice 对 int16 image 同样工作)
持久化VolumeBuildParams + int16 明细【真实落盘 + 分块压缩】
```
体积测算(明星路全路段,依据真实头文件):
| 网格 (横×纵×深) | 体素数 | int16 体积 | 进显存? |
|---|---|---|---|
| 10cm×10cm×2cm | 22230×270×400 ≈ 2.4G | **4.8GB** | 12GB+ 显卡可 |
| 10cm×10cm×原生821 | ≈ 4.9G | **9.8GB** | 16~24GB 显卡可 |
| 5cm×5cm×5cm | 44460×540×160 ≈ 3.8G | **7.7GB** | 16GB+ 显卡可 |
**关键5~10GB 全部在单显卡可承载区间——不需要金字塔/核外。** 那个 39TB 是 cm 级横向过采样的产物,物理无意义。
---
## 2. 三处核心升级(相对 A
### 2.1 dtype引入 int16 体4× 内存削减)
-`ScalarVolume` 全仓库是 `double``Field.hpp:8-26`),直接改全局风险大。**方案**:新增并行的 `ScalarVolumeI16``std::vector<int16_t>` + 同样行优先布局 + 量化标定 `scale/offset` 把物理值映射到 int16雷达走 int16 路径,反演剖面仍走 double。
- 渲染:`buildVoxel` 增加 int16 重载 → `vtkImageData` + `vtkShortArray`。**评审已证实** GPU 体绘制原生支持 short`vtkSmartVolumeMapper`→`vtkOpenGLGPUVolumeRayCastMapper`→`vtkVolumeTexture` 走 GL 16-bit 整型纹理。NaN/空值改用 int16 哨兵(如 `INT16_MIN`+ 不透明度传递函数透明(与现 `VoxelActor.cpp:23-24,68-72` 同构)。
- 收益:同体素数内存/显存/磁盘 = double 的 1/4是"让全路段进显存"的关键杠杆。雷达原始本就是 int16**无精度损失**。
- **适配面比"加个重载"大(评审 HIGH**`ScalarVolume`(double) 被 `VolumeGrid`/`buildVoxel`/`finalizeVolume`/`Api3dRepository`(`StoredVolume.cachedGrid`、`loadVolume` 回调签名、`VolumeInfo` 统计) 一路引用。int16 体需让这些**要么模板化、要么并行一套带量化 meta 的变体**。隔离方向(雷达 int16 / 反演剖面仍 double但工作量按"中"算偏乐观§6 已上调。
### 2.2 维度上限:由物理分辨率决定,拆掉 400³ 死值
- 移除/放宽 `kMaxVolumeDim=400``VolumeBuilder.hpp:8`),改为按 `cellXY/cellZ` 与场景范围算出 dims并加**显存预算守卫**(建体前估算 `nx·ny·nz·2B`**并留余量**:实际还要叠加传递函数纹理 + 颜色/深度 FBO按裸标量算偏紧——评审 MEDIUM
- **显存探测无可靠跨厂商 API评审 MEDIUM**OpenGL 无统一"可用显存"查询。实践只能 try-upload-on-fail 或留保守阈值。
- **免费兜底评审发现spec 原漏报)**`vtkSmartVolumeMapper` 自带 `MaxMemoryInBytes` + `LowResResample``vtkSmartVolumeMapper.h:194-211,373-379`),体超显存时**自动降采样重采样到可容纳**——等于"概览体"免费实现。目标机显存小时优先用它 + 按区域细化,**仍在 B 框架内,不必转 C**。
- 默认网格由雷达物理分辨率给(横 5~10cm、深 2~5cm不让用户填出过采样网格。
### 2.3 插值:结构化建体,不做 3D 散点 IDW
- **重要架构洞察**:雷达数据沿测线(X)、深度(Z)**本就是规则密采样**,只有横向(Y)的 14 通道是稀疏的。所以"插值成体"≠ 3D 无结构散点插值,而是:
- X、Z 方向按道距/采样直接落格(重采样/最近邻,廉价);
- **只在 Y 方向对 14 通道做 1D 插值**填充横向空隙。
- 这比 A 复用的全 3D IDW **快一两个数量级**且单线程可接受若仍慢Y 向插值天然可并行QtConcurrent/std::thread按 X 切片并行)。
- 保留 `IInterpolator` 抽象,新增 `GprStructuredBuilder` 实现,与 IDW 并列。
---
## 3. 持久化(真正满足"算一次、之后秒开"
用户要两种保存B 把第二种做实:
- **方式一(参数档)**`VolumeBuildParams`(源 .iprb 引用 + 建体参数 + 色阶 + 量化 scale/offset+ `GridSpec`。小、可复算、详情面板展示。
- **方式二(明细缓存,升级为真实落盘)**int16 体 **分块写盘 + 逐块压缩**
- **⚠ 不能用 `vtkHDFWriter`(评审 CRITICAL两个评审独立证实**VTK 9.6 的 `vtkHDFWriter` **写不了 `vtkImageData`/规则体**——它只支持 PolyData/UnstructuredGrid/Partitioned/MultiBlock`vtkHDFWriter.h:6-9,232-235`,无 ImageData 写重载)。`vtkHDFReader` 能**读** ImageData但 Writer 不能**写**,读写不对称。"补个 IOHdf 组件就能 VTKHDF 原生落盘体"的说法**错误**。
- **首选(改正后)****自定义 raw int16 分块 + sidecar(GridSpec/量化 scale·offset/vmin·vmax/分块索引) + 逐块 zlibVTK 自带 `vtkzlib`,无需新依赖)**。分块布局从一开始就设计好C 的"切片核外"可几乎免费复用同一格式。
- 备选:直接用底层 `vtkhdf5` C API 自写 chunked dataset绕过 `vtkHDFWriter`),获得 HDF5 生态兼容;成本高于 raw 分块。
- 不引入独立 zstd/bloscvcpkg 未含;如需更高压缩比再加)。
- **加载**:有明细 → 读盘(可 mmap)→ 整卷上显存;无明细 → 按参数后台线程重算落缓存(复用现有重算逻辑 `Api3dRepository.cpp:212-225`,从 mock 升级为真实落盘)。
- **后台重算不阻塞 UI评审 MEDIUM**:现 `loadVolume` 回调**在主线程**mock 同步)。改为工作线程建体/重算后,回调要**跨线程编组**回 UIQt 信号 / `QMetaObject::invokeMethod`),这是线程模型改动,需显式设计。
- **加载耗时别承诺"秒开"(评审 LOW**5~10GB 上传 GPU(约 1~5s) + 压缩明细解压,实际**约 10s 量级**。明星路单体压缩后约 2~6GB读盘+解压秒~十秒级——比每次重算快得多,用户"算一次之后快读"诉求成立。
### 3.5 量化贯穿(评审 HIGH正确性问题必做
int16 渲染标量是量化域 `q = round((v_phys - offset)/scale)`,不是物理值。必须把量化贯穿全链,否则色阶/读数全错:
- **传递函数 / 不透明度**:现 `VoxelActor.cpp:62-72` 用物理 `vmin/vmax` 加控制点 → int16 路径必须改成在**量化域 `qmin/qmax`** 采样。
- **切片色阶 LUT**`buildLut(cs,vmin,vmax)``SliceTool.cpp:37`)同理喂量化域。
- **反量化显示**:取值光标 / 异常详情 / 数据详情面板展示给用户的值必须 `v_phys = q*scale + offset` 反量化回物理量。
- `scale/offset` 存入 `VolumeBuildParams` 并随 `VolumeInfo` 传递。
---
## 4. 渲染与交互(基本复用,验证为主)
- 整卷 `vtkSmartVolumeMapper`现有int16 image 直接喂;确认 9.6 的 GPU ray cast 对 short 标量正常。
- 切片 `SliceTool``vtkImagePlaneWidget`/`vtkImageReslice`)对 int16 image 同样工作CPU reslice 与 dtype 无关);丝滑度由"整卷已在显存"保证。
- 异常/详情/色阶:复用现有 3D 分析栏链路。
---
## 5. 评估
**优点**
- **全路段完整连续体 + 最好体验**,切片/体绘制丝滑,且**不必上金字塔/核外**。
- 复用现有渲染/切片/异常/详情,主要新增 = int16 路径 + 结构化建体 + 真实落盘。
- int16 + 结构化插值同时解决"内存/显存/磁盘大"和"插值慢"。
- 明细真实落盘,"算一次秒开"成立。
**缺点/风险(评审分级)**
- **CRITICAL已在 §3 修正)**`vtkHDFWriter` 写不了 ImageData → 落盘改裸 int16 分块+zlib。有现成退路非方案推翻但落盘是"自写格式"的中等工程,非"补组件"。
- **HIGH**:量化未贯穿传递函数/色阶/反量化会导致颜色与读数错§3.5 已补设计)。
- **HIGH**int16 适配面被低估(`VolumeGrid`/`loadVolume` 回调/`StoredVolume`/`VolumeInfo` 均需带量化 meta非单点重载。
- **MEDIUM**后台重算从主线程改工作线程跨线程回调编组需设计显存无可靠查询、预算按裸标量偏紧结构化落格假设道近似等距GPS 抖动需沿弧长重采样。
- **LOW**5~10GB 加载约 10s 级UX 别承诺"秒开"。
- 单巨体无部分加载:打开即载全量。
- int16 路径是对核心类型的扩展,需谨慎不污染 double 主路径(用并行类型隔离)。
**适用**
- 当前明星路这一档(及绝大多数单路段工程)。**这是默认推荐。**
---
## 6. 工作量与落地顺序
0. **【开工前】验证 spike~半天)**`vtkShortArray` 填小 `vtkImageData``vtkSmartVolumeMapper` 跑通 GPU ray cast + 量化域传递函数,确认 GPU 路径与颜色正确。
1. 地基(同 A §2`.iprb`/`.iprh` 解析 + 配准 + 接入(~中)。
2. `ScalarVolumeI16` + `buildVoxel` int16 重载 + 哨兵透明 + **量化贯穿传递函数/LUT/反量化§3.5**~中大,评审上调:适配面比单点重载大)。
3. `GprStructuredBuilder`X/Z 落格 + Y 向插值可并行GPS 抖动需沿弧长重采样)替代全 3D IDW~中)。
4. 显存预算守卫(留 FBO/传函余量)+ `LowResResample` 概览兜底 + 物理分辨率默认网格(~小)。
5. 明细真实落盘(**raw int16 分块 + sidecar + zlib不用 vtkHDFWriter**+ 后台重算(**含跨线程回调编组**~中大,评审上调:自写分块格式 + 线程模型)。
6. 渲染/切片对 int16 的验证(~小)。
**结论评审Go 条件式 / 用户定:与 C 都做)**B 用"右尺寸 + int16 + 结构化插值"在现有架构上拿到全路段完整体验。**前置条件**§3 落盘章节已从 VTKHDF 改为裸分块、§3.5 量化设计已补、第 0 步 spike 通过——满足后即可进入实现。B 与 C 经同一 `IVolumeRenderSource` 并存,用户按数据规模在两者间切换(能进显存走 B、超显存走 C落盘格式两者共用B 的裸分块是 C 分块/金字塔的基座)。