最大圆度概念:
圆度计算(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 加权主轴