1. 程式人生 > >【ITK學習筆記】2. 影象的讀取

【ITK學習筆記】2. 影象的讀取

1 簡單的讀取

簡單的讀取只需要 itkImageFileReader.h 以及 itkImageFileWriter.h

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

int main(int argc,char ** argv){
    typedef itk::Image<unsigned short,2> ImageType;
    typedef itk::ImageFileReader<ImageType> ReaderType;
    typedef
itk::ImageFileWriter<ImageType> WriterType; ReaderType::Pointer reader=ReaderType::New(); WriterType::Pointer writer=WriterType::New(); reader->SetFileName(argv[1]); //要讀取的檔名 writer->SetFileName(argv[2]); //寫入的檔名 writer->SetInput(reader->GetOutput()); try
{ writer->Update(); }catch(itk::ExceptionObject &err){ std::cerr<<"ExceptionObject Caught"<<std::endl; std::cerr<<err<<std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }

2 RGB影象的讀取

RGB影象只要設定影象的畫素為RGBPixel即可

...//修改
#include "itkRGBPixel.h"
typedef itk::RGBPixel<unsigned short> PixelType; typedef itk::ImageType<PixelType,2> ImageType; ....//下面的相同

3 影象的顯示 ITKtoVTK

有兩種方法

QuickView

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0020 NEW)
project(QuickViewDemo)
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
if (ITKVtkGlue_LOADED)
  find_package(VTK REQUIRED)
  include(${VTK_USE_FILE})
else()
  find_package(ItkVtkGlue REQUIRED)
  include(${ItkVtkGlue_USE_FILE})
  set(Glue ItkVtkGlue)
endif()
add_executable(QuickViewDemo  QuickViewDemo.cxx)
target_link_libraries(QuickViewDemo
  ${Glue}  ${VTK_LIBRARIES} ${ITK_LIBRARIES})

QuickViewDemo.cxx

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkRescaleIntensityImageFilter.h"
#include "QuickView.h"

int main(int argc, char *argv[])
{
  typedef itk::Image<unsigned char, 2>  ImageType;
  typedef itk::ImageFileReader<ImageType> ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(argv[1]);
  typedef itk::RescaleIntensityImageFilter< ImageType, ImageType > RescaleFilterType;
  RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New();
  rescaleFilter->SetInput(reader->GetOutput());
  rescaleFilter->SetOutputMinimum(0);
  rescaleFilter->SetOutputMaximum(255);

  QuickView viewer;
  viewer.AddImage(reader->GetOutput());
  viewer.AddImage(rescaleFilter->GetOutput());
  viewer.Visualize();

  return EXIT_SUCCESS;
}

這裡寫圖片描述

itkImageToVTKImageFilter

這裡寫圖片描述
ImageToVTKImageFilter.cxx

#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageToVTKImageFilter.h>
#include "vtkVersion.h"
#include "vtkImageViewer.h"
#include "vtkImageMapper3D.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkImageActor.h"
#include "vtkInteractorStyleImage.h"
#include "vtkRenderer.h"
#include "itkRGBPixel.h"
int main(int argc, char *argv[])
{
    typedef itk::Image<itk::RGBPixel<unsigned char>, 2> ImageType;
    typedef itk::ImageFileReader<ImageType>             ReaderType;
    typedef itk::ImageToVTKImageFilter<ImageType>       ConnectorType;
    ReaderType::Pointer reader = ReaderType::New();
    ConnectorType::Pointer connector = ConnectorType::New();

    reader->SetFileName(argv[1]);
    connector->SetInput(reader->GetOutput());

    vtkSmartPointer<vtkImageActor> actor = vtkSmartPointer<vtkImageActor>::New();

    connector->Update();
    actor->GetMapper()->SetInputData(connector->GetOutput());
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actor);
    renderer->ResetCamera();
    vtkSmartPointer<vtkRenderWindow> renderWindow =  
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor=                                               
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    vtkSmartPointer<vtkInteractorStyleImage> style =
        vtkSmartPointer<vtkInteractorStyleImage>::New();
    renderWindowInteractor->SetInteractorStyle(style);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();
    return EXIT_SUCCESS;
}

