图像数据三视图切面
提示,世界坐标的坐标轴是不变的固定的
两种方案都是用vtkImageReslice
方案A: 通过调整相机的位置 vtkImageResliceMapper 让切片自动“面对”各自的相机
vtkImageResliceMapper 内部其实就是一个 GPU‑版 vtkImageReslice, 并且提供两行“傻瓜式”开关:
mapper->SliceFacesCameraOn(); // 让切片法向 = 相机视线
mapper->SliceAtFocalPointOn(); // 切片位置 = 相机焦点
mapper->JumpToNearestSliceOff(); // ←要平滑滚动就关掉最近切片模式
只要你的相机始终保持正交方向 (±X/±Y/±Z),它就能自动给出轴向/冠状/矢状切片。
代码框架 (3 窗口示例)
vtkSmartPointer<vtkImageData> volume = ...; // 读入 3D 数据
// 一个工具函数:为每个窗口生成“相机跟随”切片
vtkImageSlice* makeSliceView(vtkRenderer* ren, const double camPos[3],
const double viewUp[3])
{
auto mapper = vtkSmartPointer<vtkImageResliceMapper>::New();
mapper->SetInputData(volume);
mapper->SliceFacesCameraOn();
mapper->SliceAtFocalPointOn();
mapper->JumpToNearestSliceOff();
auto slice = vtkSmartPointer<vtkImageSlice>::New();
slice->SetMapper(mapper);
ren->AddViewProp(slice);
// 相机:朝 volume 中心看
auto cam = ren->GetActiveCamera();
cam->SetPosition(camPos);
cam->SetFocalPoint(volumeCenter); // 你自己算中心
cam->SetViewUp(viewUp);
ren->ResetCamera(); // 让切片充满窗口
return slice;
}
// ① XOY(轴向)—— 从 +Z 方向俯视
double cam1[3] = {0, 0, +distance}, up1[3] = {0, 1, 0};
makeSliceView(rendererXY, cam1, up1);
// ② YOZ(冠状)—— 从 +X 方向看
double cam2[3] = {+distance, 0, 0}, up2[3] = {0, 0, 1};
makeSliceView(rendererYZ, cam2, up2);
// ③ XOZ(矢状)—— 从 +Y 方向看
double cam3[3] = {0, +distance, 0}, up3[3] = {0, 0, 1};
makeSliceView(rendererXZ, cam3, up3);
只要用户拖拽平移相机(Dolly/Pan)、或者你用代码改 camera->SetFocalPoint(), 切片就会在体数据里移动,不用你重算 ResliceAxes。
方案B:经典 vtkImageReslice + 手动把相机姿态→ResliceAxes
如果由于版本或算法(如做斜切面、厚层 MIP) 你必须坚持用 vtkImageReslice,就要自己在回调里: 取相机的 视线(dir)、ViewUp、焦点(FP); 构出平面基向量: * right = dir × ViewUp, up = right × dir; 组出 4×4 矩阵 R = [right | up | dir | FP]; reslice->SetResliceAxes(R); reslice->Update();
void syncResliceWithCamera(vtkCamera* cam, vtkImageReslice* reslice)
{
double fp[3], dir[3], up[3];
cam->GetFocalPoint(fp);
cam->GetDirectionOfProjection(dir);
cam->GetViewUp(up);
vtkMath::Normalize(dir); vtkMath::Normalize(up);
double right[3]; vtkMath::Cross(dir, up, right);
vtkMath::Normalize(right);
vtkMath::Cross(right, dir, up); // 保证三向量正交
double M[16] = {
right[0], up[0], dir[0], fp[0],
right[1], up[1], dir[1], fp[1],
right[2], up[2], dir[2], fp[2],
0, 0, 0, 1
};
vtkNew<vtkMatrix4x4> axes; axes->DeepCopy(M);
reslice->SetResliceAxes(axes);
reslice->Update();
}
// 在交互回调或定时器中调用:
syncResliceWithCamera(rendererXY->GetActiveCamera(), resliceXY);
优点:手动可控、想切多斜面都行。 缺点:要自己写更新逻辑,每动一下相机就得 Update(),比方案 A 费 CPU。
使用SetResliceTransform替换SetResliceAxes可以吗
可以替换,但有条件: 线性变换情况: 如果 SetResliceAxes 使用的是简单的线性变换,可以创建一个 vtkTransform 对象,设置相同的矩阵,然后使用 SetResliceTransform 替代 非线性变换情况:如果需要非线性变换,必须使用 SetResliceTransform,SetResliceAxes 无法处理这种情况 性能考虑: SetResliceAxes 对于简单线性变换更高效 SetResliceTransform 更灵活但可能有额外开销 互斥性: 这两个方法是互斥的 设置其中一个会清除另一个的设置 默认行为: 如果两者都未设置,重切片器默认使用身份变换 坐标系: 确保理解变换是在世界坐标系还是局部坐标系中应用
场景 | 推荐 |
---|---|
只要标准轴向/冠状/矢状,并想自动跟随相机 | 方案 A → vtkImageResliceMapper |
要斜切面 / 自定义厚度 / 特殊重建 | 方案 B → 自推 ResliceAxes |
VTK 旧版 (< 8.2) 没有 ResliceMapper | 方案 B 或换 vtkImageSliceMapper |
如果使用旋转,那么使用方案B