ITK 最大圆度连通域提取

发布时间 2023-07-13 14:29:33作者: 一杯清酒邀明月

最大圆度概念:
圆度计算(Circularity,Roundness)

1 Roundness = (4 * CV_PI * Area) / (Perimeter * Perimeter )
2 double getRoundness(std::vector<cv::Point> contour)
3 {
4     double factor = (cv::contourArea(contour) * 4 * CV_PI) / (pow(cv::arcLength(contour, true), 2));
5     return factor;
6 }

1、代码

1.1 code

  1 #include "itkImage.h"
  2 #include <vtkSmartPointer.h>
  3 #include <vtkPNGWriter.h>
  4 #include "itkScalarConnectedComponentImageFilter.h"
  5 #include <itkImageToVTKImageFilter.h> 
  6 #include <itkVTKImageToImageFilter.h>
  7 #include <string>
  8 #include <iostream>
  9 #include<vtkImageShiftScale.h>
 10 #include <itkImageRegionIteratorWithIndex.h>
 11 #include <itkStatisticsLabelObject.h>
 12 #include <itkBinaryImageToShapeLabelMapFilter.h>
 13 #include <itkBinaryImageToStatisticsLabelMapFilter.h>
 14 #include <itkLabelMapToBinaryImageFilter.h>
 15 #include <itkImageFileReader.h>
 16 #include <itkImageFileWriter.h>
 17 #include <itkMetaImageIO.h>
 18 
 19 using namespace std;
 20 void CreateImage(itk::Image<unsigned char, 2>* const image)
 21 {
 22     // Create an image with 2 connected components
 23     itk::Image<unsigned char, 2>::IndexType start = { {0,0} };
 24     start[0] = 0;
 25     start[1] = 0;
 26  
 27     itk::Image<unsigned char, 2>::SizeType size;
 28     unsigned int NumRows = 100;
 29     unsigned int NumCols = 200;
 30     size[0] = NumRows;
 31     size[1] = NumCols;
 32  
 33     typename itk::Image<unsigned char, 2>::RegionType region(start, size);
 34  
 35     image->SetRegions(region);
 36     
 37     image->Allocate(true);// 全0的像素(黑色)
 38  
 39     // Make a square
 40     for (itk::Image<unsigned char, 2>::IndexValueType r = 5; r < 40; r++)
 41     {
 42         for (itk::Image<unsigned char, 2>::IndexValueType c = 10; c < 50; c++)
 43         {
 44             itk::Image<unsigned char, 2>::IndexType pixelIndex = { {r,c} };
 45  
 46             image->SetPixel(pixelIndex, 100);//灰色
 47         }
 48     }
 49  
 50     // Make another square
 51     for (typename itk::Image<unsigned char, 2>::IndexValueType r = 50; r < 70; r++)
 52     {
 53         for (typename itk::Image<unsigned char, 2>::IndexValueType c = 50; c < 80; c++)
 54         {
 55             typename itk::Image<unsigned char, 2>::IndexType pixelIndex = { {r,c} };
 56  
 57             image->SetPixel(pixelIndex, 255);//白色
 58         }
 59     }
 60  
 61 }
 62 void print(const std::string& file, itk::Image<unsigned char, 2>* image)
 63 {
 64     ofstream fout(file);
 65     auto size = image->GetBufferedRegion().GetSize();
 66     for (auto i = 0; i < size[0]; i++)
 67     {
 68         for (auto j = 0; j < size[1]; j++)
 69         {
 70             itk::Image<unsigned char, 2>::IndexType index{ {i,j} };
 71             auto c = image->GetPixel(index);
 72             fout << (int)c;
 73         }
 74         fout << std::endl;
 75     }
 76 }
 77 
 78 using ImageType = itk::Image<unsigned char, 2>;
 79 
 80 ImageType::Pointer CreateMaskImage()
 81 {
 82     ImageType::Pointer image = ImageType::New();
 83     ImageType::IndexType start;
 84     start.Fill(0);
 85 
 86     ImageType::SizeType size;
 87     size.Fill(128);
 88 
 89     ImageType::RegionType region;
 90     region.SetSize(size);
 91     region.SetIndex(start);
 92 
 93     image->SetRegions(region);
 94     image->Allocate();
 95 
 96     using IteratorType = itk::ImageRegionIteratorWithIndex< ImageType >;
 97     IteratorType it(image, image->GetRequestedRegion());
 98 
 99     for (it.GoToBegin(); !it.IsAtEnd(); ++it)
100     {
101         ImageType::IndexType idx = it.GetIndex();
102 
103         // 创建空心圆 C=(50,50),R=15,r=5
104         if ((idx[0] - 50) * (idx[0] - 50) + (idx[1] - 50) * (idx[1] - 50) < 225 &&
105             (idx[0] - 50) * (idx[0] - 50) + (idx[1] - 50) * (idx[1] - 50) > 25)
106             it.Set(1);
107 
108         // 创建圆 C=(70,80),r=7
109         else if ((idx[0] - 70) * (idx[0] - 70) + (idx[1] - 80) * (idx[1] - 80) < 49)
110             it.Set(1);
111 
112         // 创建矩形 C=(100,100),W(120,110)
113         else if (idx[0] >= 100 && idx[0] <= 120 &&
114             idx[1] >= 100 && idx[1] <= 110)
115             it.Set(1);
116 
117         else
118             it.Set(0);
119     }
120 
121     return image;
122 }
123 
124 int main(int argc, char *argv[])
125 {
126     // 1、创建二值图像
127     ImageType::Pointer image = CreateMaskImage();// 
128 
129     //将itk图片转换成vtk图片
130     auto imageToVtkImage = itk::ImageToVTKImageFilter<itk::Image<unsigned char, 2>>::New();
131     imageToVtkImage->SetInput(image.GetPointer());
132     imageToVtkImage->Update();// 只有更新之后,后续使用者才可以拿到真正的数据
133 
134     //保存vtk图片为png文件
135     vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
136     writer->SetFileName("D:/documents/vs2019/itk_tutorial/connectcompent/build/RelWithDebInfo/1CreateImage.png");
137     writer->SetInputData(imageToVtkImage->GetOutput());
138     writer->Write();
139     //保存vtk图片像素值到文本文件
140     print("D:/documents/vs2019/itk_tutorial/connectcompent/build/RelWithDebInfo/1CreateImage.txt", image.GetPointer());
141 
142     // 2、过滤连通区域
143     typedef unsigned long LabelType;
144     typedef itk::ShapeLabelObject< LabelType, 2 >    LabelObjectType;
145     typedef itk::LabelMap< LabelObjectType >    LabelMapType;
146     typedef itk::BinaryImageToShapeLabelMapFilter< ImageType, LabelMapType >    I2LType;
147     I2LType::Pointer i2l = I2LType::New();
148     i2l->SetInput(image);
149     i2l->SetFullyConnected(false);
150     i2l->SetInputForegroundValue(1);
151     i2l->SetOutputBackgroundValue(0);
152     i2l->Update();
153 
154     LabelMapType::Pointer labelMap = i2l->GetOutput();
155     for (unsigned int label = 1; label <= labelMap->GetNumberOfLabelObjects(); label++)
156     {
157         const LabelObjectType* labelObject = labelMap->GetLabelObject(label);
158         labelObject->Print(std::cout);
159         std::cout << "----------------------------------------" << std::endl;
160     }
161 
162     std::vector< LabelObjectType::Pointer > filtered_label_objects;
163     for (LabelMapType::Iterator it(labelMap); !it.IsAtEnd(); ++it)
164     {
165         // 过滤条件
166         if (it.GetLabelObject()->GetRoundness() < 0.95)
167             filtered_label_objects.push_back(it.GetLabelObject());
168     }
169 
170     for (int i = 0; i < filtered_label_objects.size(); i++)
171     {
172         labelMap->RemoveLabelObject(filtered_label_objects[i]);
173     }
174 
175     typedef itk::LabelMapToBinaryImageFilter< LabelMapType, ImageType> L2IType;
176     L2IType::Pointer l2i = L2IType::New();
177     l2i->SetInput(labelMap);
178     l2i->Update();
179 
180     using WriterType = itk::ImageFileWriter<ImageType>;
181     WriterType::Pointer writer1 = WriterType::New();
182     writer1->SetFileName("mask.mha");
183     writer1->SetInput(l2i->GetOutput());
184     writer1->SetImageIO(itk::MetaImageIO::New());
185     writer1->Update();
186  
187     return EXIT_SUCCESS;
188 }

