ITK 实例3 OTSU算法对PNG图像进行单阈值二维分割

发布时间 2023-08-16 14:51:51作者: 一杯清酒邀明月
 1 #include "itkOtsuThresholdImageFilter.h"//Otsu分割头文件
 2 #include "itkImage.h"
 3 #include "itkImageFileReader.h"
 4 #include "itkImageFileWriter.h"
 5  
 6 int main( int argc, char * argv[] )
 7 {
 8   /*if( argc < 5 )
 9     {
10     std::cerr << "Usage: " << argv[0];
11     std::cerr << " inputImageFile outputImageFile ";
12     std::cerr << " insideValue    outsideValue   "  << std::endl;
13     return EXIT_FAILURE;
14     }*/
15  
16   //确定作为输入和输出图像的像素类型
17   typedef  unsigned char  InputPixelType;
18   typedef  unsigned char  OutputPixelType;
19   const unsigned int      Dimension = 2;
20  //使用输入输出图像的像素类型和维来定义它们的图像类型
21   typedef itk::Image< InputPixelType,  Dimension >   InputImageType;
22   typedef itk::Image< OutputPixelType, Dimension >   OutputImageType;
23   //使用上面定义的输入输出图像的类型对滤波器类型进行实例化
24   typedef itk::OtsuThresholdImageFilter<InputImageType, OutputImageType >  FilterType;
25   //对一个 itk::ImageFileReader 类也进行实例化以便从文件中读取图像数据
26   typedef itk::ImageFileReader< InputImageType >  ReaderType;
27   
28   typedef itk::ImageFileWriter< OutputImageType >  WriterType;
29   //调用 New( ) 方式创建滤波器和 reader 并将结果指向 itk::Smartpointers 
30   ReaderType::Pointer reader = ReaderType::New();
31   FilterType::Pointer filter = FilterType::New();
32   WriterType::Pointer writer = WriterType::New();
33  
34   //由 reader 得到的图像作为输入传递给 OtsuThresholdImageFilter
35   reader->SetFileName("BrainProtonDensitySlice.png");
36   filter->SetInput(reader->GetOutput());
37   writer->SetInput( filter->GetOutput() );
38  
39   //outsideValue:给定阈值的上下限范围之外的像素的亮度值
40   //insideValue:给定阈值的上下限范围之内的像素的亮度值
41   const OutputPixelType outsideValue = atoi( "0" );//范围之外设置为纯黑
42   const OutputPixelType insideValue  = atoi( "255" );//范围之内设置为纯白
43  
44   /*用 SetOutsideValue() 方式定义指向那些亮度值在给定阈值的上下限范围之外的像素的
45   亮度值,用 SetInsideValue() 方式定义指向那些亮度值在给定阈值的上下限范围之内的像素的
46   亮度值*/
47   filter->SetOutsideValue( outsideValue );
48   filter->SetInsideValue(  insideValue  );
49   
50   try
51     {
52     filter->Update();
53     }
54   catch( itk::ExceptionObject & excp )
55     {
56     std::cerr << "Exception thrown " << excp << std::endl;
57     }
58   
59   //由滤波器内部计算得到的阈值。为了做到这些我们调用 GetThreshold 方式
60   int threshold = filter->GetThreshold();
61   std::cout << "Threshold = " << threshold << std::endl;
62   
63   writer->SetFileName( "BrainProtonDensitySlice_OTSU2.png" );
64   try
65     {
66     writer->Update();
67     }
68   catch( itk::ExceptionObject & excp )
69     {
70     std::cerr << "Exception thrown " << excp << std::endl;
71     }
72  
73   return EXIT_SUCCESS;
74 }

得到分割阈值为98:

  另外一个对像素进行分类的方法就是把错分类率降到最小。这样就要 寻找一个阈值, 这个阈值将图像分为两部分,并且使得其中一部分落在另一部分那侧的直方图降到最小。这等同于 将类中的差异最小化或者说 将类之间的差异最大化。
  这个图展示了这种滤波器在进行分割时的自身局限性,这些局限性在处理含噪声的图像和由于领域偏见而缺乏空间均匀性的MRI图像时表现得尤为突出。