ITK 学习笔记

ITK的所有实例都有一个Register()方法可以被引用它们的其他对象调用。
Register()方法增加实例的引用计数。当对实例的引用消失时,会在实例上调用Delete()方法,该方法会减少引用计数,这相当于UnRegister()方法。当引用计数返回零时,实例将被销毁。

ITK中有两种主要的数据类型:图像和网格。在itk::Image和itk::Mesh类中实现,这两个类都是itk:∶DataObject的子类。
在ITK中,数据对象是指在系统中传递的类,可以参与数据流管道。itk::Image表示数据的n维、规则采样。采样方向与方向矩阵轴平行,可以指定采样原点、像素间距和每个方向上的采样数量(即图像尺寸)。ITK中的样本或像素类型是任意的——模板参数TPixel可以指定模板实例化时的类型。(在实例化图像类时还必须指定图像的维度。)
关键是,像素类型必须支持某些操作(例如,加法或差分)。实际上,大多数应用程序将使用C++基元类型(例如int、float)或预定义的像素类型,并且很少创建新类型的像素类。

下面是几个简单的例子,带详细解释

先创建一个图像的对象

#include "itkImage.h"
 
/*
 * 设置模板参数,并给模板起别名
 * unsigned short代表每个像素占用内存的大小
 *  3代表图像的空间维度,即三维
 */
using ImageType = itk::Image<unsigned short,3>;
// 下面这种写法也可以 
//typedef itk::Image< unsigned short, 3 > ImageType; 
 
//创建image数据对象(智能指针写法)
ImageType::Pointer image = ImageType::New( ); 

itk::Image是ITK 中表示数据的类
itk::Image 遵循范型编程思想,支持任何像素类型和空间维度的图像。

ITK 中,图像以一个或多个区域组合的形式存在。一个区域是图像的一个子集。
矩形、连续的图像片段被称为区域。区域用于指定要处理图像的哪个部分,例如在多线程中,或要保存在内存中的哪个部分。
在ITK中,有三种常见的区域类型

  1. LargePossibleRegion —整个图像。
  2. BufferedRegion 是内存中存有的部分图像。
  3. RequestedRegion 是在对图像进行操作时,被滤波器或其他类请求的一部分。
    人为创建image后,需要指定图像区域。

一个区域由 itk::Index 和 itk::Size 来确定:
itk::Index : 指定图像的起始位置:
itk::Size :指定图像大小(整数):

有了这两个参数,就可以处理选定区域

ImageType::IndexType start; //用来指定图像起点位置
start[0] = 0; //代表像素所在行。(对应x坐标)
start[1] = 0; //代表像素所在列。(对应y坐标)
start[2] = 0; //代表像素所在层(有三维的话,则对应z坐标)。
 
ImageType::SizeType size;   //指定图像各方向大小
size[0] = 200; //X 方向大小
size[1] = 200; //Y 方向大小
size[2] = 200; //Z方向大小

定义了起始位置和大小后,接下来创建 ImageRegion 对象:

ImageType::RegionType region; //创建图像区域,并设置起点和大小
region.SetSize( size );
region.SetIndex( start ); 

最后,把区域传递给图像对象。

image->SetRegions( region );
image->Allocate( );   //注意:这里才真正给image对象分配内存

在图像上涂色
实际上,很少直接给图像分配内存(或对图像初始化),图像通常是从一个源文件直接读取的,比如从文件获取数据。

获取像素数据:image->GetPixel(index) ,根据索引访问像素值。
设置像素数据: image->SetPixel(index,value)
上面的get和set都是非常低效的!!!

ImageType::IndexType pixelIndex;   //创建像素位置
pixelIndex[0] = 27; // x position
pixelIndex[1] = 29; // y position
pixelIndex[2] = 37; // z position 
 
 //通过位置获取像素值
ImageType::PixelType pixelValue = image->GetPixel( pixelIndex ); 

// 给指定位置设置像素值
image->SetPixel( pixelIndex, pixelValue+1 ); 

原点和间距: 很重要!
原点和间距: 很重要!
图像原点(Image Origin,voxel direction,spacing)、体素方向(即orientation)和间距是许多应用的基础。
在这里插入图片描述

