问题

  VTK图像处理交流群(962611958)里有朋友提了一个问题:使用交互器操作轴面图像的中心点时,出现图像随着鼠标移动;大家都认为平移时出现图像的平移是不可能的,因为在使用vtkImageReslice取图时,如果不指定OutputOrigin坐标位置,是默认以体数据的中心点在切面上的投影为中心点的图像,在同一个断层上移动,中心点是不会发生变化的,图像也就是同一张图。这个问题很有意思;
  我这段时间也在做和切面重建相关的内容,跟着群友的代码来查这个问题;
  参考群友的代码写的复现代码,每次平移只考虑了鼠标的XY的改变量,没有结合XY方向的spacing的值,这个地方暂时忽略,主要关注在鼠标移动事件MouseMoveEvent,代码如下:

#pragma once#include "vtk_include.h"
#include <vtkMetaImageReader.h>
#include <vtkImageActor.h>class vtkImageInteractionCallback : public vtkCommand {public:static vtkImageInteractionCallback* New() {return new vtkImageInteractionCallback;}vtkImageInteractionCallback() {this->Slicing = 0;this->ImageReslice = 0;this->Interactor = 0;}void SetImageReslice(vtkImageReslice* reslice) {this->ImageReslice = reslice;}void SetImageMapToColors(vtkImageMapToColors* mapToColors) {this->mapToColors = mapToColors;}void SetImageActor(vtkImageActor* actor) {myActor = actor;}void SetInteractor(vtkRenderWindowInteractor* interactor) {this->Interactor = interactor;}vtkRenderWindowInteractor* GetInteractor() {return this->Interactor;}virtual void Execute(vtkObject*, unsigned long event, void*) {vtkRenderWindowInteractor* interactor = this->GetInteractor();int lastPos[2];interactor->GetLastEventPosition(lastPos);int currPos[2];interactor->GetEventPosition(currPos);if (event == vtkCommand::LeftButtonPressEvent) {this->Slicing = 1;}else if (event == vtkCommand::LeftButtonReleaseEvent) {this->Slicing = 0;}else if (event == vtkCommand::MouseMoveEvent) {if (this->Slicing){int deltaX = lastPos[0] - currPos[0];int deltaY = lastPos[1] - currPos[1];double translateC[16] = {1,0,0,deltaX,0,1,0,deltaY,0,0,1,0,0,0,0,1 };vtkImageReslice* reslice = this->ImageReslice;reslice->Update();vtkMatrix4x4* matrix = reslice->GetResliceAxes();vtkMatrix4x4* translateM = vtkMatrix4x4::New();vtkMatrix4x4* resultM = vtkMatrix4x4::New();translateM->DeepCopy(translateC);vtkMatrix4x4::Multiply4x4(matrix, translateM, resultM);matrix->DeepCopy(resultM);reslice->SetResliceAxes(matrix);reslice->Update();translateM->Delete();resultM->Delete();mapToColors->Update();interactor->Render();}else {vtkInteractorStyle* style = vtkInteractorStyle::SafeDownCast(interactor->GetInteractorStyle());if (style) {style->OnMouseMove();}}}}
private:int Slicing;vtkImageReslice* ImageReslice;vtkRenderWindowInteractor* Interactor;vtkImageMapToColors* mapToColors;vtkImageActor* myActor;
};class Test_Reslice
{public:Test_Reslice() {reader = vtkSmartPointer<vtkMetaImageReader>::New();reader->SetFileName("G:\\Data\\brain.mhd");reader->Update();  reader->GetOutput()->GetExtent(extent);reader->GetOutput()->GetSpacing(spacing);reader->GetOutput()->GetOrigin(origin);center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);}void Render(){this->renwin = vtkRenderWindow::New();this->iren = vtkRenderWindowInteractor::New();int extent[6];double spacing[3];double origin[3];double center[3];this->Getimagedata()->GetExtent(extent);this->Getimagedata()->GetSpacing(spacing);this->Getimagedata()->GetOrigin(origin);center[0] = origin[0] + 0.5 * spacing[0] * (extent[0] + extent[1]);center[1] = origin[1] + 0.5 * spacing[1] * (extent[2] + extent[3]);center[2] = origin[2] + 0.5 * spacing[2] * (extent[4] + extent[5]);double Axial[16] = {1, 0, 0, 0,0, 1, 0, 0,0, 0, 1, 0,0, 0, 0, 1};vtkMatrix4x4 *AxialResliceMatrix = vtkMatrix4x4::New();AxialResliceMatrix->DeepCopy(Axial);AxialResliceMatrix->SetElement(0, 3, center[0]);AxialResliceMatrix->SetElement(1, 3, center[1]);AxialResliceMatrix->SetElement(2, 3, center[2]);vtkImageReslice* myImageReslice = this->ImageReslice = vtkImageReslice::New();//设置体数据来源myImageReslice->SetInputData(this->Getimagedata());myImageReslice->SetResliceAxes(AxialResliceMatrix);myImageReslice->SetOutputDimensionality(2);myImageReslice->SetInterpolationModeToLinear();vtkLookupTable* myLookupTable = vtkLookupTable::New();myLookupTable->SetRange(0, 2000);myLookupTable->SetValueRange(0.0, 1.0);myLookupTable->SetSaturationRange(0.0, 0.0);myLookupTable->SetRampToLinear();myLookupTable->Build();vtkImageMapToColors* myMapToColors = this->ColorMap = vtkImageMapToColors::New();myMapToColors->SetLookupTable(myLookupTable);myMapToColors->SetInputConnection(myImageReslice->GetOutputPort());myMapToColors->Update();vtkImageActor* myImageActor = vtkImageActor::New();myImageActor->SetInputData(myMapToColors->GetOutput());this->ren = vtkRenderer::New();this->ren->AddActor(myImageActor);this->renwin->AddRenderer(this->ren);vtkSmartPointer<vtkInteractorStyleImage> imagestyle = vtkSmartPointer<vtkInteractorStyleImage>::New();this->iren->SetInteractorStyle(imagestyle);iren->SetRenderWindow(this->renwin);iren->Initialize();vtkSmartPointer<vtkImageInteractionCallback> callback = vtkSmartPointer<vtkImageInteractionCallback>::New();callback->SetImageReslice(ImageReslice);callback->SetInteractor(this->iren);callback->SetImageMapToColors(ColorMap);callback->SetImageActor(myImageActor);imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback);imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback);imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback);        this->iren->Start();}vtkImageData* Getimagedata() { return reader->GetOutput(); }vtkSmartPointer<vtkMetaImageReader> reader;int extent[6];double spacing[3];double origin[3];double center[3];vtkRenderer* ren;vtkRenderWindow* renwin;vtkRenderWindowInteractor* iren;vtkImageReslice* ImageReslice;vtkImageMapToColors*  ColorMap;
};

  复现结果是,左图为原始图像,右图为鼠标移动改变取图中心点后的图像。
  可以发现图像向左下方向移动了,和鼠标的移动方向是一致的;