1.2、生成的mask图片

因为是二值图,像素值只有0和1,直接查看颜色是黑色的,导入slicer中查看。
直接查看:

 slicer中查看:

 最终保留的圆度最大文件mask.mha,使用slicer打开:

1.3、打印信息

 1 ShapeLabelObject (0000022C062D43F0)
 2   RTTI typeinfo:   class itk::ShapeLabelObject<unsigned long,2>
 3   Reference Count: 1
 4   LineContainer: 0000022C062D4400
 5   Label: 1
 6   NumberOfPixels: 616
 7   PhysicalSize: 616
 8   Perimeter: 127.254
 9   NumberOfPixelsOnBorder: 0
10   PerimeterOnBorder: 0
11   PerimeterOnBorderRatio: 0
12   Elongation: 1
13   Flatness: 1
14   Roundness: 0.691393
15   Centroid: [50, 50]
16   BoundingBox:   ImageRegion (0000022C062D4430)
17     Dimension: 2
18     Index: [36, 36]
19     Size: [29, 29]
20   EquivalentSphericalRadius: 14.0028
21   EquivalentSphericalPerimeter: 87.9823
22   EquivalentEllipsoidDiameter: [28.0056, 28.0056]
23   PrincipalMoments: [61.9156, 61.9156]
24   PrincipalAxes:
25 1 0
26 0 1
27   FeretDiameter: 0
28   m_OrientedBoundingBoxSize: [0, 0]
29   m_OrientedBoundingBoxOrigin: [0, 0]
30 ----------------------------------------
31 ShapeLabelObject (0000022C062D3630)
32   RTTI typeinfo:   class itk::ShapeLabelObject<unsigned long,2>
33   Reference Count: 1
34   LineContainer: 0000022C062D3640
35   Label: 2
36   NumberOfPixels: 145
37   PhysicalSize: 145
38   Perimeter: 41.524
39   NumberOfPixelsOnBorder: 0
40   PerimeterOnBorder: 0
41   PerimeterOnBorderRatio: 0
42   Elongation: 1
43   Flatness: 1
44   Roundness: 1.02799
45   Centroid: [70, 80]
46   BoundingBox:   ImageRegion (0000022C062D3670)
47     Dimension: 2
48     Index: [64, 74]
49     Size: [13, 13]
50   EquivalentSphericalRadius: 6.79374
51   EquivalentSphericalPerimeter: 42.6863
52   EquivalentEllipsoidDiameter: [13.5875, 13.5875]
53   PrincipalMoments: [11.5172, 11.5172]
54   PrincipalAxes:
55 1 0
56 0 1
57   FeretDiameter: 0
58   m_OrientedBoundingBoxSize: [0, 0]
59   m_OrientedBoundingBoxOrigin: [0, 0]
60 ----------------------------------------
61 ShapeLabelObject (0000022C062D4170)
62   RTTI typeinfo:   class itk::ShapeLabelObject<unsigned long,2>
63   Reference Count: 1
64   LineContainer: 0000022C062D4180
65   Label: 3
66   NumberOfPixels: 231
67   PhysicalSize: 231
68   Perimeter: 59.5651
69   NumberOfPixelsOnBorder: 0
70   PerimeterOnBorder: 0
71   PerimeterOnBorderRatio: 0
72   Elongation: 1.91485
73   Flatness: 1.91485
74   Roundness: 0.904522
75   Centroid: [110, 105]
76   BoundingBox:   ImageRegion (0000022C062D41B0)
77     Dimension: 2
78     Index: [100, 100]
79     Size: [21, 11]
80   EquivalentSphericalRadius: 8.57494
81   EquivalentSphericalPerimeter: 53.8779
82   EquivalentEllipsoidDiameter: [12.3935, 23.7317]
83   PrincipalMoments: [10, 36.6667]
84   PrincipalAxes:
85 0 1
86 -1 -0
87   FeretDiameter: 0
88   m_OrientedBoundingBoxSize: [0, 0]
89   m_OrientedBoundingBoxOrigin: [0, 0]
90 ----------------------------------------

