2 利用ITK实现多帧Dicom读取,VTK实现数据显示

本文介绍了如何在VTK中使用ITK进行多帧DICOM数据的读取,包括编译ITK并解决遇到的问题,以及如何将ITK数据转换为VTK格式以便于三维显示。还提到在显示VTKImageData时可能遇到的权限问题及解决方案。
摘要由CSDN通过智能技术生成

vtk中也有dicom读写类,但是只能完成单帧DICOM数据读取,这对于实际应用是非常不利的。
而ITK可以实现dicom多帧读取,通常情况ITK与VTK也会结合使用(ITK处理,VTK显示),所以就一起学习下吧!

一、编译ITK

因为之后要将ITK与VTK混合编程,所以先编译生成VTK之后再进行ITK编译。
详情参考以下博文,这里不再赘述。
ITK 5.0.1 在Windows10+VS2017+CMake 环境下编译安装
ITK-001-5.2.0版本源码-编译
不过我在这里陷入了一个错误,给大家提个醒:最好不要随意改动生成好的VTK,因为ITK cmake时读取VTK中的cmake文件,会调取一些路径,如果路径被改变则会报错,不好找到原因。

另外需要注意的,在CMAKE_DEBUG_POSTFIX后面添加d这样进行Debug版本编译时会在库文件名后面多个d。

二、利用ITK实现多帧DICOM读取

先贴一下这段的代码:

itk::ImageBase<3>::Pointer DicomReadWrite::DicomReadSeries(const QString &path)
{
    itk::ImageBase<3>::Pointer outImage;
    // 检查路径是否有效,检查文件是否存在
    if (path.isEmpty() || !QFile::exists(path)) {
        return outImage;
    }

    std::string DirectPath = path.toStdString();
    // 图像类型
    using PixelType = unsigned char; // dicom图像常见像素类型
    constexpr unsigned int Dimension = 3; //维度为3
    using ImageType = itk::Image<PixelType, Dimension>;
    // 创建dicom图像读取器
    using ReaderType = itk::ImageSeriesReader<ImageType>;
    ReaderType::Pointer reader = ReaderType::New();
    reader->SetFileName(DirectPath);
    //创建GDCMImageIO对象与reader相连
    using ImageIOType = itk::GDCMImageIO;
    ImageIOType::Pointer gdcmImageIO = ImageIOType::New();
    reader->SetImageIO(gdcmImageIO);
    // 读取
    try
    {
        // 用序列图像reader的Update出发读取程序
        reader->Update();
        // 获取读取的图像
        outImage = reader->GetOutput();    
    }
    catch (const itk::ExceptionObject& excp)
    {
        std::cerr << "Exception thrown while writing the image" << std::endl;
        std::cerr << excp << std::endl;
    }

    return outImage;
}

我读的是一个dicom数据,包含了连续多帧的灰度图序列,非彩色的,上述代码也可以读单帧图像。返回值是一个ImageBase类型。itk::ImageBase是itk::Image的基类,它可以不用事先定义Type类型(但这也是有风险的,尽量用在已知确定Type的地方),不然要作为参数返回的话,还要先定义一下ImageType。
包含的头文件如下:

#include "itkGDCMImageIO.h" 
#include "itkGDCMSeriesFileNames.h" 
#include "itkImageSeriesReader.h" 
#include <QString>
#include<QFile>

ITK读写dicom是基于GDCM库的,GDCMImageIO是一个读取和写入DICOM V3和ACR/NEMA图像的ImageIO类。

在此编译过程中遇到了一个错误,就是“无法解析该符号”,这一般就是添加的库目录以及包含的lib不正确造成的,不想一个个去试了就直接将所有lib都添加到附加依赖项了,解决此问题。

三、ITK数据向VTK数据转换

使用itk::vtkImageToVTKImageFilter可以将itk::Image转换喂vtkImageData,相反的,itk::VTKImageToImageFilter将vtkImageData转换喂itk::Image,这要比访问像素的方法要简单快速的多。
参考链接🔗使用VTK读取DICOM数据及其与DCMTK/ITK数据的转换

vtkSmartPointer<vtkImageData> VtkAndItk::ItkImages2VtkImages(itk::ImageBase<3>::Pointer inputImage)
{
	using PixelType = unsigned char;
	constexpr unsigned int Dimension = 3;
	using ImageType = itk::Image<PixelType, Dimension>;
	
	 // 动态类型转换,将 image 转换为 itk::Image 指针
	ImageType::Pointer itkImage = dynamic_cast<itk::Image<PixelType, Dimension>*>(inputImage.GetPointer());
	 if (itkImage.IsNull())
		 return vtkSmartPointer<vtkImageData>::New();
	 // 利用tovtkfilter转换至vtk图像
	 itk::ImageToVTKImageFilter<ImageType>::Pointer itkToVtkFilter = itk::ImageToVTKImageFilter<ImageType>::New();
	 itkToVtkFilter->SetInput(itkImage);
	 itkToVtkFilter->UpdateLargestPossibleRegion();
	 itkToVtkFilter->Update();

	 vtkSmartPointer<vtkImageData>vtkImage = vtkSmartPointer<vtkImageData>::New();
	 vtkImage = itkToVtkFilter->GetOutput();

	return vtkImage;
}

三、显示VTKImageData三维数据