在左图中,
每一个黑色的方形框是一个像素,蓝色部分则表示像素的中心;
图像原点是图像中第一个像素的坐标;如图中原点坐标(60,70);
像素间距是像素中心之间的距离:上图中,横轴方向像素间距为20,纵轴方向上像素间距为30;
一个像素就是含有数据值的矩形区域;
图像大小指的是图像长宽方向像素个数相乘;如图中图像大小为7*6=42(像素);

ImageType::SpacingType spacing;  //创建像素间距对象
spacing[0] = 0.33; // spacing along X
spacing[1] = 0.33; // spacing along Y
spacing[2] = 1.20; // spacing along Z
image->SetSpacing( spacing );     //给图像设置间距
 
ImageType::PointType origin;       //创建像素原点对象
origin[0] = 0.0; 
origin[1] = 0.0;
origin[2] = 0.0;
image->SetOrigin( origin );        //给图像指定原点
//获取图像的间距信息
const ImageType::SpacingType& sp = image->GetSpacing( );
std::cout << "Spacing = ";
std::cout << sp[0] << ", " << sp[1] << ", " << sp[2] << std::endl; 
 
//获取图像的原点信息
const ImageType::PointType& orgn = image->GetOrigin( );
std::cout << "Origin = ";
std::cout << orgn[0] << ", " << orgn[1] << ", " << orgn[2] << std::endl; 

原点和间距一经初始化,就会以物理空间坐标来正确映射到图像像素。
(常用于查找鼠标位置的像素值等情况)

自定义图像的完整代码展示:

 //创建一个二维图像
    using ImageType = itk::Image<unsigned char,2>;
    ImageType::Pointer image = ImageType::New();
 
    ImageType::IndexType start; //创建itk::Index对象,用来指定图像起点位置
    start[0] = 0;
    start[1] = 0;
 
    ImageType::SizeType size;   //创建itk::Size对象,指定图像各方向大小
    size[0] = 200;
    size[1] = 256;
 
    ImageType::RegionType region; //创建图像区域,并设置起点和大小
    region.SetSize( size );
    region.SetIndex( start );
    image->SetRegions(region);
 
    ImageType::SpacingType spacing;  //定义像素间距
    spacing[0] = 0.1;
    spacing[1] = 0.1;
    image->SetSpacing( spacing );
 
    ImageType::PointType origin;     //定义像素原点
    origin[0] = 0.0;
    origin[1] = 0.0;
    image->SetOrigin( origin );
 
    image->Allocate( );   //分配内存
    //初始化图像缓冲区
    image->FillBuffer( itk::NumericTraits<unsigned char>::Zero );
 
	// 设置像素值
    for(int i = 0 ; i < 200; i++){ //像素所在行
        start[0] = i;
        for(int j = 0; j < 256; j++){ //像素所在列
            start[1] = j;
            image->SetPixel(start,j);  
        }
    }
 
 	 // 图像写入
     using WriterType = itk::ImageFileWriter<ImageType>;
     WriterType::Pointer writer = WriterType::New();
     writer->SetInput(image);
     writer->SetFileName("../createImage.jpg");
 
     using ImageIOType = itk::JPEGImageIO;
     ImageIOType::Pointer io = ImageIOType::New();
     writer->SetImageIO(io);
 
     try {
       writer->Update();
     }
     catch( itk::ExceptionObject & error ) {
       std::cerr << "Error: " << error << std::endl;
     }

最终效果展示:
在这里插入图片描述

从文件读取PNG图像

介绍ReaderType类的使用

#include "itkImage.h" //图像类的头文件
#include "itkImageFileReader.h" //图像读取类的头文件
#include <itkPNGImageIOFactory.h> // PNG对应
 
int main( int , char * argv[]) {
  typedef unsigned char PixelType; //图像的像素类型
  const unsigned int Dimension = 3; //图像的维数
  typedef itk::Image< PixelType, Dimension > ImageType; //定义图像的类型ImageType
  
  // 图像读取 Reader 类实例化
  typedef itk::ImageFileReader< ImageType >  ReaderType;
  ReaderType::Pointer reader = ReaderType::New(); // 创建对象reader
  
  reader->SetFileName("123.png"); // 设置图像的文件名
  reader->Update();
 
  // Reader 使用 GetOutput( )访问新读取的图像
  ImageType::Pointer image = reader->GetOutput();
  
  return EXIT_SUCCESS;
}

