基于C++的ITK图像分割与配准学习笔记2(图像滤波)

ITK学习参考资料整理汇总(包含 ItkSoftwareGuide.PDF英文版、ItkSoftwareGuide-2.4.0-中文版、医学图像分割与配准(1ITK初步分册) (1)PDF、 医学图像分割与配准(ITK实现分册2)PDF、ITK介绍与开发  WORD中文版)

本文章全部源码和用到的素材整理汇总

 

ITK系列目录:

1 ITK图像数据表达之图像

2 ITK图像处理之图像滤波

3 ITK图像处理之图像分割

 

目录:

1 投射和亮度映射

实例1 PNG图像进行二维线性映射

实例2 MHA格式文件进行三维线性映射

2 非线性映射

实例3 PNG图像进行二维非线性映射

实例4 MHA格式文件进行三维非线性映射

3 梯度

实例5 PNG图像进行不带滤波的二维梯度强度提取

实例6 PNG图像进行带滤波的二维梯度强度提取

实例7 MHA格式文件进行带滤波三维的梯度强度提取

实例8 PNG图像进行不带滤波二维的导函数提取

 

 

1 投射和亮度映射

本节介绍的滤波器实现 pixel-wise 亮度映射投射用来将一种像素类型转换成另一种,而亮度映射也用来计算不同像素类型的亮度范围

本小节介绍流经流水线的图像的外在投射的机制。下面将处理接下来的四个滤波器:itk::CastImageFilteritk::RescaleIntensityImageFilteritk::ShiftScaleImageFilteritk::NormalizeImageFilter 。这些滤波器除了它们都可以修改像素值之外,互相之间并不直接相关。这里将它们放在一起是为了比较它们之间各自的特征。CastImageFilter 是一个非常简单的滤波器,它对输入图像进行 pixel-wise ,将每个像素投射到输出图像类型。注意这个滤波器并不对亮度执行任何算法操作。应用 CastImageFilter等价于对每个像素执行一个 C 类型的投射。

                                          outputPixel = static cast( inputPixel )
RescaleIntensityImageFilter 以一种将输入的最大值、最小值映射到用户提供的最大值、最小值的方式来线性地度量像素值。这是强制将图像的动态范围转换为适合于图像显示常见的一个特定范围内的一个普遍过程。这个滤波器应用的变换可以表达为:

                                   

ShiftScaleImageFilter 同样应用一个输入图像亮度的线性变换,不过这个变换是由用户以增加一个值并乘一个乘数因子的形式来指定的。可以表达为:

                                                           

NormalizeImageFilter 应用的线性变换的参数是在中心计算的,因此输出图像灰度级的统计分布的均值为 0 ,方差为 1 。这个亮度修正在作为相互信息度量的估计的一个预处理步骤的注册应用中特别有用。 NormalizeImageFilter 的线性变换可以表达为:

                                                                             

实例1 PNG图像进行二维线性映射

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
//线性映射头文件
#include "itkCastImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkNormalizeImageFilter.h"