参考链接
vtk体绘制代码报错的解决办法(代码在vtk7,8,9中都能运行),以及VTK数据集网站
由于我们要显示的试一个3维的数据,所以这里使用了vtkFixedPointVolumeRayCastMapper进行体绘制。

我一开始是直接使用的vtkVolumeMapper,结果在New时报错“无法从“initializer list”转换为“vtkSmartPointer””,这个是不行的,因为vtkVolumeMapper是一个抽象基类,无法创建vtkVolumeMapper实例。应该选择一个具体的子类来创建实例。

void DispOnVtkActor(vtkImageData *imagesData)
{
	// 创建一个actor,用于在渲染器中渲染图像
	//vtkSmartPointer<vtkImageActor> actor = vtkImageActor::New();
	//actor->SetInputData(imagesData);

	// 不透明度
	vtkSmartPointer<vtkPiecewiseFunction>compoisteOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
	compoisteOpacity->AddPoint(70, 0.00);
	compoisteOpacity->AddPoint(90, 1.00);
	// 梯度不透明度
	
	// 体积属性
	vtkSmartPointer<vtkVolumeProperty>volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
	//volumeProperty->ShadeOff();//关闭阴影
	//volumeProperty->SetAmbient(0.4);// 设置环境光系数
	//volumeProperty->SetDiffuse(0.6);// 设置散射光系数
	//volumeProperty->SetSpecular(0.2);// 设置反射系数
	//volumeProperty->SetSpecularPower(0.1);// 高光强度
	volumeProperty->SetScalarOpacity(compoisteOpacity);
	// 创建提体积映射器
	vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>mapper = vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>::New();
	mapper->SetInputData(imagesData);
	// 创建体积
	vtkSmartPointer<vtkVolume>volume = vtkSmartPointer<vtkVolume>::New();
	volume->SetMapper(mapper);
	volume->SetProperty(volumeProperty);

	//actor->SetMapper(mapper);

	// 创建一个渲染器
	vtkSmartPointer<vtkRenderer>render = vtkSmartPointer<vtkRenderer>::New();
	//render->AddActor(actor);
	render->AddVolume(volume);
	render->SetBackground(.1, .2, .3);//设置背景颜色
	// 创建一个渲染窗口
	vtkSmartPointer<vtkRenderWindow>renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(render);
	renderWindow->SetSize(1024,2048);
	// 创建一个渲染窗口交互器,并设置渲染窗口
	vtkSmartPointer<vtkRenderWindowInteractor>renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	//设置交互器样式,允许3D视角切换
	//vtkSmartPointer<vtkInteractorStyleImage> style =vtkSmartPointer<vtkInteractorStyleImage>::New();
	vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	//开始渲染和交互
	 renderWindowInteractor->SetInteractorStyle(style);
	 renderWindowInteractor->SetRenderWindow(renderWindow);
	 renderWindowInteractor->Initialize();
	//renderWindow->Render();
	renderWindowInteractor->Start();

}

另外,运行上面的显示程序时,发生了异常中断,“读取访问权限冲突”,
在这里插入图片描述
解决办法就是在你的程序中添加以下内容:

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);

有点不理解,这几个模块还要单独手动初始化,不咋友好。有知道的朋友可以留言~

问了百度助手,给出的解释如下:
在这里插入图片描述

  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先需要安装ITKVTK库,然后按照以下步骤实现读取DICOM文件并转换为VTK数据: 1. 导入相关头文件: ```cpp #include "itkImageSeriesReader.h" #include "itkGDCMImageIO.h" #include "itkGDCMSeriesFileNames.h" #include "itkImageToVTKImageFilter.h" ``` 2. 设置DICOM文件夹路径和输出VTK文件路径: ```cpp std::string inputPath = "path/to/dicom/folder"; std::string outputPath = "path/to/output/vtk/file.vtk"; ``` 3. 使用itkGDCMSeriesFileNames类获取DICOM文件名列表: ```cpp itk::GDCMSeriesFileNames::Pointer nameGenerator = itk::GDCMSeriesFileNames::New(); nameGenerator->SetUseSeriesDetails(true); nameGenerator->AddSeriesRestriction("0008|0021"); nameGenerator->SetDirectory(inputPath); std::vector<std::string> seriesUID = nameGenerator->GetSeriesUIDs(); std::vector<std::string> seriesFileNames = nameGenerator->GetFileNames(seriesUID[0]); ``` 4. 使用itkImageSeriesReader类读取DICOM文件: ```cpp typedef itk::Image<short, 3> ImageType; itk::ImageSeriesReader<ImageType>::Pointer reader = itk::ImageSeriesReader<ImageType>::New(); reader->SetImageIO(itk::GDCMImageIO::New()); reader->SetFileNames(seriesFileNames); reader->Update(); ImageType::Pointer image = reader->GetOutput(); ``` 5. 将ITK图像转换为VTK图像: ```cpp typedef itk::ImageToVTKImageFilter<ImageType> ConnectorType; ConnectorType::Pointer connector = ConnectorType::New(); connector->SetInput(image); connector->Update(); vtkSmartPointer<vtkImageData> vtkImage = connector->GetOutput(); ``` 6. 将VTK图像写入文件: ```cpp vtkSmartPointer<vtkXMLImageDataWriter> writer = vtkSmartPointer<vtkXMLImageDataWriter>::New(); writer->SetFileName(outputPath.c_str()); writer->SetInputData(vtkImage); writer->Write(); ``` 这样就完成了将DICOM文件转换为VTK数据的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值