ImageType用作模板参数(ReaderType的参数),用于定义数据加载到内存后将如何表示。此类型不必与文件中存储的类型完全对应
除了从文件的像素类型转换为ImageFileReader的像素类型之外,Reader不会对像素数据应用任何转换。

定义图像原点和间距

The image direction matrix represents the orientation relationships between the image samples and
physical space coordinate systems. The image direction matrix is an orthonormal matrix that de-
scribes the possible permutation of image index values and the rotational aspects that are needed
to properly reconcile image index organization with physical space axis. The image directions is
a NxN matrix where N is the dimension of the image. An identity image direction indicates that
increasing values of the 1st, 2nd, 3rd index element corresponds to increasing values of the 1st, 2nd
and 3rd physical space axis respectively, and that the voxel samples are perfectly aligned with the
physical space axis.
图像方向矩阵表示图像样本和物理空间坐标系之间的方向关系。
图像方向矩阵是一个正交矩阵,它描述了图像索引值的可能排列以及正确协调图像索引组织与物理空间轴所需的旋转方面。
图像方向是NxN矩阵,其中N是图像的维度。
identity image方向指示第一、第二、第三索引元素的增加值,分别对应于第一、第2和第三物理空间轴的增加值,并且体素样本与物理空间轴完美对齐。

The following code illustrates the creation and assignment of a variable suitable for initializing the
image direction with an identity.

// coordinates of the center of the first pixel in N-D
ImageType::DirectionType direction;
direction.SetIdentity();
image->SetDirection(direction);

一旦初始化了图像样本的间距、原点和方向,图像将正确地将像素索引映射到物理空间坐标和物理空间坐标。以下代码说明了如何将物理空间中的点映射到图像索引中,以便读取最近像素的内容。首先,必须声明itk::Point类型。点类型在用于表示坐标的类型和空间维度上模板化。在这种特殊情况下,点的尺寸必须与图像的尺寸相匹配。

#include "itkImage.h"
 
// 模拟从图像中获得鼠标点击
static itk::Image< unsigned short, 3 >::IndexType GetIndexFromMouseClick()
{
  itk::Image< unsigned short, 3 >::IndexType LeftEyeIndex;
  LeftEyeIndex[0]=60;
  LeftEyeIndex[1]=127;
  LeftEyeIndex[2]=93;
  return LeftEyeIndex;
}