生成的影象是倒立的
這裡寫圖片描述
解決方法是 增加一個影象翻轉濾波器

//新增下面程式碼
#include "itkFlipImageFilter"
...
typedef itk::FlipImageFilter<ImageType> FilterType
typedef FlipterType::FilpAxesArrayType FlipAxesArrayType;
FlipterType::Pointer filter=FilterType::New();
FlipAxesArrayType flipArray;
flipArray[0]=0;
flipArray[1]=1;//x不變,y翻轉
fliter->SetFlipAxes(flipArray);

//修改連線順序
reader->SetFileName(argv[1]);
filter->SetInput(reader->GetOutput());//將濾波其插入到這
connector->SetInput(filter->GetOutput());

結果
這裡寫圖片描述

4 DICOM 影象的讀取

4.1. 2D Dicom 影象的讀取 以及 插拔式工廠

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

int main(int argc, char ** argv) {
    typedef itk::Image<unsigned short, 2> ImageType;
    typedef itk::ImageFileReader<ImageType> ReaderType;
    typedef itk::ImageFileWriter<ImageType> WriterType;
    typedef itk::GDCMImageIO GDCMIOType;
    typedef itk::RescaleIntensityImageFilter<ImageType,ImageType> FilterType;

    ReaderType::Pointer reader = ReaderType::New();
    WriterType::Pointer writer = WriterType::New();
    GDCMIOType::Pointer gdcmIO = GDCMIOType::New();
    FilterType::Pointer filter = FilterType::New();
    filter->SetOutputMinimum(0);
    filter->SetOutputMaximum(255);

    reader->SetFileName(argv[1]);
    reader->SetImageIO(gdcmIO);
    try {
        reader->Update();
    }
    catch (itk::ExceptionObject &err) {
        std::cerr << "ExceptionObject Caught" << std::endl;
        std::cerr << err << std::endl;
        return EXIT_FAILURE;
    }

    filter->SetInput(reader->GetOutput());

    writer->SetInput(filter->GetOutput());
    writer->SetFileName(argv[2]);
    writer->UseInputMetaDataDictionaryOff();
    writer->SetImageIO(gdcmIO);
    try {
        writer->Update();
    }
    catch (itk::ExceptionObject &err) {
        std::cerr << "ExceptionObject caught" << std::endl;
        std::cerr << err << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;

}

這裡寫圖片描述
插拔式工廠

ITK中在輸入/輸出結構後面的原理叫插拔式工廠。如上圖。從使用者的觀點看,可靠的讀寫檔案的類是
itk::ImageFileReaderitk::ImageFileWriter.這兩個類並不知道讀和寫特殊檔案格式如 PNG 和 DICOM的細節,他們所做的就是分派使用者的要求給知道檔案格式的類。這些類是itk::ImageIO的.
這裡寫圖片描述
ImageIO的每一個必須提供一個工廠類。如上圖,比如 我們需要讀取一個 PNG檔案,那麼ImageFileReader 要求 ImageIOFactory給一個能讀取PNG檔案的 ImageIO類,ImageIOFactory 會問工廠列表中那個辦到這件事,結果

PNGImageIOFactoryMetaImageIOFactory 表示 我能行,那麼就將他們註冊,建立MetaImageIOPNGImageIO 物件來讀取PNG檔案。

4.2. 2D DICOM 序列影象

讀取 序列影象寫入體資料

這是需要讀取的DICOM 序列,我們用MITK檢視
這裡寫圖片描述
程式碼

#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkImageFileWriter.h"
int main(int argc, char* argv[])
{

    if (argc < 3)
    {
        std::cerr << "Usage: " << std::endl;
        std::cerr << argv[0] << " DicomDirectory  outputFileName  [seriesName]"
            << std::endl;
        return EXIT_FAILURE;
    }
    typedef signed short    PixelType;
    const unsigned int      Dimension = 3;

    typedef itk::Image< PixelType, Dimension >         ImageType;
    typedef itk::ImageSeriesReader< ImageType >        ReaderType;
    ReaderType::Pointer reader = ReaderType::New();
    typedef itk::GDCMImageIO       ImageIOType;
    ImageIOType::Pointer dicomIO = ImageIOType::New();

    reader->SetImageIO(dicomIO);

    typedef itk::GDCMSeriesFileNames NamesGeneratorType;
    NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
    nameGenerator->SetUseSeriesDetails(true);
    nameGenerator->AddSeriesRestriction("0008|0021");
    nameGenerator->SetDirectory(argv[1]);
    try
    {
        std::cout << std::endl << "The directory: " << std::endl;
        std::cout << std::endl << argv[1] << std::endl << std::endl;
        std::cout << "Contains the following DICOM Series: ";
        std::cout << std::endl << std::endl;

        typedef std::vector< std::string >    SeriesIdContainer;
        const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
        SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
        SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
        while (seriesItr != seriesEnd)
        {
            std::cout << seriesItr->c_str() << std::endl;
            ++seriesItr;
        }

        std::string seriesIdentifier;
        if (argc > 3) // If no optional series identifier
        {
            seriesIdentifier = argv[3];
        }
        else
        {
            seriesIdentifier = seriesUID.begin()->c_str();
        }

        std::cout << std::endl << std::endl;
        std::cout << "Now reading series: " << std::endl << std::endl;
        std::cout << seriesIdentifier << std::endl;
        std::cout << std::endl << std::endl;

        typedef std::vector< std::string >   FileNamesContainer;
        FileNamesContainer fileNames;
        fileNames = nameGenerator->GetFileNames(seriesIdentifier);

        reader->SetFileNames(fileNames);
        try
        {
            reader->Update();
        }
        catch (itk::ExceptionObject &ex)
        {
            std::cout << ex << std::endl;
            return EXIT_FAILURE;
        }

        typedef itk::ImageFileWriter< ImageType > WriterType;
        WriterType::Pointer writer = WriterType::New();
        writer->SetFileName(argv[2]);
        writer->SetInput(reader->GetOutput());
        std::cout << "Writing the image as " << std::endl << std::endl;
        std::cout << argv[2] << std::endl << std::endl;
        try
        {
            writer->Update();
        }
        catch (itk::ExceptionObject &ex)
        {
            std::cout << ex << std::endl;
            return EXIT_FAILURE;
        }
    }
    catch (itk::ExceptionObject &ex)
    {
        std::cout << ex << std::endl;
        return EXIT_FAILURE;
    }
}

這裡寫圖片描述
這裡寫圖片描述
我們用MITK開啟

這裡寫圖片描述

DICOM 的 UID

DICOM 的識別碼就像命令列中的那一串數字.
我們換一組DICOM序列
這裡寫圖片描述
會發現後面部分數字不同,相同的是組織識別碼,不同的是組織內的唯一識別碼
這是他的圖片
這裡寫圖片描述

這裡寫圖片描述
如果我們只有一組影象不用分辨


#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkImageFileWriter.h"

int main(int argc, char* argv[])
{

    typedef signed short    PixelType;
    const unsigned int      Dimension = 3;
    typedef itk::Image< PixelType, Dimension >         ImageType;
    typedef itk::ImageSeriesReader< ImageType >        ReaderType;
    ReaderType::Pointer reader = ReaderType::New();

    typedef itk::GDCMImageIO       ImageIOType;
    ImageIOType::Pointer dicomIO = ImageIOType::New();
    reader->SetImageIO(dicomIO);

    typedef itk::GDCMSeriesFileNames NamesGeneratorType;
    NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
    nameGenerator->SetDirectory(argv[1]);

    try
    {
        std::cout << std::endl << "The directory: " << std::endl;
        std::cout << std::endl << argv[1] << std::endl << std::endl;
        std::cout << "Contains the following DICOM Series: ";
        std::cout << std::endl << std::endl;

        typedef std::vector< std::string >    SeriesIdContainer;
        const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();

        std::string seriesIdentifier= seriesUID.begin()->c_str();

        std::cout << std::endl << std::endl;
        std::cout << "Now reading series: " << std::endl << std::endl;
        std::cout << seriesIdentifier << std::endl;
        std::cout << std::endl << std::endl;

        typedef std::vector< std::string >   FileNamesContainer;
        FileNamesContainer fileNames;

        fileNames = nameGenerator->GetFileNames(seriesIdentifier);

        reader->SetFileNames(fileNames);

        try
        {
            reader->Update();
        }
        catch (itk::ExceptionObject &ex)
        {
            std::cout << ex << std::endl;
            return EXIT_FAILURE;
        }

        typedef itk::ImageFileWriter< ImageType > WriterType;
        WriterType::Pointer writer = WriterType::New();
        writer->SetFileName(argv[2]);
        writer->SetInput(reader->GetOutput());
        std::cout << "Writing the image as " << std::endl << std::endl;
        std::cout << argv[2] << std::endl << std::endl;
        try
        {
            writer->Update();
        }
        catch (itk::ExceptionObject &ex)
        {
            std::cout << ex << std::endl;
            return EXIT_FAILURE;
        }
    }
    catch (itk::ExceptionObject &ex)
    {
        std::cout << ex << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

這裡寫圖片描述
去掉

nameGenerator->SetUseSeriesDetails(true);

後只有組織識別嗎,沒有組織內唯一識別嗎
下面的程式碼是用標籤限制

nameGenerator->AddSeriesRestriction("0008|0021");

主要過程如下

nameGenerator->SetDirectory(argv[1]);
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
std::string seriesIdentifier= seriesUID.begin()->c_str();
std::vector< std::string > fileNames = nameGenerator->GetFileNames(seriesIdentifier);
reader->SetFileNames(fileNames);

讀取序列影象寫出序列影象

#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkImageSeriesWriter.h"
#include <vector>
#include "itksys/SystemTools.hxx"

int main( int argc, char* argv[] )
{
  if( argc < 3 )
    {
    std::cerr << "Usage: " << argv[0] <<
      " DicomDirectory  OutputDicomDirectory" << std::endl;
    return EXIT_FAILURE;
    }

  typedef signed short    PixelType;
  const unsigned int      Dimension = 3;
  typedef itk::Image< PixelType, Dimension >      ImageType;
  typedef itk::ImageSeriesReader< ImageType >     ReaderType;

  typedef itk::GDCMImageIO                        ImageIOType;
  typedef itk::GDCMSeriesFileNames                NamesGeneratorType;

  ImageIOType::Pointer gdcmIO = ImageIOType::New();
  NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();

  namesGenerator->SetInputDirectory( argv[1] );
  const ReaderType::FileNamesContainer & filenames =namesGenerator->GetInputFileNames();

  std::size_t numberOfFileNames = filenames.size();
  std::cout << numberOfFileNames << std::endl;
  for(unsigned int fni = 0; fni < numberOfFileNames; ++fni)
    {
    std::cout << "filename # " << fni << " = ";
    std::cout << filenames[fni] << std::endl;
    }
  ReaderType::Pointer reader = ReaderType::New();
  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;
    return EXIT_FAILURE;
    }
  const char * outputDirectory = argv[2];
  itksys::SystemTools::MakeDirectory( outputDirectory );
  typedef signed short    OutputPixelType;
  const unsigned int      OutputDimension = 2;

  typedef itk::Image< OutputPixelType, OutputDimension >    Image2DType;
  typedef itk::ImageSeriesWriter<ImageType, Image2DType >  SeriesWriterType;
  SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();

  seriesWriter->SetInput( reader->GetOutput() );
  seriesWriter->SetImageIO( gdcmIO );
  namesGenerator->SetOutputDirectory( outputDirectory );
  seriesWriter->SetFileNames( namesGenerator->GetOutputFileNames() );
  seriesWriter->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray() );
  try
    {
    seriesWriter->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Exception thrown while writing the series " << std::endl;
    std::cerr << excp << std::endl;
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}

關鍵程式碼

 namesGenerator->SetInputDirectory( argv[1] );
 const ReaderType::FileNamesContainer & filenames =namesGenerator->GetInputFileNames();
 namesGenerator->SetOutputDirectory( outputDirectory );
 seriesWriter->SetFileNames( namesGenerator->GetOutputFileNames() );
 seriesWriter->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray() );