天天看點

用ITK讀、寫一幅2D圖像(DICOM切片)

這個例子介紹了如何讀一個單獨的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; }

繼續閱讀