int main(int, char *[])
{
  const unsigned int Dimension=3;
  typedef itk::Image< unsigned short, Dimension > ImageType;
  ImageType::Pointer image = ImageType::New();
 
  const ImageType::SizeType  size  = {{ 200, 200, 200}}; //Size along {X,Y,Z}
  const ImageType::IndexType start = {{ 0, 0, 0 }}; // First index on {X,Y,Z}
 
  ImageType::RegionType region;
  region.SetSize( size );
  region.SetIndex( start );
 
  image->SetRegions( region );
  image->Allocate(true); // initialize buffer to zero
 
  //创建一个和图像数据类型相一致的数列spacing
  ImageType::SpacingType spacing;
  //设定X、Y、Z方向间距
  spacing[0] = 0.33; // X方向 相邻两像素中心的间距
  spacing[1] = 0.33; // Y方向 相邻两像素中心的间距
  spacing[2] = 1.20; // Z方向 相邻两像素中心的间距
  image->SetSpacing( spacing ); //给图像设置间距
  //使用 GetSpacing( ) 方法可以从图像中得到间距信息, const 表示数列是不可修改的
  const ImageType::SpacingType& sp = image->GetSpacing();
  std::cout << "Spacing = ";
  std::cout << sp[0] << ", " << sp[1] << ", " << sp[2] << std::endl;   //输出读取到的间距信息
 
  // 初始化图像原点的创建和分配
  ImageType::PointType newOrigin;
  newOrigin.Fill(0.0);
  image->SetOrigin( newOrigin );
  const ImageType::PointType & origin = image->GetOrigin();   //从图像中读取原点
  std::cout << "Origin = ";   //输出读取到的原点坐标
  std::cout << origin[0] <<", "<< origin[1] <<", "<< origin[2] <<std::endl;
 
  // 图像方向矩阵代表了图像采样和物理空间坐标系统之间的方向关系。
  // 图像方向矩阵是一个标准正交矩阵,是一个N*N矩阵,其中N是图像维数
  // 初始化恒等图像方向的变量的创建和分配
  ImageType::DirectionType direction;
  direction.SetIdentity();
  image->SetDirection( direction );
 
  // 使用GetDirection( )方法也可以从图像中提取方向。这将返回Matrix的一个引用。
  // 该引用可以用来读取数组中的内容。注意关键字const 表示数组内容是不可修改的。
  const ImageType::DirectionType& direct = image->GetDirection();
  std::cout << "Direction = " << std::endl << direct << std::endl;

  // 将物理空间点映射到图像索引,以读取其邻近像素的内容
  // itk::Point类型 表示坐标的类型和空间大小之上模块化
  typedef itk::Point< double, ImageType::ImageDimension > PointType;
  
  PointType point;
  point[0] = 1.45;    // x coordinate
  point[1] = 7.21;    // y coordinate
  point[2] = 9.28;    // z coordinate
  // IndexType 就是图像指定起点的那个类型,在第一个例子中
  ImageType::IndexType pixelIndex;
  
  // 将Point 映射到 index
  // TransformPhysicalPointToIndex( ) 可以计算出与point 最接近的像素index、
  const bool isInside =
    image->TransformPhysicalPointToIndex( point, pixelIndex );
  // 访问图像像素的数据
  if ( isInside ) {
    ImageType::PixelType pixelValue = image->GetPixel( pixelIndex );
    pixelValue += 5;
    image->SetPixel( pixelIndex, pixelValue );
  }
  
  const ImageType::IndexType LeftEyeIndex = GetIndexFromMouseClick();
  ImageType::PointType LeftEyePoint;
  image->TransformIndexToPhysicalPoint(LeftEyeIndex,LeftEyePoint);
 
  std::cout << "===========================================" << std::endl;
  std::cout << "The Left Eye Location is " << LeftEyePoint << std::endl;
 
  
  typedef itk::Matrix<double, Dimension, Dimension> MatrixType;
  MatrixType SpacingMatrix;
  SpacingMatrix.Fill( 0.0F );
 
  const ImageType::SpacingType & ImageSpacing = image->GetSpacing();
  SpacingMatrix( 0,0 ) = ImageSpacing[0];
  SpacingMatrix( 1,1 ) = ImageSpacing[1];
  SpacingMatrix( 2,2 ) = ImageSpacing[2];
 
  const ImageType::DirectionType & ImageDirectionCosines =
    image->GetDirection();
  const ImageType::PointType &ImageOrigin = image->GetOrigin();
 
  typedef itk::Vector< double, Dimension > VectorType;
  VectorType LeftEyeIndexVector;
  LeftEyeIndexVector[0]= LeftEyeIndex[0];
  LeftEyeIndexVector[1]= LeftEyeIndex[1];
  LeftEyeIndexVector[2]= LeftEyeIndex[2];
 
  ImageType::PointType LeftEyePointByHand =
     ImageOrigin + ImageDirectionCosines * SpacingMatrix * LeftEyeIndexVector;
 
  std::cout << "===========================================" << std::endl;
  std::cout << "Spacing:: " << std::endl << SpacingMatrix << std::endl;
  std::cout << "===========================================" << std::endl;
  std::cout << "DirectionCosines:: " << std::endl << ImageDirectionCosines << std::endl;
  std::cout << "===========================================" << std::endl;
  std::cout << "Origin:: " << std::endl << ImageOrigin << std::endl;
  std::cout << "===========================================" << std::endl;
  std::cout << "The Left Eye Location is " << LeftEyePointByHand << std::endl;
 
  if ( (LeftEyePointByHand - LeftEyePoint).GetNorm() < 0.01F )
  {
    std::cout << "===========================================" << std::endl;
    std::cout << "Two results are identical as expected!" << std::endl;
    std::cout << "The Left Eye from TransformIndexToPhysicalPoint is " << LeftEyePoint << std::endl;
    std::cout << "The Left Eye from Math is " << LeftEyePointByHand << std::endl;
  }
 
  return EXIT_SUCCESS;
}