int main( int argc, char * argv[] )
{
 /* if( argc < 2 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "   inputImageFile " << std::endl;
    return EXIT_FAILURE;
    }*/
//我们定义输入和输出图像的像素类型
  typedef   float    InputPixelType;
  //typedef   float            OutputPixelType;
  typedef  unsigned char  OutputPixelType;
  //然后,定义输入和输出图像类型
  typedef itk::Image< InputPixelType,  2 >   InputImageType;
  typedef itk::Image< OutputPixelType, 2 >   OutputImageType;
 
  typedef itk::ImageFileReader< InputImageType >  ReaderType;//读文件类型
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;//写文件类型
  //使用定义的图像类型来对滤波器进行实例化
  typedef itk::CastImageFilter<
               InputImageType, OutputImageType >  CastFilterType;

  typedef itk::RescaleIntensityImageFilter<
               InputImageType, OutputImageType >  RescaleFilterType1;

  typedef itk::ShiftScaleImageFilter<
               InputImageType, OutputImageType >  ShiftScaleFilterType;

  typedef itk::NormalizeImageFilter<
               InputImageType, OutputImageType >  NormalizeFilterType;

  ReaderType::Pointer reader = ReaderType::New();//实例化对象reader
  WriterType::Pointer writer1 = WriterType::New();//实例化对象writer1
  WriterType::Pointer writer2 = WriterType::New();//实例化对象writer2
  WriterType::Pointer writer3 = WriterType::New();//实例化对象writer3
  WriterType::Pointer writer4 = WriterType::New();//实例化对象writer4
  //通过调用 New( ) 操作来创建对象滤波器并将结果指向 itk::SmartPointers 
  CastFilterType::Pointer       castFilter       = CastFilterType::New();
  RescaleFilterType1::Pointer    rescaleFilter    = RescaleFilterType1::New();
  ShiftScaleFilterType::Pointer shiftFilter      = ShiftScaleFilterType::New();
  NormalizeFilterType::Pointer  normalizeFilter = NormalizeFilterType::New();

  reader->SetFileName( "BrainProtonDensitySlice.png" );
  //现在将一个 reader 滤波器 ( 这里并未展示它的创建 ) 的输出作为输入连接到投射滤波器(四种)
  castFilter->SetInput( reader->GetOutput() );//castFilter滤波器
  shiftFilter->SetInput( reader->GetOutput() );//shiftFilter滤波器
  rescaleFilter->SetInput( reader->GetOutput() );//rescaleFilter滤波器
  normalizeFilter->SetInput( reader->GetOutput() );//normalizeFilter滤波器
  /*接下来我们设置每个滤波器需要的参数。 CastImageFilter 和 NormalizeImageFilter 不需要
      任何参数。另一方面, RescaleIntensityImageFilter 需要用户提供想得到的输出图像像素值的
      最大最小值,这可以通过使用 SetOutputMinimum() 和 SetOutputMaximum() 方式来实现,如
      下所示*/
  rescaleFilter->SetOutputMinimum(  0 );
  rescaleFilter->SetOutputMaximum( 255 );
  /*ShiftScaleImageFilter 需要一个乘数因子(比例)(一个传递比例的附加值(移位)。可以
      分别使用 SetScale() 和 SetShift() 方式来设置这些值*/
  shiftFilter->SetScale( 1.2 );//1.2
  shiftFilter->SetShift( 25 );//25
  //最后,通过调用 Update() 方式来运行这些滤波器
  /*castFilter->Update();
  shiftFilter->Update();
  rescaleFilter->Update();
  normalizeFilter->Update();*/
  //写文件,输出线性映射四种滤波效果
  writer1->SetFileName("castFilter_out.png");
  writer2->SetFileName("shiftFilter_out.png");
  writer3->SetFileName("rescaleFilter_out.png");
  writer4->SetFileName("normalizeFilter_out.png");

  typedef unsigned char                          WritePixelType;
  typedef itk::Image< WritePixelType, 2 >        WriteImageType;
  typedef itk::RescaleIntensityImageFilter<
      OutputImageType, WriteImageType > RescaleFilterType;

  RescaleFilterType::Pointer rescaler1 = RescaleFilterType::New();
  RescaleFilterType::Pointer rescaler2 = RescaleFilterType::New();
  RescaleFilterType::Pointer rescaler3 = RescaleFilterType::New();
  RescaleFilterType::Pointer rescaler4 = RescaleFilterType::New();

  rescaler1->SetOutputMinimum(0);
  rescaler1->SetOutputMaximum(255);

  rescaler2->SetOutputMinimum(0);
  rescaler2->SetOutputMaximum(255);

  rescaler3->SetOutputMinimum(155);
  rescaler3->SetOutputMaximum(255);

  rescaler4->SetOutputMinimum(0);
  rescaler4->SetOutputMaximum(255);

  rescaler1->SetInput(castFilter->GetOutput());
  rescaler2->SetInput(shiftFilter->GetOutput());
  rescaler3->SetInput(rescaleFilter->GetOutput());
  rescaler4->SetInput(normalizeFilter->GetOutput());

  writer1->SetInput(rescaler1->GetOutput());
  writer2->SetInput(rescaler2->GetOutput());
  writer3->SetInput(rescaler3->GetOutput());
  writer4->SetInput(rescaler4->GetOutput());

  writer1->Update();
  writer2->Update();
  writer3->Update();
  writer4->Update();

  return EXIT_SUCCESS;
}

     基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第1张图片    基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第2张图片    基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第3张图片     基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第4张图片   基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第5张图片

               输入图像               castFilter图像            normalizeFilter图像          rescaleFilter图像            shiftFilter图像

