最近要使用ITK 进行一些分割算法的实现,所以就联合了之前的VTK+QT 做了一个小的测试,现在把过程和错误及解决方案记录下来,以便以后少踩坑。
环境配置:
VTK 7.0
QT 5.7
ITK 4.11
vs2015
系统64位
1、使用Cmake编译ITK 的时候过程基本和VTK 差不多,但是这里没有编译成功ITK 的python接口。尝试了一下,发现在后面的生成的时候会缺少python27_d.dll. 因为python不是自己编译的,所以就放弃了Debug模型下的python接口编译。后面在release 模式下页尝试了编译,但是仍然有错误。因为暂时不需要使用python所以就跳过了。如果有编译成功的,也希望大家能分享一下自己的经验。接下来就是为了要配合vtk的使用,在camke编译的时候勾选vtkglue 这个module就可以了。编译过程比较顺利没有什么问题。
2、找了一个example来实现ITK image To Vtk。
example:Itk image convert to vtk image example
主要的代码如下:
typedef itk::Image<itk::RGBPixel<unsigned char>, 2> ImageType;
typedef itk::ImageFileReader<ImageType> ReaderType;
typedef itk::ImageToVTKImageFilter<ImageType> ConnectorType;
ReaderType::Pointer reader = ReaderType::New();
ConnectorType::Pointer connector = ConnectorType::New();
reader->SetFileName(argv[1]);
connector->SetInput(reader->GetOutput());
vtkSmartPointer<vtkImageActor> actor =
vtkSmartPointer<vtkImageActor>::New();
#if VTK_MAJOR_VERSION <= 5
actor->SetInput(connector->GetOutput());
#else
connector->Update();
actor->GetMapper()->SetInputData(connector->GetOutput());
#endif
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->ResetCamera();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style =
vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
上述代码在VTK当中运行的没有问题,还尝试了ITK 自带的QuickViewr,都ok。但是在我将最后的renderWindow 放入的QVTWidg中时就报错了,我的代码如下:
this->ui.vtkWidget1->SetRenderWindow(renderWindow);
renderWindow->AddRenderer(renderer);
this->ui.vtkWidget1->GetRenderWindow()->Start();
错误如下:
中断之后就是:帧不在模块中了,对于我来说去看反汇编更不可能了。
就只能慢慢分析问题的可能原因了:
1、使用VTK自带的窗口和itk的quickview显示都没有问题,那么矛头就是在QWidget上了。
2、QWidget这个是大神写的估计本身应该没有问题,而且之前使用的时候和VTK 兼容的很好。
3、那就可能是数据的问题,而且是访问冲突的错误,那么就是itktovtk的imagedata和vtk自身读取的imagedata的问题。关于两个数据的差别,网上都有,但是不影响显示,那么访问冲突的话,我就试试把数据拷贝一下吧。
4、vtkImageData* myvtkImageData = connector->GetOutput();
vtkImageData* img = vtkImageData::New();
img->DeepCopy(myvtkImageData);
使用上面的深拷贝把imagedata的数据拷贝一下,然后再用img去显示,就没有问题了。
5、qt的界面显示是在最后main函数里面的show调用后。但是我把函数写在整个界面生成之前(直接运行就出来结果那种),则在界面生成前数据就已经准备好了,但是最后生成界面的时候再去访问这个数据,可能就发生了冲突(虽然之前VTK,没有这样的问题)觉得这可能是ITK自身数据存储的问题。
6、那么除了深拷贝,按照上面的逻辑,我可以先生成Qwidget界面后再通过按钮之类的来显示呢,是否就会避免上述的问题呢?
好吧,还是有问题,看来这个数据无论如何都不能被QT 拿来显示了,所以先用深拷贝了,也试过用static 静态数据,都没有用。
7、结果通过深拷贝:
完整的代码如下:
void itk_example::myItkTest()
{
itk::PNGImageIOFactory::RegisterOneFactory();
typedef itk::Image<itk::RGBPixel<unsigned char>, 2> ImageType;
typedef itk::ImageFileReader<ImageType> ReaderType;
typedef itk::ImageToVTKImageFilter<ImageType> ConnectorType;
ReaderType::Pointer reader = ReaderType::New();
ConnectorType::Pointer connector = ConnectorType::New();
reader->SetFileName("C:\\Users\\jhj\\Documents\\Visual Studio 2015\\Projects\\itk_example\\itk_example\\Resources\\12.png");
connector->SetInput(reader->GetOutput());
vtkSmartPointer<vtkImageActor> actor =
vtkSmartPointer<vtkImageActor>::New();
connector->Update(); // VTK 7.0 must update
vtkImageData* img = vtkImageData::New(); //deep copy
img->DeepCopy(connector->GetOutput());
actor->GetMapper()->SetInputData(img);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->ResetCamera();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
ui.vtkWidget1->SetRenderWindow(renderWindow);
ui.vtkWidget1->update();
}
conclusion:
1、首先遇到问题不要慌,多看看官方的文档,多问问有经验的人(师兄就给了比较好的建议)
2、自己分析问题的思路还不够清晰,导致这个问题纠结了很久,当然知识储备量不够要背锅。
3、这个问题个人很有兴趣深挖下去(可以学到很多更深层次的东西),但是由于项目时间紧张,以后有时间再挖吧。