1. 程式人生 > 其它 >ITK系列8_ 從緩衝器中輸入影象資料

ITK系列8_ 從緩衝器中輸入影象資料

例項8從緩衝器中輸入影象資料

#include "itkImage.h"
#include "itkImportImageFilter.h"//包含 ImportImageFilter(影象畫素資料匯入緩衝器) 類的標頭檔案
#include "itkImageFileWriter.h"
//這個例子闡述瞭如何將資料輸入到 itk::Image 類中。這在同其他軟體系統相連時更加有
//用。許多系統都使用記憶體的一個鄰近記憶體塊作為影象畫素資料的緩衝器。當前樣例就是假定
//這種情況並在緩衝器中插入一個 itk::ImportImageFilter ,從而產生一個影象作為輸出。
//我們呼叫記憶體中心塊建立一個同步的影象並將這個記憶體塊傳給 ImportImageFilter 。這個
//例子是基於執行上而設定的,使用者必須提供一個輸出檔名作為一個命令列變數。
int main(int argc, char * argv[])
{
  /*if( argc < 2 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  outputImageFile" << std::endl;
    return EXIT_FAILURE;
    }*/
  /*選擇資料型別來表示影象畫素。我們假設記憶體的外部記憶體塊使用同樣的資料類
    型來表示畫素*/
  typedef unsigned char   PixelType;
  const unsigned int Dimension = 3;

  typedef itk::Image< PixelType, Dimension > ImageType;
  //ImportImageFilter 型別的例項化
  typedef itk::ImportImageFilter< PixelType, Dimension >   ImportFilterType;
  //使用 New( ) 方法建立一個濾鏡物件importFilter然後指向一個智慧指標
  ImportFilterType::Pointer importFilter = ImportFilterType::New();
  /*濾鏡要求使用者指定影象的大小來作為輸出,使用 SetRgion() 方法即可做到。影象大小必
   須和當前呼叫的緩衝器的畫素變數的數字相匹配*/
  ImportFilterType::SizeType  size;
  size[0]  = 200;  // size along X
  size[1]  = 200;  // size along Y
  size[2]  = 200;  // size along Z
  ImportFilterType::IndexType start;
  start.Fill(0);

  ImportFilterType::RegionType region;
  region.SetIndex( start );
  region.SetSize(  size  );
  importFilter->SetRegion( region );
  //使用 SetOrigin() 方法來指定輸出影象的原點
  const itk::SpacePrecisionType origin[ Dimension ] = { 0.0, 0.0, 0.0 };
  importFilter->SetOrigin( origin );
  //使用 SetSpacing( ) 方法來傳遞輸出影象的間距
  const itk::SpacePrecisionType  spacing[ Dimension ] =  { 1.0, 1.0, 1.0 };
  importFilter->SetSpacing( spacing );
  /*現在我們分配包含畫素資料的記憶體塊傳遞資訊到 ImportImageFilter 。注意:我們使用與
  SetRegion() 方法指定的大小完全相同的尺寸。在實際應用中,你可以使用一個代表影象的
  不同的資料結構從一些其他的類庫中得到這個緩衝器。*/
  const unsigned int numberOfPixels =  size[0] * size[1] * size[2];
  PixelType * localBuffer = new PixelType[ numberOfPixels ];

  const double radius = 80.0;
  /*這裡可以用一個 binary sphere 來填充這個緩衝器。這裡我們像 C 或 FOTTRAN 程式設計語
  言一樣使用簡單的 for () 迴圈。注意: ITK 在其訪問畫素的內部編碼中不能使用 for () 迴圈。
  使用支援處理 n 維影象的 itk::ImageIterators 來代替執行所以的畫素訪問任務。*/
  const double radius2 = radius * radius;
  PixelType * it = localBuffer;

  for(unsigned int z=0; z < size[2]; z++)
    {
    const double dz = static_cast<double>( z )
      - static_cast<double>(size[2])/2.0;
    for(unsigned int y=0; y < size[1]; y++)
      {
      const double dy = static_cast<double>( y )
        - static_cast<double>(size[1])/2.0;
      for(unsigned int x=0; x < size[0]; x++)
        {
        const double dx = static_cast<double>( x )
          - static_cast<double>(size[0])/2.0;
        const double d2 = dx*dx + dy*dy + dz*dz;
        *it++ = ( d2 < radius2 ) ? 255 : 0;
        }
      }
    }
 /* 緩衝器在 SetImportPointer() 作用下傳遞到 ImportImageFilter 。注意這種方法的最後一個
 問題是當記憶體不再使用時指定誰來釋放記憶體。當返回值為假時,表示當呼叫析構時
 ImportImageFilter 並沒有釋放緩衝器;另一方面,當返回值是真時,表示允許釋放析構的輸
 入濾鏡上的記憶體塊。
 由於 ImportImageFilter 釋放了適當的記憶體塊, C++ new() 操作就可以呼叫這些記憶體。用
 其他分配記憶體機制分配的記憶體,比如 C 中的 malloc 和 calloc ,將不會由 ImportImageFilter
 來釋放適當的記憶體。換句話說,程式設計應用者就需要確保僅僅給 ImportImageFilter 命令來釋放
 C++ 新操作分配記憶體。*/
  const bool importImageFilterWillOwnTheBuffer = true;
  importFilter->SetImportPointer( localBuffer, numberOfPixels,
                                  importImageFilterWillOwnTheBuffer );
  typedef itk::ImageFileWriter< ImageType > WriterType;
  WriterType::Pointer writer = WriterType::New();

  writer->SetFileName(argv[1]);
  writer->SetFileName("123.png");
  /*最後,我們將這個濾鏡的輸出連到一個管道上。為簡便起見,我們在這裡只使用一個
  writer ,當然其他任何濾鏡都可以:*/
  writer->SetInput(  importFilter->GetOutput()  );

  try
    {
    writer->Update();
    }
  catch( itk::ExceptionObject & exp )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << exp << std::endl;
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
//注意:我們傳遞 true 作為 SetImportPointer() 的最後問題就不需要對緩衝器呼叫釋放操
//作。現在緩衝器歸 ImportImageFilter 所有

輸入影象123.png 寫入資料後的影象123.png

ITK系列目錄:

1 ITK影象資料表達之影象

2 ITK影象處理之影象濾波

3 ITK影象處理之影象分割

注:例程配套素材見系列目錄