实例2 MHA格式文件进行三维线性映射

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
//线性映射头文件
#include "itkCastImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkNormalizeImageFilter.h"

int main( int argc, char * argv[] )
{
 /* if( argc < 2 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "   inputImageFile " << std::endl;
    return EXIT_FAILURE;
    }*/
//我们定义输入和输出图像的像素类型
  typedef   float    InputPixelType;
  //typedef   float            OutputPixelType;
  typedef  unsigned char  OutputPixelType;
  //然后,定义输入和输出图像类型
  typedef itk::Image< InputPixelType,  3 >   InputImageType;
  typedef itk::Image< OutputPixelType, 3 >   OutputImageType;
 
  typedef itk::ImageFileReader< InputImageType >  ReaderType;//读文件类型
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;//写文件类型

  //使用定义的图像类型来对滤波器进行实例化
  typedef itk::RescaleIntensityImageFilter<
               InputImageType, OutputImageType >  RescaleFilterType;

  ReaderType::Pointer reader = ReaderType::New();//实例化对象reader
  WriterType::Pointer writer = WriterType::New();//实例化对象writer
 
  //通过调用 New( ) 操作来创建对象滤波器并将结果指向 itk::SmartPointers 
  RescaleFilterType::Pointer    rescaleFilter    = RescaleFilterType::New();

  reader->SetFileName( "CT_215.mha" );
  //现在将一个 reader 滤波器 ( 这里并未展示它的创建 ) 的输出作为输入连接到投射滤波器(四种)
  rescaleFilter->SetInput( reader->GetOutput() );//rescaleFilter滤波器
  /*接下来我们设置每个滤波器需要的参数。 CastImageFilter 和 NormalizeImageFilter 不需要
      任何参数。另一方面, RescaleIntensityImageFilter 需要用户提供想得到的输出图像像素值的
      最大最小值,这可以通过使用 SetOutputMinimum() 和 SetOutputMaximum() 方式来实现,如
      下所示*/
  rescaleFilter->SetOutputMinimum(  0 );
  rescaleFilter->SetOutputMaximum( 255 );
  
  writer->SetInput(rescaleFilter->GetOutput());//rescaleFilter滤波器
  //最后,通过调用 Update() 方式来运行这些滤波器
  //写文件,输出线性映射四种滤波效果
  writer->SetFileName("CT_215-RescaleIntensity0_255.mha");

  writer->Update();

  return EXIT_SUCCESS;
}

基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第6张图片

                                                        输入215张CT股骨图像数据(像素范围为-3024~+3071)(CT_215.mha)

基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第7张图片

                输出215张通过线性映射的CT股骨图像数据(像素范围为0~+255)(CT_215-RescaleIntensity0_255.mha)

2 非线性映射

接下来的滤波器可以被看成是投射滤波器的一个变量。它的主要特性是使用一个平滑、连续的非线性形式的变换函数

itk::SigmoidImageFilter 通常作为一个亮度变换使用。它通过在亮度值的一个特定范围的边界的一个非常平滑连续的转变将这个范围映射到一个新的亮度范围,是广泛使用 Sigmoids来作为关注值的一个设置并逐渐削弱范围之外的值的一个机制。为了扩展 Sigmoids 滤波器的机动性,使用四个参数通过选择它的输入输出亮度范围来调节它在 ITK 中的执行。接下来的方程表达了 Sigmoids 亮度变换:

                                                              基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第8张图片

