天天看点

基于ITK的读并写 2D的DICOM 图像

 DICOM 图像

20 世纪 70 年代,在 CT 引入之后,数字诊断图像模式例如 MRI 和电脑在临床应用的增加,美国放射医学学会 (ACR) 和国家电子制造学会 (NEMA) 认为有设置一个标准的需要,以便为不同的厂商制造的装置之间传递信息和图像带来方便。大多数医学领域的图像存储和传递都用的是 DICOM 标准。DICOM 文件由一个头文件和一个图像数据体构成。头文件包括标准和自由形成域。

这个例子介绍了如何读一个单独的 DICOM 切片以及把它写作另一个 DICOM 切片。在处理过程中应用亮度变化。

为了读和写切片,我们这里使用 itk::GDCMImageIO 类, itk::GDCMImageIO 类压缩了一个优先的 GDCM 库的连接。用这种方法我们就可以进行从 ITK 到 GDCM 提供的 DICOM 的范函性的存取。 GDCMImageIO 对象被作为 itk::ImageFileWriter 使用的 ImageIO 的对象连接。

基于ITK的读、写一幅 2D 的DICOM图像

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkGDCMImageIO.h"

#include <list>
#include <fstream>
//reader:读取DICOM格式图像  IM3
//writer1:将读取的DICOM图像再另存为DICOM图像  writer1.dcm
//writer2:读取的DICOM图像进行像素亮度改变调节后写出保存   writer2.png
//writer3:将亮度调节后的数据写成DICOM格式图像输出   writer3.dcm

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( "IM3" );
  //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();//reader:读取DICOM格式图像
    }
  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( "writer1.dcm" );
  writer1->SetInput( reader->GetOutput() );
  //我们需要明确地设置对于 writer 滤波器的合适的图像IO ,因为输入的 DICOM 是沿着写入
  //过程被传递的。这个名称包含所有有效的 DICOM 文件应该包含的所有信息,像病人名字、
  //病人ID 、机构名等等
  writer1->SetImageIO( gdcmImageIO );
  /*通过调用 Update() 来触发写入程序。因为执行会导致异常情况出现,我们放 Update() 问
    询在一个 try / catch 模块里*/
  try
    {
    writer1->Update();//writer1:将读取的DICOM图像再另存为DICOM图像
    }
  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("writer2.png");
  rescaler->SetInput(reader->GetOutput());
  writer2->SetInput(rescaler->GetOutput());

  
 //writer 能够通过调用 try/catch 模块里的 Update( ) 来执行
  try
    {
    writer2->Update();//writer2:读取的DICOM图像进行像素亮度改变调节后写出保存
    }
  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( "writer3.dcm" );
  writer3->SetInput( rescaler->GetOutput() );
  /*我们现在需要明确地设置合适的图像 IO(GDCMImageIO) ,所以我们必须告诉
  ImageFileWriter 不要从输入中用 MetaDataDictionary 而是从 GDCMImageIO 中用,因为 IO 包含
  DICOM 的精确信息。GDCMImageIO对象将会自动地探测像素类型,这种情况下无符字符串和GDCMImageIO 对象
  将会更新 DICOM 头文件信息。*/
  writer3->UseInputMetaDataDictionaryOff ();
  writer3->SetImageIO( gdcmImageIO );//写成DICOM 格式
  //最后我们调用一个 try/catch 模块的 Update( ) 来触发 DICOM writer 的执行
  try
    {
    writer3->Update();//writer3将亮度调节后的数据写成DICOM格式图像输出
    }
  catch (itk::ExceptionObject & e)
    {
    std::cerr << "Exception in file writer " << std::endl;
    std::cerr << e << std::endl;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;

}
           

//IM3:读取的输入DICOM格式图像  

//writer1:将读取的DICOM图像再另存为DICOM图像  writer1.dcm

//writer2:读取的DICOM图像进行像素亮度改变调节后写出保存   writer2.png

//writer3:将亮度调节后的数据写成DICOM格式图像输出   writer3.dcm

基于ITK的读并写 2D的DICOM 图像
基于ITK的读并写 2D的DICOM 图像

              输入MR图像:IM3                        输出DCM图像:writer1.dcm     

基于ITK的读并写 2D的DICOM 图像

     输出png图像:writer2.png

基于ITK的读并写 2D的DICOM 图像
基于ITK的读并写 2D的DICOM 图像

    输出DCM图像:writer3.dcm