在这里插入图片描述
图像采样的间距、原点和方向一经初始化,图像就会正确映射像素索引到物理空间坐标。
方向在上面的代码中有体现

RGB图像-像素色彩的访问

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkRGBPixel.h" // 使用 itk::RGBPixel 类
int main( int , char * argv[] )
{
  //RGBPixeld 类的使用是基于用来代表红、绿和蓝的像素成分的类型之上的
  //定义RGBPixel类型的PixelType对象
  typedef itk::RGBPixel< unsigned char >    PixelType;
  typedef itk::Image< PixelType, 3 >   ImageType;
  typedef itk::ImageFileReader< ImageType >  ReaderType; // 从文件中读取图像
  ReaderType::Pointer reader = ReaderType::New(); // 实例化ReaderType
  const char * const filename = "789.jpg";
  reader->SetFileName( filename );
  reader->Update();
  //reader读取到的图像数据输出到image
  ImageType::Pointer image = reader->GetOutput();
  const ImageType::IndexType pixelIndex = {{25,35,0}};
 
  PixelType onePixel = image->GetPixel( pixelIndex );
  PixelType::ValueType red   = onePixel.GetRed();//提取红色部分
  PixelType::ValueType green = onePixel.GetGreen();//提取绿色部分
  PixelType::ValueType blue  = onePixel.GetBlue();//提取蓝色部分

  std::cout << "method1" << std::endl;
  std::cout << "Pixel values from GetRed,GetGreen,GetBlue:" << std::endl;
  std::cout << "Red = "
            << itk::NumericTraits<PixelType::ValueType>::PrintType(red)
            << std::endl;
  std::cout << "Green = "
            << itk::NumericTraits<PixelType::ValueType>::PrintType(green)
            << std::endl;
  std::cout << "Blue = "
      << itk::NumericTraits<PixelType::ValueType>::PrintType(blue)
      << std::endl << std::endl;
 
  //由于 itk::RGBPixel 从 itk::FixedArray 类继承了 [ ] 操作
  //所以以下方法也可对像素色彩成分的访问
  red   = onePixel[0];  // extract Red   component
  green = onePixel[1];  // extract Green component
  blue  = onePixel[2];  // extract Blue  component

  return EXIT_SUCCESS;
}

在这里插入图片描述

向量图像(将一个向量存储到一个图像像素中)

使用itk::Vector类来定义像素类型。Vector类旨在表示空间中的几何矢量。
The Vector class is templated over the type used to represent the coordinate in space and over the
dimension of the space.

#include "itkVector.h"//向量类的头文件
#include "itkImage.h"
 
int main(int, char *[])
{
  /*向量类的使用是在基于空间中代表坐标和维数的类型之上进行模板化的。在此例中,向
  量的长度和图像长度相匹配,但并不是完全相同。我们可以用一个三维的向量作为像素来
  定义一个四维的图像*/
  typedef itk::Vector< float, 3 >       PixelType;
  typedef itk::Image< PixelType, 3 >    ImageType;
  
  ImageType::Pointer image = ImageType::New();
 
  const ImageType::IndexType start = {{0,0,0}}; //First index at {X,Y,Z}
  const ImageType::SizeType  size = {{200,200,200}}; //Size of {X,Y,Z}
 
  ImageType::RegionType region;
  region.SetSize( size );
  region.SetIndex( start );
 
  image->SetRegions( region );
  image->Allocate();
 
  ImageType::PixelType  initialValue; // 像素值类型
  initialValue.Fill( 0.0 );
  image->FillBuffer( initialValue );
  const ImageType::IndexType pixelIndex = {{27,29,37}}; //{X,Y,Z}对应像素索引位置
  //由于向量类从 itk::FixedArray 类继承了[] 操作,所以可以使用下标访问向量成员
  ImageType::PixelType   pixelValue;
  pixelValue[0] =  1.345;   // x component
  pixelValue[1] =  6.841;   // y component
  pixelValue[2] =  3.295;   // x component
 
  std::cout << "pixelIndex索引处给定的向量值:" << std::endl;
  std::cout << pixelValue << std::endl;
  // SetPixel( ) 将这个向量储存到pixelIndex索引像素中
  image->SetPixel(   pixelIndex,   pixelValue  );
  ImageType::PixelType value = image->GetPixel( pixelIndex );  //获取pixelIndex处像素值value
  std::cout << "pixelIndex索引处读取的像素值:" << std::endl;
  std::cout << value << std::endl;
 
  return EXIT_SUCCESS;
}

