Advertisement

ITK对DICOM数据的读与写

阅读量:

该文本介绍了使用ITK库进行DICOM序列读写和处理的方法,重点包括:1)通过GDCMImageIO实现DICOM序列的读写,支持三维到二维的转换;2)处理单张DICOM数据时,避免了文件头信息从reader获取可能导致的错误;3)针对输入输出类型转换的问题,使用RescaleIntensityImageFilter进行类型转换;4)在使用fastMarching算法时,需要手动设置输出原点、间距和尺寸以匹配输入图像。代码示例展示了完整的读写流程和相关设置细节。

1.读写DICOM序列

首先,通过读取一系列DICOM数据,构建三维体数据。随后,经过必要的处理过程后,输出二维DICOM数据。其中,GDCMImageIO被选作满足DICOM格式需求的ImageIO库。

读写过程如下:

复制代码
 //IO相关

    
 #include "itkGDCMImageIO.h"
    
 #include "itkGDCMSeriesFileNames.h"
    
 #include "itkImageSeriesReader.h"
    
 #include "itkImageSeriesWriter.h"
    
  
    
 int main(int argc, char *argv[])
    
 {
    
 	
    
 	typedef   float           InternalPixelType;
    
 	const     unsigned int    Dimension = 3;//输入为三维
    
 	typedef itk::Image< InternalPixelType, Dimension >  InternalImageType;
    
 	
    
 	typedef  float          OutputPixelType;
    
 	const unsigned int      OutputDimension = 2;//输出为二维
    
 	typedef itk::Image< OutputPixelType, OutputDimension > OutputImageType;
    
  
    
 	typedef  itk::ImageSeriesReader< InternalImageType > ReaderType;
    
 	typedef  itk::ImageSeriesWriter<  InternalImageType,OutputImageType  > WriterType;//自动在输入和输出之间转换
    
  
    
 	ReaderType::Pointer reader = ReaderType::New();
    
 	WriterType::Pointer writer = WriterType::New();
    
  
    
 	//DICOM数据的ImageIO
    
 	typedef itk::GDCMImageIO             ImageIOType;
    
 	ImageIOType::Pointer gdcmIO = ImageIOType::New();
    
  
    
 	//文件生成器
    
 	typedef itk::GDCMSeriesFileNames     NamesGeneratorType;
    
 	NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();
    
 	namesGenerator->SetInputDirectory("D:/VTKCode/Data/Threshold");
    
  
    
 	//保存文件名
    
 	const ReaderType::FileNamesContainer & filenames =
    
 		namesGenerator->GetInputFileNames();
    
  
    
 	reader->SetImageIO(gdcmIO);
    
 	reader->SetFileNames(filenames);
    
  
    
 	try
    
 	{
    
 		reader->Update();
    
 	}
    
 	catch (itk::ExceptionObject &excp)
    
 	{
    
 		std::cerr << "Exception thrown while writing the image" << std::endl;
    
 		std::cerr << excp << std::endl;
    
 		system("pause");
    
 		return EXIT_FAILURE;
    
 	}
    
  
    
 	//显示Image Space的不同方法
    
 	std::cout << "Spacing = ";
    
 	std::cout << gdcmIO->GetSpacing(0) <<" "<<gdcmIO->GetSpacing(1)<<" "<<gdcmIO->GetSpacing(2) << std::endl;
    
 	std::cout << "Origin = ";
    
 	std::cout << gdcmIO->GetOrigin(0) << " " << gdcmIO->GetOrigin(1) << " " << gdcmIO->GetOrigin(2) << std::endl;
    
 	const InternalImageType::SpacingType& inputSpacing = reader->GetOutput()->GetSpacing();
    
 	std::cout << "Spacing=";
    
 	std::cout << inputSpacing[0] << " " << inputSpacing[1] << " " << inputSpacing[2] << std::endl;
    
  
    
 	//输出文件夹
    
 	const char * outputDirectory = "D:/image";
    
 	itksys::SystemTools::MakeDirectory(outputDirectory);
    
  
    
 	//设置输出文件夹
    
 	namesGenerator->SetOutputDirectory(outputDirectory);
    
  
    
 	writer->SetFileNames(namesGenerator->GetOutputFileNames());
    
 	//用原来的文件头
    
 	writer->SetMetaDataDictionaryArray(
    
 		reader->GetMetaDataDictionaryArray());
    
  
    
 	writer->SetInput(reader->GetOutput());
    
 	writer->SetImageIO(gdcmIO);
    
 	try
    
 	{
    
 		writer->Update();
    
 	}
    
 	catch (itk::ExceptionObject & excep)
    
 	{
    
 		std::cerr << "Exception caught !" << std::endl;
    
 		std::cerr << excep << std::endl;
    
 		system("pause");
    
 		return EXIT_FAILURE;
    
 	}
    
  
    
 	system("pause");
    
 	return EXIT_SUCCESS;
    
 }

2.读写单张DICOM数据

