当前位置:   article > 正文

【VTK库学习】使用VTK读取DICOM数据及其与DCMTK/ITK数据的转换

vtk读取dicom

使用vtkDICOMImageReader读取dicom数据

1、vtkDICOMImageReader

DICOM(代表通信和医学数字成像)是一种广泛用于交换数据的医学图像文件格式。
该类可能会处理 ACR-NEMA 文件(医学图像 DICOM 格式的前身)。但该类不处理封装格式,仅处理普通原始文件。
该类不处理多帧 DICOM 数据集。

常用的成员函数

  • SetFileName(const char *):设置文件读取路径,读取单张单帧的DCM文件
  • SetDirectoryName(const char *):设置文件夹读取路径,读取多张单帧的DCM文件
  • vtkGetFilePathMacro(DirectoryName):返回目录名称
  • GetPixelSpacing ():获取体数据的x/y/z三轴的像素间距(mm),返回double*
  • GetWidth ()/GetHeight ():获取image数据的宽、高,返回int
  • GetImagePositionPatient():最后一个图像中左上角的x,y,z 坐标返回float*
  • GetImageOrientationPatient():获取 (DICOM) 方向余弦
  • GetBitsAllocated():获取为文件中每个像素分配的位数,返回int
  • GetTransferSyntaxUID():获取最后处理的图像的传输语法 UID,
  • GetGantryAngle():获取最后处理的图像的绕y轴的旋转角度,返回float
  • GetPatientName ()/GetStudyUID ()/GetStudyID ():获取病人的姓名、检查UID和检查ID等,返回const char *

2、代码示例

#include <vtkDICOMImageReader.h>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageViewer2.h>
#include <vtkAutoInit.h>

VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)

//path:单张:DICOM数据的存储路径,多张:DICOM数据的存储文件夹
int loadDcmDataByVTK(std::string path)
{
    //读取单张单帧DICOM数据
    //vtkSmartPointer<vtkDICOMImageReader> reader =
	//	vtkSmartPointer<vtkDICOMImageReader>::New();
	//reader->SetFileName(path.c_str());
	reader->SetFileDimensionality(3);
	//reader->Update();
	
	//读取多张单帧DICOM数据
	vtkNew<vtkDICOMImageReader> reader;
    reader->SetDirectoryName(path.c_str());
    reader->Update();

    vtkSmartPointer<vtkImageData> imgData = vtkSmartPointer<vtkImageData>::New();
	imgData->DeepCopy(reader->GetOutput());   //深拷贝
	//imgData->ShallowCopy(reader->GetOutput());   //浅拷贝
    std::cout << imageViewer[0] << endl;  //打印体数据详细信息
    this->showDiocmData(imgData);
    return 1;
}