ITK还提供了itk::BinaryImageToStatisticsLabelMapFilter类,可以提供原图区域的统计信息。

itk::ShapeLabelObject提供的形状信息包括:

 1 NumberOfPixels 像素数
 2 PhysicalSize 物理尺寸
 3 Perimeter 周长
 4 NumberOfPixelsOnBorder 边界像素数
 5 PerimeterOnBorder 边界周长
 6 PerimeterOnBorderRatio 边界周长比
 7 Elongation 伸长率
 8 Flatness 平整度
 9 Roundness 圆度
10 Centroid 质心
11 BoundingBox 包围盒
12 EquivalentSphericalRadius 等效球面半径
13 EquivalentSphericalPerimeter 等效球面周长
14 EquivalentEllipsoidDiameter 等效椭球直径
15 PrincipalMoments 主力矩
16 PrincipalAxes 主轴
17 FeretDiameter

itk::StatisticsLabelObject提供的统计信息包括:

 1 Minimum
 2 Maximum
 3 Mean
 4 Sum
 5 StandardDeviation 标准差
 6 Variance 方差
 7 Median
 8 Skewness 偏态
 9 Kurtosis 峰度
10 WeightedElongation 加权伸长率
11 WeightedFlatness 加权平面度
12 MaximumIndex
13 MinimumIndex
14 CenterOfGravity 重心
15 WeightedPrincipalMoments 加权主力矩
16 WeightedPrincipalAxes 加权主轴