在上面的方程中, I 是输入像素的亮度I′ 是输出像素的亮度Min 、 Max 是输出图像的最小值和最大值α 定义了输入亮度范围的宽度(可以理解为定义了函数形状β 定义了围绕在范围中心的亮度(可以理解为定义了函数具体位置。如图 所示阐述了每个参数的意义。1

               基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第9张图片

                   SigmoidImageFilter 使用不同参数的效果(参数 α 定义了窗口像素的宽度;参数 β 定义了窗口像素的亮度

实例3 PNG图像进行二维非线性映射

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
//非线性映射滤波器头文件
#include "itkSigmoidImageFilter.h"

int main( int argc, char * argv[] )
{
  /*if( argc < 7 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile   outputImageFile";
    std::cerr << " OutputMin OutputMax SigmoidAlpha SigmoidBeta" << std::endl;
    return EXIT_FAILURE;
    }*/
//然后必须定义这个滤波器的输入、输出像素和图像类型
  typedef   unsigned char  InputPixelType;
  typedef   unsigned char  OutputPixelType;

  typedef itk::Image< InputPixelType,  2 >   InputImageType;
  typedef itk::Image< OutputPixelType, 2 >   OutputImageType;
  
  typedef itk::ImageFileReader< InputImageType  >  ReaderType;
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();
  //输入图像
  reader->SetFileName( "BrainProtonDensitySlice.png" );
  //输出图像
  writer->SetFileName( "Sigmoid_out.png" );
  //我们使用图像类型来实例化滤波器类型并创建滤波器对象
  typedef itk::SigmoidImageFilter<
               InputImageType, OutputImageType >  SigmoidFilterType;
  SigmoidFilterType::Pointer sigmoidFilter = SigmoidFilterType::New();
  //输出像素中的最小值和最大值分别使用 SetOutputMinimum( ) 和 SetOutputMaximum( ) 方式来定义
  const OutputPixelType outputMinimum = atoi( "10" );
  const OutputPixelType outputMaximum = atoi( "240" );

  sigmoidFilter->SetOutputMinimum(   outputMinimum  );
  sigmoidFilter->SetOutputMaximum(   outputMaximum  );
  
  const double  alpha = atof( "10" );
  const double  beta  = atof( "170" );
  /*使用 SetAlpha() 和 SetBeta() 来设置系数 α 和 β 。注意 α 是和输入亮度窗口成比例的。按
      照惯例我们可以说这个窗口是间距[-3α , 3α] 。亮度窗口的边界并不明显。如图所示, α
      平稳地接近它的极值。当你想通过在围绕人口均值周围定义一个间距[-3σ , 3σ] 来设置一个
      人口测量的范围时,你可以以同样的形式来进行考虑*/
  sigmoidFilter->SetAlpha(  alpha  );
  sigmoidFilter->SetBeta(   beta   );
  /*可以从其他滤波器得到 SigmoidImageFilter 的输入,例如一个图像文件 reader 。输出可
      以像一个图像文件 writer 一样传递给其他滤波器流水线。任何下游的滤波器调用 update 都可
      以触发 Sigmoids 滤波器的运行*/

  sigmoidFilter->SetInput( reader->GetOutput() );
  writer->SetInput( sigmoidFilter->GetOutput() );
  writer->Update();
  
  return EXIT_SUCCESS;
}

脑部组织结构图像进行分割时可参考的参数:

                                         基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第10张图片

白质部分:取 最小值 =10、 最大值 =240、α = 10、β = 170

脑室部分:取 最小值 =0、 最大值 =255、α = 6.67(20/3)、β = 230

灰质部分:取 最小值 =0、 最大值 =255、α = 5(15/3)、β =195

基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第11张图片      基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第12张图片        基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第13张图片      基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第14张图片

               输入图像                       白质Sigmoid输出图像              脑室Sigmoid输出图像          灰质Sigmoid输出图像

从图片中我们可以看到,白质部分的亮度扩展到它们的动态范围【β - 3α,β+3α 】),而亮度值在 β - 3α 之下和在 β+3α 之上的值分别映射到输出值的最小值和最大值(即白质部分在在本例中像素范围为【140,200】)。这是一个 Sigmoids 用来执行平滑亮度窗口时使用的方式。
注意: α 和 β 都是可正可负的一个负的 α 将对图像有相反的效果。这可以在上图中左边的图像中看到。在现实中 Sigmoids 曲线是很常见的。它们表达了图对一个刺激的灵敏性。它们也是高斯积分曲线,因此自然地可以作为高斯分布信号的一个响应。

注:非线性映射算法只能实现像素值(0-255)范围的映射

实例4 MHA格式文件进行三维非线性映射

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
//非线性映射滤波器头文件
#include "itkSigmoidImageFilter.h"
//注:非线性映射算法只能实现像素值(0-255)范围的输入输出映射。
int main( int argc, char * argv[] )
{
  /*if( argc < 7 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile   outputImageFile";
    std::cerr << " OutputMin OutputMax SigmoidAlpha SigmoidBeta" << std::endl;
    return EXIT_FAILURE;
    }*/
//然后必须定义这个滤波器的输入、输出像素和图像类型
  typedef   unsigned char  InputPixelType;
  typedef   unsigned char  OutputPixelType;

  typedef itk::Image< InputPixelType,  3 >   InputImageType;
  typedef itk::Image< OutputPixelType, 3 >   OutputImageType;
  
  typedef itk::ImageFileReader< InputImageType  >  ReaderType;
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();
  //输入图像
  reader->SetFileName( "CT_215-RescaleIntensity0_255.mha" );
  //输出图像
  writer->SetFileName( "CT_215_Sigmoid_out.mha" );
  //我们使用图像类型来实例化滤波器类型并创建滤波器对象
  typedef itk::SigmoidImageFilter<
               InputImageType, OutputImageType >  SigmoidFilterType;
  SigmoidFilterType::Pointer sigmoidFilter = SigmoidFilterType::New();
  //输出像素中的最小值和最大值分别使用 SetOutputMinimum( ) 和 SetOutputMaximum( ) 方式来定义
  const OutputPixelType outputMinimum = atoi( "10" );
  const OutputPixelType outputMaximum = atoi( "240" );

  sigmoidFilter->SetOutputMinimum(   outputMinimum  );
  sigmoidFilter->SetOutputMaximum(   outputMaximum  );
  
  const double  alpha = atof( "8" );//宽度
  const double  beta  = atof( "155.5" );//位置
  /*使用 SetAlpha() 和 SetBeta() 来设置系数 α 和 β 。注意 α 是和输入亮度窗口成比例的。按
      照惯例我们可以说这个窗口是间距[-3α , 3α] 。亮度窗口的边界并不明显。如图所示, α
      平稳地接近它的极值。当你想通过在围绕人口均值周围定义一个间距[-3σ , 3σ] 来设置一个
      人口测量的范围时,你可以以同样的形式来进行考虑*/
  sigmoidFilter->SetAlpha(  alpha  );
  sigmoidFilter->SetBeta(   beta   );
  /*可以从其他滤波器得到 SigmoidImageFilter 的输入,例如一个图像文件 reader 。输出可
      以像一个图像文件 writer 一样传递给其他滤波器流水线。任何下游的滤波器调用 update 都可
      以触发 Sigmoids 滤波器的运行*/

  sigmoidFilter->SetInput( reader->GetOutput() );
  writer->SetInput( sigmoidFilter->GetOutput() );
  writer->Update();
  
  return EXIT_SUCCESS;
}

基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第15张图片                 基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第16张图片

    输入数据(CT_215-RescaleIntensity0_255.mha)                  三维非线性映射输出数据(CT_215_Sigmoid_out.mha)

3 梯度

梯度在一些背景下表示梯度向量而在其他情况下可以表示梯度向量的大小。 ITK 滤波器在涉及这个概念时通过强度这个概念来区别该不明确概念。 ITK 提供可以计算图像梯度向量图像强度大小的滤波器。

方向导数:一个函数沿指定方向的变化率。

梯度:方向导数变化最大的方向。

实例5 PNG图像进行不带滤波的二维梯度强度提取

图像梯度的强度广泛地应用在图像分析中,主要用来帮助检测对象轮廓和分离均匀区域itk::GradientMagnitudeImageFilter 使用一个简单的有限差分方式来计算图像中每个像素位置的梯度强度。例如:在二维情况下计算等同于将图像使用模块类型,如下所示:然后计算它们的平方和并计算和的平方根。

                                                                             基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第17张图片

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkGradientMagnitudeImageFilter.h"//梯度强度头文件

int main( int argc, char * argv[] )
{
 /* if( argc < 3 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile  outputImageFile " << std::endl;
    return EXIT_FAILURE;
    }*/
  //选择输入和输出图像的像素类型:
  typedef    float    InputPixelType;
  typedef    float    OutputPixelType;
  //使用像素类型可以定义输入、输出图像类型
  typedef itk::Image< InputPixelType,  2 >   InputImageType;
  typedef itk::Image< OutputPixelType, 2 >   OutputImageType;

  typedef itk::ImageFileReader< InputImageType >  ReaderType;
  //通过定义输入输出图像类型来定义梯度强度的类型:
  typedef itk::GradientMagnitudeImageFilter<
               InputImageType, OutputImageType >  FilterType;
  //通过调用 New( ) 方式来创建一个滤波器对象并将结果指向一个 itk::SmartPointer :
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName("BrainProtonDensitySlice.png");

  FilterType::Pointer filter = FilterType::New();
  //输入图像可以从另一个滤波器的输出得到。这里,源于一个图像 reader 来得到:
  filter->SetInput( reader->GetOutput() );
  //最后,通过调用 Update( ) 方式来执行滤波器:
  filter->Update();
  

  typedef unsigned char                          WritePixelType;
  typedef itk::Image< WritePixelType, 2 >        WriteImageType;
  typedef itk::RescaleIntensityImageFilter<
               OutputImageType, WriteImageType > RescaleFilterType;

  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

  rescaler->SetOutputMinimum(   0 );
  rescaler->SetOutputMaximum( 255 );

  typedef itk::ImageFileWriter< WriteImageType >  WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName("GradientMagnitude_out.png");
  //如果这个滤波器的输出已经连接到流水线中的其他滤波器,更新任何下游的滤波器将同
  //样触发这个滤波器的一个更新。例如,梯度强度滤波器可能连接到一个图像 writer 
  rescaler->SetInput( filter->GetOutput() );
  writer->SetInput( rescaler->GetOutput() );
  writer->Update();
 
  return EXIT_SUCCESS;
}

                                             基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第18张图片                              基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第19张图片

                                                           输入图像                                                       梯度强度图

上图阐述了梯度强度滤波器对一个 MRI 脑部图像切片作用的效果。这个图片展示了这个滤波器对噪声数据的灵敏性(即对噪声灵敏)。由于梯度强度图像的动态范围往往比输入图像的动态范围要小,所以必须注意选择用来表达输出图像的图像类型。通常,这个规则会产生异常,例如,合成图像包含高对比对象。这个滤波器在计算梯度前不会对图像进行任何滤波。因此这个结果对噪声非常敏感,而且并不一定是尺度空间分析的最佳选择。

实例6 PNG图像进行带滤波的二维梯度强度提取

微分是对一个数字数据的不规则操作。实际中可以方便地定义一个执行微分的比例。在执行这样的滤波时使用一个高斯核被认为是最便捷的选择。通过选择一个特定的高斯标准差(σ)就可以选择一个相应的比例来去除通常被认为是噪声的高频部分
itk::GradientMagnitudeRecursiveGaussianImageFilter 计算在每个像素的图像梯度。这个计算过程等同于首先通过将图像和一个高斯核卷积来平滑图像,然后应用一个差分操作。 s 的值是由用户选择的。这些是通过使用一个 IIR ( Infinite Impulse Response 无限脉冲响应)和高斯核的派生卷积来实现的。传统的卷积将产生一个更精确的结果,但是 IIR 方式更加迅速,尤其是使用大的 σ 值。GradientMagnitudeRecursiveGaussianImageFilter 通过使用高斯核和它的导函数的自然分离来对任何维的图像进行操作。

如下图所示阐述了这个滤波器对一个 MRI 脑部图像切片作用的效果,使用的 σ 值分别为 1 ( 左图)、 3 (中图)、 5 (右图)滤波器对一个 MRI 脑部图像切片作用的效果。

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h"//带滤波梯度强度的头文件

int main( int argc, char * argv[] )
{
  /*if( argc < 4 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile   outputImageFile   sigma" << std::endl;
    return EXIT_FAILURE;
    }*/
  //类型必须基于输入和输出图像的像素进行实例化
  typedef    float    InputPixelType;
  typedef    float    OutputPixelType;
  //使用它们就可以对输入、输出图像进行实例化
  typedef itk::Image< InputPixelType,  2 >   InputImageType;
  typedef itk::Image< OutputPixelType, 2 >   OutputImageType;
  //现在同时使用输入和输出图像类型来实例化滤波器类型
  typedef itk::ImageFileReader< InputImageType >  ReaderType;
  typedef itk::GradientMagnitudeRecursiveGaussianImageFilter<
                        InputImageType, OutputImageType >  FilterType;
  //通过调用 New( ) 方式来创建一个滤波器对象并将结果指向一个 itk::SmartPointer
  ReaderType::Pointer reader = ReaderType::New();
  //输入图像
  reader->SetFileName("BrainProtonDensitySlice.png");

  FilterType::Pointer filter = FilterType::New();
  //输入图像可以从另一个滤波器的输出得到。这里,源自于一个图像 reader 来得到
  filter->SetInput( reader->GetOutput() );
  //对高斯滤波核的标准差进行赋值
  const double sigma = atof("1");
  //现在设置高斯滤波核的标准差
  filter->SetSigma( sigma );
  //最后,通过调用 Update( ) 方式来执行滤波器
  filter->Update();
  
  typedef unsigned char                   WritePixelType;
  typedef itk::Image< WritePixelType, 2 > WriteImageType;

  typedef itk::RescaleIntensityImageFilter<
                   OutputImageType, WriteImageType > RescaleFilterType;

  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

  rescaler->SetOutputMinimum(   0 );
  rescaler->SetOutputMaximum( 255 );

  typedef itk::ImageFileWriter< WriteImageType >  WriterType;

  WriterType::Pointer writer = WriterType::New();
  //输出强度图像
  writer->SetFileName("GradientMagnitude_RG_1.png");
  /*如果这个滤波器的输出已经连接到流水线中的其他滤波器,更新任何下游的滤波器将同
      样触发这个滤波器的一个更新。例如,梯度强度滤波器可能连接到一个图像 writer*/
  rescaler->SetInput( filter->GetOutput() );
  writer->SetInput( rescaler->GetOutput() );
  writer->Update();

  return EXIT_SUCCESS;
}

     基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第20张图片          基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第21张图片         基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第22张图片         基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第23张图片     

                  输入图像                              梯度强度图(σ=1)                  梯度强度图(σ=3)                  梯度强度图(σ=5)

由于梯度强度图像的动态范围往往比输入图像的动态范围要小,所以必须注意选择用来表达输出图像的图像类型。

实例7 MHA格式文件进行带滤波三维的梯度强度提取

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h"//带滤波梯度强度的头文件

int main( int argc, char * argv[] )
{
  /*if( argc < 4 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile   outputImageFile   sigma" << std::endl;
    return EXIT_FAILURE;
    }*/
  //类型必须基于输入和输出图像的像素进行实例化
  typedef    float    InputPixelType;
  typedef    float    OutputPixelType;
  //使用它们就可以对输入、输出图像进行实例化
  typedef itk::Image< InputPixelType,  3 >   InputImageType;
  typedef itk::Image< OutputPixelType, 3 >   OutputImageType;
  //现在同时使用输入和输出图像类型来实例化滤波器类型
  typedef itk::ImageFileReader< InputImageType >  ReaderType;
  typedef itk::GradientMagnitudeRecursiveGaussianImageFilter<
                        InputImageType, OutputImageType >  FilterType;
  //通过调用 New( ) 方式来创建一个滤波器对象并将结果指向一个 itk::SmartPointer
  ReaderType::Pointer reader = ReaderType::New();
  //输入图像cuiti_256.mha
  reader->SetFileName("cuiti_4.mha");//

  FilterType::Pointer filter = FilterType::New();
  //输入图像可以从另一个滤波器的输出得到。这里,源自于一个图像 reader 来得到
  filter->SetInput( reader->GetOutput() );
  //对高斯滤波核的标准差进行赋值
  const double sigma = atof("1");
  //现在设置高斯滤波核的标准差
  filter->SetSigma(sigma);
  //最后,通过调用 Update( ) 方式来执行滤波器
  filter->Update();
  
  typedef unsigned char                   WritePixelType;
  typedef itk::Image< WritePixelType, 3 > WriteImageType;

  typedef itk::RescaleIntensityImageFilter<
                   OutputImageType, WriteImageType > RescaleFilterType;

  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

  rescaler->SetOutputMinimum(   0 );
  rescaler->SetOutputMaximum( 255 );

  typedef itk::ImageFileWriter< WriteImageType >  WriterType;

  WriterType::Pointer writer = WriterType::New();
  //输出强度图像
  writer->SetFileName("GradientMagnitude_4.mha");
  /*如果这个滤波器的输出已经连接到流水线中的其他滤波器,更新任何下游的滤波器将同
      样触发这个滤波器的一个更新。例如,梯度强度滤波器可能连接到一个图像 writer*/
  rescaler->SetInput( filter->GetOutput() );
  writer->SetInput( rescaler->GetOutput() );
  writer->Update();

  return EXIT_SUCCESS;
}

输入三维图像(cuiti_4.mha):

   基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第24张图片   基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第25张图片   基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第26张图片  基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第27张图片

               切片1                            切片2                             切片3                          切片4

输出三维梯度强度图像(GradientMagnitude_4.mha):

  基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第28张图片    基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第29张图片     基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第30张图片  基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第31张图片

            切片1                                切片2                                  切片3                        切片4

实例8 PNG图像进行不带滤波的二维导函数提取

使用 itk::DerivativeImageFilter 来计算一幅图像的偏微分——图像沿一个特定的坐标轴方向上的微分。

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

#include "itkDerivativeImageFilter.h"//不带滤波导函数头文件

int main( int argc, char * argv[] )
{
  //if( argc < 6 )
  //  {
  //  std::cerr << "Usage: " << std::endl;
  //  std::cerr << argv[0] << "  inputImageFile   outputImageFile  normalizedOutputImageFile ";
  //  std::cerr << " derivativeOrder direction" << std::endl;
  //  return EXIT_FAILURE;
  //  }
    /*接下来,必须定义输入、输出图像的像素类型,并使用它们实例化图像类型。注意:由
        于导数值是可正可负的,所以选择的图像应具有符号类型是很重要的*/
  typedef   float  InputPixelType;
  typedef   float  OutputPixelType;

  const unsigned int Dimension = 2;

  typedef itk::Image< InputPixelType,  Dimension >   InputImageType;
  typedef itk::Image< OutputPixelType, Dimension >   OutputImageType;

  typedef itk::ImageFileReader< InputImageType  >  ReaderType;
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;
  //现在就可以使用图像类型来定义滤波器类型并创建滤波器对象
  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();
  //输入图像
  reader->SetFileName("BrainProtonDensitySlice.png");
  保存输出某方向(本例由于为二维图,所以为x轴或y轴)导数图像
  //writer->SetFileName("BrainProtonDensitySlice_Derivative.png");

  typedef itk::DerivativeImageFilter<
               InputImageType, OutputImageType >  FilterType;

  FilterType::Pointer filter = FilterType::New();
  //使用 SetOrder( ) 方式来选择微分的阶数。使用 SetDirection( ) 方式来选择计算微分的坐标方向
  filter->SetOrder(atoi("1"));//选择一阶微分
  filter->SetDirection( atoi("0") );//选择X方向
  /*可以从任何其他滤波器得到这个滤波器的输入,例如一个 reader 。输出可以像一个 writer
      一样传递给其他滤波器流水线。任何下游的滤波器调用 update 都可以触发微分滤波器的运
      行*/
  filter->SetInput( reader->GetOutput() );
  /*writer->SetInput( filter->GetOutput() );*/
  /*writer->Update();*/
  
  typedef itk::Image< unsigned char, Dimension >  WriteImageType;

  typedef itk::RescaleIntensityImageFilter<
                                  OutputImageType,
                                  WriteImageType >    NormalizeFilterType;

  typedef itk::ImageFileWriter< WriteImageType >       NormalizedWriterType;

  NormalizeFilterType::Pointer normalizer = NormalizeFilterType::New();
  NormalizedWriterType::Pointer normalizedWriter = NormalizedWriterType::New();

  normalizer->SetInput( filter->GetOutput() );
  normalizedWriter->SetInput( normalizer->GetOutput() );

  normalizer->SetOutputMinimum(   0 );
  normalizer->SetOutputMaximum( 255 );
  //导数图像(含有负数)进行(0-255)线性标准化后图像
  normalizedWriter->SetFileName("Derivative_normalizer_x_1.png");
  normalizedWriter->Update();

  return EXIT_SUCCESS;
}

下图阐述了 DerivativeImageFilter 对一个 MRI 脑部图像作用的效果。微分是沿 着 x 轴和y轴方向来计算的。从这个结果可以看出对图像中的噪声的敏感度是很明显的。

基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第32张图片         基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第33张图片           基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第34张图片        基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第35张图片

              输入图像                           X方向一阶微分图                       X方向二阶微分图                       X方向三阶微分图

基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第36张图片          基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第37张图片           基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第38张图片        基于C++的ITK图像分割与配准学习笔记2(图像滤波)_第39张图片

               输入图像                             Y方向一阶微分图                       Y方向二阶微分图                     Y方向三阶微分图

 

 

你可能感兴趣的:(医学图像分割,ITK,图像分割,ITK图像分割,周振华,图像滤波,医学图像分割与配准,图像处理)