在读写单张DICOM数据时,输入与输出的格式保持一致,同时采用GDCMImageIO作为ImageIO工具。其中,文件头信息不通过reader获取,而是由GDCMImageIO提供,否则可能会遇到如下问题。

复制代码
    itk::ExceptionObject (00000014AA4FD6D8)
    Location: "void __cdecl itk::GDCMImageIO::Write(const void *)"
    File: D:\S\D\ITKv4\Modules\IO\GDCM\src\itkGDCMImageIO.cxx
    Line: 1036
    Description: itk::ERROR: GDCMImageIO(000001BB3A34A4D0): A Floating point buffer was passed but the stored pixel type was not specified.This is currently not supported

读写代码如下:

复制代码
 //IO相关

    
 #include "itkImageFileReader.h"
    
 #include "itkImageFileWriter.h"
    
 #include "itkGDCMImageIO.h"
    
 #include "itkGDCMSeriesFileNames.h"
    
  
    
 int main(int argc, char *argv[])
    
 {
    
 	typedef   float           InternalPixelType;
    
 	const     unsigned int    Dimension = 2;
    
 	typedef itk::Image< InternalPixelType, Dimension >  InternalImageType;
    
 	
    
 	typedef  float      OutputPixelType;
    
 	typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
    
 	
    
 	typedef  itk::ImageFileReader< InternalImageType > ReaderType;
    
 	typedef  itk::ImageFileWriter<  OutputImageType  > WriterType;
    
  
    
 	ReaderType::Pointer reader = ReaderType::New();
    
 	WriterType::Pointer writer = WriterType::New();
    
  
    
 	//DICOM数据的ImageIO
    
 	typedef itk::GDCMImageIO      ImageIOType;
    
 	ImageIOType::Pointer gdcmIO = ImageIOType::New();
    
  
    
 	reader->SetImageIO(gdcmIO);
    
 	reader->SetFileName("D:/VTKCode/Data/digest_article/84485356.dcm");
    
  
    
 	try
    
 	{
    
 		reader->Update();
    
 	}
    
 	catch (itk::ExceptionObject &excp)
    
 	{
    
 		std::cerr << "Exception thrown while writing the image" << std::endl;
    
 		std::cerr << excp << std::endl;
    
 		system("pause");
    
 		return EXIT_FAILURE;
    
 	}
    
  
    
 	//设置输出文件
    
 	writer->SetFileName("D:/image/84485356.dcm");
    
 	//设置文件头
    
 	writer->UseInputMetaDataDictionaryOff();
    
  
    
 	writer->SetInput(reader->GetOutput());
    
 	writer->SetImageIO(gdcmIO);
    
 	try
    
 	{
    
 		writer->Update();
    
 	}
    
 	catch (itk::ExceptionObject & excep)
    
 	{
    
 		std::cerr << "Exception caught !" << std::endl;
    
 		std::cerr << excep << std::endl;
    
 		system("pause");
    
 		return EXIT_FAILURE;
    
 	}
    
  
    
 	system("pause");
    
 	return EXIT_SUCCESS;
    
 }

3.关于输入输出类型转换的问题

在DICOM序列输出中,可以通过指定输入和输出类型来实现类型转换。因此,不同类型的输入和输出类型可以实现相互转换。对于单张的情况,通常需要手动进行转换操作。通过指定输入和输出类型参数来完成转换任务,相关代码如下:

复制代码
 typedef itk::RescaleIntensityImageFilter<

    
                            InternalImageType,
    
                            OutputImageType >   CastFilterType;
    
 CastFilterType::Pointer caster = CastFilterType::New();
    
  
    
 caster->SetInput( reader->GetOutput() );
    
 writer->SetInput( caster->GetOutput() );
    
 caster->SetOutputMinimum(   0 );
    
 caster->SetOutputMaximum( 255 );
    
 writer->Update();

4.关于fastMarching的问题

ITK的GeodesicActiveContourImageFilter等算法通常采用fastMarching方法求解方程。若未指定输入参数,则默认采用spacing和origin参数进行计算,这种做法通常不够理想。因此,在实际应用中,建议用户根据输入图像调整相关属性,以确保计算的一致性和准确性。相关代码如下:

复制代码
 typedef  itk::FastMarchingImageFilter<

    
 		InternalImageType,
    
 		InternalImageType >    FastMarchingFilterType;
    
  
    
 FastMarchingFilterType::Pointer  fastMarching = FastMarchingFilterType::New();
    
  
    
 const InternalImageType::PointType& point = reader->GetOutput()->GetOrigin();
    
  
    
 InternalImageType::SpacingType spacing = reader->GetOutput()->GetSpacing();
    
 fastMarching->SetOutputOrigin(point);
    
 fastMarching->SetOutputSpacing(spacing);
    
 fastMarching->SetOutputSize(
    
 reader->GetOutput()->GetBufferedRegion().GetSize());

全部评论 (0)

还没有任何评论哟~