在这里插入图片描述

从缓冲器中输入图像数据

如何将数据导入itk::Image类?
这与其他软件系统的接口特别有用。许多系统使用连续的内存块作为图像像素数据的缓冲区。当前示例假设是这种情况,会将缓冲区输入到itk::ImportImageFilter中,从而生成图像作为输出。
注意: ITK的内部编码在访问像素时不使用 for () 循环。
而是使用支持处理 n 维图像的 itk::ImageIterators 来代替执行所以的像素访问任务。

在这里,我们在本地分配的缓冲区中创建一个具有居中球体的合成图像,并将此内存块传递给ImportImageFilter。用户必须提供输出文件的名称作为命令行参数。

#include "itkImage.h"
#include "itkImportImageFilter.h"//包含 ImportImageFilter(图像像素数据导入缓冲器) 类的头文件
#include "itkImageFileWriter.h"

int main(int argc, char * argv[])
{
  /*选择数据类型来表示图像像素。我们假设内存的外部内存块使用同样的数据类
    型来表示像素*/
  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 );
  // 指定输出图像的原点
  const itk::SpacePrecisionType origin[ Dimension ] = { 0.0, 0.0, 0.0 };
  importFilter->SetOrigin( origin );
  // 传递输出图像的间距
  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。请注意,此方法的最后一个参数指定了不再使用内存块时,谁负责删除该内存块。如果值为false,则表示ImportImageFilter在调用析构函数时不会删除缓冲区。另一方面,设为true将允许过滤器在销毁mport filter时删除内存块。为了让ImportImageFilter适当地删除内存块,必须使用C++ new()运算符分配内存。使用其他内存分配机制(如C malloc或calloc)分配的内存不会被ImportImageFilter正确删除。*/
  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");
  /*最后,我们可以将此过滤器的输出连接到管道。
  为了简单起见,我们在这里只使用ImageFileWriter,但它可以是任何其他过滤器。*/
  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 所有

在这里插入图片描述

实例-两张图片叠加:

#include "itkImage.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkAddImageFilter.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"

using ImageType = itk::Image<unsigned char, 2>;

static void
CreateImage1(ImageType::Pointer image);
static void
CreateImage2(ImageType::Pointer image);