问题定位过程

  1.拿到问题代码后,确实可以复现,其实问题百分百是可以解决的,最怕的就是不能复现和偶发的现象;
  2.之前也说过我一直认为图像是不变的,那么要么是我的认知是错误的,要么是图像是对的渲染后在窗口中的展示结果是错误的;
  3.验证从vtkImageReslice中获取的图像是否正确。这里犯了一个错误,我用vtkImageViewer2来展示我从vtkImageReslice中获取的图像,发现图像确实有偏移;难道是我理解的真有问题…… ,记录了当前右图对应的坐标,在代码中我初始时对vtkImageReslice设置这个坐标,发现图像居中,没有偏移,这个和刚才那个vtkImageViewer2显示的结果相悖;这个时候大概感觉到是vtkImageViewer2和vtkImageActor的坑了,因为图像是从vtkImageData放到vtkImageActor中然后在窗口渲染显示;
  4.步骤3验证了图像没有问题,那么只能是渲染的问题,从vtkImageActor提供的接口来看,vtkImageActor内确实有自己的坐标,使用vtkImageActor的GetCenter方法获取坐标位置;

cout << "++++++++++++++++++x:" << myActor->GetCenter()[0] << endl;
cout << "++++++++++++++++++y:" << myActor->GetCenter()[1] << endl;

  随着鼠标的移动,Center坐标确实发生了改变;

  我使用SetOrigin和SetPosition妄想将vtkImageActor的坐标设置为(0,0),发现没有效果,图像照旧向鼠标移动方向平移;

double zero_center[3] = { 0 };
myActor->SetOrigin(zero_center);
myActor->SetPosition(zero_center);

  从VTK的源码中,可以得知vtkImageActor的Center是由Bounds计算的:

double *vtkProp3D::GetCenter()
{this->GetBounds();this->Center[0] = (this->Bounds[1] + this->Bounds[0])/2.0;this->Center[1] = (this->Bounds[3] + this->Bounds[2])/2.0;this->Center[2] = (this->Bounds[5] + this->Bounds[4])/2.0;return this->Center;
}

  打印vtkImageActor的Bounds,从上图上看Bounds是在改变的;

double bounds[6] = { 0 };
myActor->GetBounds(bounds);

结论

  可以定位是vtkImageActor和vtkImageViewer2的问题,群友给出的解决办法是使用vtkRenderer的ResetCamera方法,根据图像的坐标,重新计算相机的坐标。不过实现项目中很少会遇到这种问题,因为项目中一般不会使用交互器,也很少使用vtkImageActor的(这里仅限于图像切面重建,不包括体渲染)。
  注:多看VTK的源码,还是极其必要的。