int showDiocmData(vtkSmartPointer<vtkImageData> reader)
{
	int size = reader->GetNumberOfPoints();
	if (size <= 0)
	{
		std::cerr<< ": 输入的Dicom数据为空,请重新输入!" << std::endl;
		return 0;
	}
	vtkSmartPointer<vtkImageViewer2> imageViewer =
		vtkSmartPointer<vtkImageViewer2>::New();
	imageViewer->SetInputData(reader);

	int index = 0;   
	imageViewer->SetSlice(index);     //设置切片index
	//imageViewer->SetColorLevel(int);      
	//imageViewer->SetColorWindow(int);     //设置窗宽窗位
	
	imageViewer->GetRenderer()->ResetCamera();
	imageViewer->Render();
	renderWindowInteractor->Start();

	return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

3、延伸学习:多帧的DCMTK数据转VTK的imagedata

实际应用过程中,经常会遇到多帧的DICOM数据的读取与现实,由于VTK不支持多帧数据的读取,因此可以利用DCMTK库先读取DICOM数据,再将其转换为vtkimagedata进行后续处理
DCMTK读取多帧数据的方法参见之前的帖子:
【DCMTK】使用DCMTK库读取多帧DICOM数据

读取后的两种库数据转换代码如下:

//将DCMTK读入的dicom数据存入vtkimagedata中
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <dcmtk/dcmimgle/dcmimage.h>
//imgDCM:利用dcmtk库读取的多帧dicom数据
int DCMTKtoVTKImageData(DicomImage *imgDCM,double[3] spacing)
{
	//开辟vtkimagedata的空间,初值为0
	vtkSmartPointer<vtkImageData > imageVTK= vtkSmartPointer<vtkImageData >::New();
	vtkSmartPointer<vtkInformation> info = vtkSmartPointer<vtkInformation>::New();
	//dicom图像的宽、高和帧数(z),可以在dcmtk读取文件时获得
	int row = 512;    
	int col = 512;
	int frameCount = 100;   
	int extent[6] = { 0,row - 1,0,col - 1,0,frameCount - 1 };
	imageVTK->SetDimensions(row, col, framecount);
	imageVTK->SetExtent(extent);
	imageVTK->SetSpacing(spacing[0],spacing[1],spacing[2]);
	imageVTK->SetOrigin(0, 0, 0);
	imageVTK->SetScalarType(VTK_INT, info);
	imageVTK->SetNumberOfScalarComponents(1, info);
	imageVTK->AllocateScalars(info);
	//将DcmDataset中的像素值写入vtk
	for (int k = 0; k < framecount; k++)
	{
		Uint8 /*unsigned short*/ *pixelData = (Uint8*)/*(unsigned short*)*/(img->getOutputData(8, k, 0)); //获得图像数据指针  
		if (pixelData != NULL)
		{
			for (int i = 0; i < row; i++) 
			{
				for (int j = 0; j < col; j++) 
				{
					int*p = (int*)(imageVTK->GetScalarPointer(i, j, k));
					*p = int(*(pixelData + row * i + j));
				}
			}
		}
	}
	return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

4、延伸学习:ITK image体数据与VTK image体数据的互相转换

实际应用过程中,经常可能碰到itk库和vtk库的共同应用,就需要两种库数据的互相转换

具体转换代码如下:

#include <itkVTKImageToImageFilter.h>
#include <vtkImageData.h>
#include <itkImageToVTKImageFilter.h>
#include <itkImage.h>
#include <vtkSmartPointer.h>

typedef int PixelType;
typedef itk::Image< PixelType, 3> ImageType;

//imageVTK:传入的vtk体数据 vtkSmartPointer<vtkImageData> imageVTK = vtkSmartPointer<vtkImageData>::New();
bool VTKImageToITKImage(vtkImageData* imageVTK)
{
    typedef itk::VTKImageToImageFilter<ImageType> vtkToitkFilter;
    
	vtkToitkFilter::Pointer itkFilter = vtkToitkFilter::New();
	itkFilter->SetInput(imageVTK);
	itkFilter->UpdateLargestPossibleRegion();
	try
	{
		itkFilter->Update();
	}
	catch (itk::ExceptionObject)
	{
		std::cerr<<"vtk to itk failed!"<<std::endl;
		return false;
	}
	
	return true;
}

//itkImage: 传入的itk体数据 ImageType::Pointer itkImage = ImageType::New();
bool ITKImageToVTKImage(ImageType::Pointer itkImage)
{
    typedef itk::ImageToVTKImageFilter<ImageType> ConnectorType;
	ConnectorType::Pointer connector = ConnectorType::New();
    connector->SetInput(itkImage );
	try
	{
		connector->Update();
	}
	catch (itk::ExceptionObject)
	{
		std::cerr<<"itk to vtk failed!"<<std::endl;
		return false;
	}
	
	vtkSmartPointer<vtkImageData> imageVTK = vtkSmartPointer<vtkImageData>::New();
	imageVTK->ShallowCopy(connector->GetOutput());
    return true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/901424
推荐阅读
相关标签
  

闽ICP备14008679号