这个例子介绍了如何读一个单独的DICOM切片和写回作为另一个DICOM切片。在处理过程中亮度变化也要应用。
为了读和写切片,我们这里使用itk::GDCMImageIO类,itk::GDCMImageIO类压缩了一个优先的GDCM库的连接。用这种方法我们就可以从ITK到GDCM提供的DICOM的范函性的存取。GDCMImageIO对象被itk::ImageFileWriter使用的ImageIO的对象连接。
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkGDCMImageIO.h"
#include <list>
#include <fstream>
int main( int argc, char* argv[] )
{
// 命令行参数校验
if( argc < 5 )
{
std::cerr << "Usage: " << std::endl;
std::cerr << argv[0] << " DicomImage OutputDicomImage ";
std::cerr << " OutputImage RescaleDicomImage\n";
return EXIT_FAILURE;
}
// 这时我们声明像素类型和图像维数,并用它们例示被读的图像类型。
typedef signed short InputPixelType;
const unsigned int InputDimension = 2;
typedef itk::Image< InputPixelType, InputDimension > InputImageType;
// 用图像类型我们能够例示reader的类型,创建它并设置被读的图像的文件名。
typedef itk::ImageFileReader< InputImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName( argv[1] );
// GDCMImageIO是一个读取和写入DICOM v3和ACR/NEMA图像的ImageIO类。在这里
GDCMImageIO对象被创建并与ImageFileReader相连。
typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmImageIO = ImageIOType::New();
reader->SetImageIO( gdcmImageIO );
// 这时我们调用Update()来触发读取过程。因为这个读取过程会导致异常,我们放置一个问询在try/catch模块中。
try
{
reader->Update();
}
catch (itk::ExceptionObject & e)
{
std::cerr << "exception in file reader " << std::endl;
std::cerr << e << std::endl;
return EXIT_FAILURE;
}
// 现在图像在内存中,通过GetOutput()我们可以对它进行存取。在当前例子的维护中,焦点放在我们如何再一次将图像在新文件中保存成DICOM格式。
//首先,我们必须例示一个ImageFileWriter类型。这时,我们创建它并设置用于写的文件名,连接被写的输入图像。在这个例子中,我们用不同的方法
//写图像,每种情况里我们用不 同的writer,我们列举writer对象的变量名和他们的类型。
typedef itk::ImageFileWriter< InputImageType > Writer1Type;
Writer1Type::Pointer writer1 = Writer1Type::New();
writer1->SetFileName( argv[2] );
writer1->SetInput( reader->GetOutput() );
//我们需要明确的设置对于writer滤波器的合适的图像IO,因为输入的DICOM字典沿着写入过程被传递。这个字典包含所有一个有效的DICOM文件应该包含的所有信息,像病人名 字、病人ID、机构名等等。
writer1->SetImageIO( gdcmImageIO );
// 通过调用Update()来触发写入程序。因为执行会导致异常情况出现,我们放Update()问询在一个try/catch模块里。
try
{
writer1->Update();
}
catch (itk::ExceptionObject & e)
{
std::cerr << "exception in file writer " << std::endl;
std::cerr << e << std::endl;
return EXIT_FAILURE;
}
// 我们现在将用重新调节亮度图像滤波器重新调节图像使之变到被重新调节的图像。为了
//这个目的,我们使用一个更适合的像素类型:无符字符型代替有符短型。输出图像的最小值和最大值在缩放滤波器中明确定义。
typedef unsigned char WritePixelType;
typedef itk::Image< WritePixelType, 2 > WriteImageType;
typedef itk::RescaleIntensityImageFilter<
InputImageType, WriteImageType > RescaleFilterType;
RescaleFilterType::Pointer rescaler = RescaleFilterType::New();
rescaler->SetOutputMinimum( 0 );
rescaler->SetOutputMaximum( 255 );
// 我们现在创建第二个writer对象,保存被保存的图像到一个文件中。这时不是DICOM格式。做这个只是为了校验图像,对照在这个例子里以后被
//保存成DICOM的格式。
typedef itk::ImageFileWriter< WriteImageType > Writer2Type;
Writer2Type::Pointer writer2 = Writer2Type::New();
writer2->SetFileName( argv[3] );
rescaler->SetInput( reader->GetOutput() );
writer2->SetInput( rescaler->GetOutput() );
// writer能够通过调用try/catch模块里的Update()来执行。
try
{
writer2->Update();
}
catch (itk::ExceptionObject & e)
{
std::cerr << "exception in file writer " << std::endl;
std::cerr << e << std::endl;
return EXIT_FAILURE;
}
//我们现在保存相同重新调节的图像到一个DICOM格式的文件中。为此我们仅仅需要设 置itk::ImageFileWriter并传递给它重新调节的图像作为输入。
typedef itk::ImageFileWriter< WriteImageType > Writer3Type;
Writer3Type::Pointer writer3 = Writer3Type::New();
writer3->SetFileName( argv[4] );
writer3->SetInput( rescaler->GetOutput() );
//我们现在需要明确地设置合适的图像IO (GDCMImageIO),但是我们必须告诉
//ImageFileWriter不要从输入中用MetaDataDictionary而是从GDCMImageIO中用,因为IO包含
//DICOM的精确信息。
//GDCMImageIO 对 象 将 会 自 动 地 探 测 像 素 类 型 , 这 种 情 况 下 无 符 字 符 串 和
//GDCMImageIO对象将会更新DICOM头文件信息。
writer3->UseInputMetaDataDictionaryOff ();
writer3->SetImageIO( gdcmImageIO );
try
{
writer3->Update();
}
catch (itk::ExceptionObject & e)
{
std::cerr << "Exception in file writer " << std::endl;
std::cerr << e << std::endl;
system("pasue");
return EXIT_FAILURE;
}
system("pasue");
return EXIT_SUCCESS;
}