VTK笔记-切面重建-使用交互器更新断层图的奇异现象的问题排查相关推荐

  1. VTK交互系统 2 交互器样式

    所谓交互器样式,就是你设置了交互器,然后它里面会有各种默认的或者你自己定义的交互方式,比如你可以设置滚轮来将图片放大或者缩小.或者你可以设置鼠标点击移动来改变摄像机的视角,从而看到物体的不同面. VT ...

  2. VTK笔记-了解VTK

    最近,重新学习了VTK相关内容,网上资料质量参差不齐,自己从多处搜集资料,整理记录之: VTK简介 VTK,(visualization toolkit)是一个开源的免费软件系统,主要用于三维计算机图 ...

  3. ios学习--iphone开发笔记和技巧总结(原址持续更新)

    ios学习--iphone开发笔记和技巧总结(原址持续更新) 分类: ios Object-C2012-04-18 10:16 2716人阅读 评论(1) 收藏 举报 uiviewiphonelist ...

  4. VTK笔记-图像相关-vtkImageViewer2类

    vtkImageViewer2   vtkImageViewer2类用来显示二维图像:vtk的版本更新,使用vtkImageViewer2替代vtkImageViewer类:   vtkImageVi ...

  5. KinectFusion:用运动的深度相机进行实时3D重建及交互

    KinectFusion的GPU Pipeline实现, 涉及到的两篇原理和实现中的一篇,两年前翻译的,那时候多数不理解,再拿出来整理一下,也是加深理解,配图来自原论文,文字为本人翻译,如有不正,敬请 ...

  6. 交互器、linux下的常用命令

    使用交互器步骤 搜索-->cmd dir(查看当前目录文件) # 若想清空,输入cls python--> print(" hello world") # 若想退出,输 ...

  7. VTK笔记-图形相关-多边形数据转换图像数据-vtkPolyData转换为vtkImageData

      VTK中vtkImageData类和vtkPolyData类使用频率极高,vtkImageData类和vtkPolyData类派生自vtkDataSet类,是数据集的一种.   vtkPolyDa ...

  8. Interacting Attention Graph for Single Image Two-Hand Reconstruction(单幅图像双手重建的交互注意图)

    2203.09364.pdf (arxiv.org) 摘要 图卷积网络(GCN)在单手重建任务中取得了巨大的成功,而利用GCN进行双向交互重建的研究尚不深入.在本文中,我们提出了交互注意图手(Inta ...

  9. VTK笔记-灯光vtkLight

    光   光在我们周围无处不在,光学成像技术也和我们的生活密不可分,如各种相机.摄像机.望远镜.投影仪等:   在现实中,人.相机以及各种各样的采集显示世界信息的收影设施都是通过收集物体反射到人眼中的光 ...

最新文章

  1. Python:zip()函数
  2. 1337:【例3-2】单词查找树
  3. PKG_CONFIG_PATH错误提示解决办法
  4. Html5画布(canvas)实例之绘制矩形
  5. python 基础知识点整理 和具体应用
  6. 谷歌浏览器打开链接,如何不是覆盖当前页面而自动跳转到新标签页?
  7. 将 instance 连接到 second_local_net - 每天5分钟玩转 OpenStack(85)
  8. 测试计划模板——Test Plan(中英文)
  9. MAC(多路访问控制)协议
  10. php天猫列表数据抓取,天猫数据抓取方法_简易采集 - 八爪鱼采集器
  11. 标签上title属性与alt属性的区别是什么
  12. dw中html是什么,dw中的css是什么意思?
  13. webpack2系列step1--HTML
  14. Android视频录制命令screenrecord
  15. 使用Nginx访问日志统计PV和UV
  16. ORA-01547、ORA-01194、ORA-01110
  17. 行人属性识别的一个调研
  18. Java字节码,字节码指令
  19. java jsp页面传值_JSP 页面传值方法总结
  20. 成神结局量子计算机雏惨,成神之日:消失数月之后雏再次出现,不过形象却差点让人认不出...

热门文章

  1. Excel 对象模型
  2. SP4354 TWINSNOW - Snowflakes
  3. Mac电脑如何查看本机网卡mac地址
  4. OGRE粒子系统脚本详解
  5. 操作系统习题(有一个具有两道作业的批处理系统)
  6. Vue实现一键截屏功能
  7. BZOJ 5293 求和(LCA)
  8. 【 交换最小值和最大值 】本题要求编写程序,先将输入的一系列整数中的最小值与第一个数交换,然后将最大值与最后一个数交换,最后输出交换后的序列。 注意:题目保证最大和最小值都是唯一的。
  9. GPS定位基本原理浅析
  10. 《调色师手册:电影和视频调色专业技法(第2版)》——第1章 调色的工作流程 我要为电影院(电影)、广播(电视),还是网络调色?...