static int testFunc() {
	// 创建两个初始图象
	auto image1 = ImageType::New();
	CreateImage1(image1);
	auto image2 = ImageType::New();
	CreateImage2(image2);

	using AddImageFilterType = itk::AddImageFilter<ImageType, ImageType>;

	auto addFilter = AddImageFilterType::New();
	addFilter->SetInput1(image1);
	addFilter->SetInput2(image2);
	addFilter->Update();

	// 可视化,将ITK转为VTK(ITK没有提供可视化功能)
	using ConnectorType = itk::ImageToVTKImageFilter<ImageType>;
	auto connector1 = ConnectorType::New();
	connector1->SetInput(image1);

	vtkSmartPointer<vtkImageActor> actor1 = vtkSmartPointer<vtkImageActor>::New();
#if VTK_MAJOR_VERSION <= 5
	actor1->SetInput(connector1->GetOutput());
#else
	connector1->Update();
	actor1->GetMapper()->SetInputData(connector1->GetOutput());
#endif

	using ConnectorType = itk::ImageToVTKImageFilter<ImageType>;
	auto connector2 = ConnectorType::New();
	connector2->SetInput(image2);

	vtkSmartPointer<vtkImageActor> actor2 = vtkSmartPointer<vtkImageActor>::New();
#if VTK_MAJOR_VERSION <= 5
	actor2->SetInput(connector2->GetOutput());
#else
	connector2->Update();
	actor2->GetMapper()->SetInputData(connector2->GetOutput());
#endif

	// Visualize joined image
	auto addConnector = ConnectorType::New();
	addConnector->SetInput(addFilter->GetOutput());

	vtkSmartPointer<vtkImageActor> addActor = vtkSmartPointer<vtkImageActor>::New();
#if VTK_MAJOR_VERSION <= 5
	addActor->SetInput(addConnector->GetOutput());
#else
	addConnector->Update();
	addActor->GetMapper()->SetInputData(addConnector->GetOutput());
#endif
	// There will be one render window
	vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->SetSize(900, 300);

	vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactor->SetRenderWindow(renderWindow);

	// Define viewport ranges
	// (xmin, ymin, xmax, ymax)
	double leftViewport[4] = { 0.0, 0.0, 0.33, 1.0 };
	double centerViewport[4] = { 0.33, 0.0, 0.66, 1.0 };
	double rightViewport[4] = { 0.66, 0.0, 1.0, 1.0 };

	// Setup both renderers
	vtkSmartPointer<vtkRenderer> leftRenderer = vtkSmartPointer<vtkRenderer>::New();
	renderWindow->AddRenderer(leftRenderer);
	leftRenderer->SetViewport(leftViewport);
	leftRenderer->SetBackground(.6, .5, .4);

	vtkSmartPointer<vtkRenderer> centerRenderer = vtkSmartPointer<vtkRenderer>::New();
	renderWindow->AddRenderer(centerRenderer);
	centerRenderer->SetViewport(centerViewport);
	centerRenderer->SetBackground(.4, .5, .6);

	vtkSmartPointer<vtkRenderer> rightRenderer = vtkSmartPointer<vtkRenderer>::New();
	renderWindow->AddRenderer(rightRenderer);
	rightRenderer->SetViewport(rightViewport);
	rightRenderer->SetBackground(.4, .5, .6);

	// Add the sphere to the left and the cube to the right
	leftRenderer->AddActor(actor1);
	centerRenderer->AddActor(actor2);
	rightRenderer->AddActor(addActor);

	leftRenderer->ResetCamera();
	centerRenderer->ResetCamera();
	rightRenderer->ResetCamera();

	renderWindow->Render();

	vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
	interactor->SetInteractorStyle(style);

	interactor->Start();

	return 1000;
}

void
CreateImage1(ImageType::Pointer image)
{
	// Create an image with 2 connected components
	ImageType::RegionType region;
	ImageType::IndexType  start;
	start[0] = 0;
	start[1] = 0;

	ImageType::SizeType size;
	unsigned int        NumRows = 200;
	unsigned int        NumCols = 300;
	size[0] = NumRows;
	size[1] = NumCols;

	region.SetSize(size);
	region.SetIndex(start);

	image->SetRegions(region);
	image->Allocate();

	// Make a square
	for (unsigned int r = 20; r < 80; ++r)
	{
		for (unsigned int c = 20; c < 80; ++c)
		{
			ImageType::IndexType pixelIndex;
			pixelIndex[0] = r;
			pixelIndex[1] = c;

			image->SetPixel(pixelIndex, 15);
		}
	}
}


void
CreateImage2(ImageType::Pointer image)
{
	// Create an image with 2 connected components
	ImageType::RegionType region;
	ImageType::IndexType  start;
	start[0] = 0;
	start[1] = 0;

	ImageType::SizeType size;
	unsigned int        NumRows = 200;
	unsigned int        NumCols = 300;
	size[0] = NumRows;
	size[1] = NumCols;

	region.SetSize(size);
	region.SetIndex(start);

	image->SetRegions(region);
	image->Allocate();

	// Make another square
	for (unsigned int r = 40; r < 100; ++r)
	{
		for (unsigned int c = 40; c < 100; ++c)
		{
			ImageType::IndexType pixelIndex;
			pixelIndex[0] = r;
			pixelIndex[1] = c;

			image->SetPixel(pixelIndex, 15);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值