一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

连通域

一个区域D中,任一闭曲线所围区域,都属于区域D,称为“单连通区域”。

连通域形状分析

  1. 创建二值图像
 1 using ImageType = itk::Image<unsigned char, 2>;
 2 
 3 ImageType::Pointer CreateMaskImage()
 4 {
 5     ImageType::Pointer image = ImageType::New();
 6     ImageType::IndexType start;
 7     start.Fill(0);
 8 
 9     ImageType::SizeType size;
10     size.Fill(128);
11 
12     ImageType::RegionType region;
13     region.SetSize(size);
14     region.SetIndex(start);
15 
16     image->SetRegions(region);
17     image->Allocate();
18 
19     using IteratorType = itk::ImageRegionIteratorWithIndex< ImageType >;
20     IteratorType it(image, image->GetRequestedRegion());
21 
22     for (it.GoToBegin(); !it.IsAtEnd(); ++it)
23     {
24         ImageType::IndexType idx = it.GetIndex();
25 
26         // 创建空心圆 C=(50,50),R=15,r=5
27         if ((idx[0] - 50)*(idx[0] - 50) + (idx[1] - 50)*(idx[1] - 50) < 225 &&
28             (idx[0] - 50)*(idx[0] - 50) + (idx[1] - 50)*(idx[1] - 50) > 25)
29             it.Set(1);
30 
31         // 创建圆 C=(70,80),r=7
32         else if ((idx[0] - 70)*(idx[0] - 70) + (idx[1] - 80)*(idx[1] - 80) < 49)
33             it.Set(1);
34 
35         // 创建矩形 C=(100,100),W(120,110)
36         else if (idx[0] >= 100 && idx[0] <= 120 &&
37             idx[1] >= 100 && idx[1] <= 110)
38             it.Set(1);
39 
40         else
41             it.Set(0);
42     }
43 
44     return image;
45 }

生成图像如下

  1. 打印所有连通区域信息
 1 typedef unsigned long LabelType;
 2 typedef itk::ShapeLabelObject< LabelType, 2 >                                    LabelObjectType;
 3 typedef itk::LabelMap< LabelObjectType >                                        LabelMapType;
 4 typedef itk::BinaryImageToShapeLabelMapFilter< ImageType, LabelMapType >        I2LType;
 5 I2LType::Pointer i2l = I2LType::New();
 6 i2l->SetInput(mask);
 7 i2l->SetFullyConnected(false);
 8 i2l->SetInputForegroundValue(1);
 9 i2l->SetOutputBackgroundValue(0);
10 i2l->Update();
11 
12 LabelMapType::Pointer labelMap = i2l->GetOutput();
13 for (unsigned int label = 1; label <= labelMap->GetNumberOfLabelObjects(); label++)
14 {
15     const LabelObjectType * labelObject = labelMap->GetLabelObject(label);
16     labelObject->Print(std::cout);
17     std::cout << "----------------------------------------" << std::endl;
18 }

打印信息如下:

 1 ShapeLabelObject (000002469EAA6CE0)
 2   RTTI typeinfo:   class itk::ShapeLabelObject<unsigned long,2>
 3   Reference Count: 1
 4   LineContainer: 000002469EAA6CF0
 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 (000002469EAA6D20)
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 (000002469EAA7030)
32   RTTI typeinfo:   class itk::ShapeLabelObject<unsigned long,2>
33   Reference Count: 1
34   LineContainer: 000002469EAA7040
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 (000002469EAA7070)
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 (000002469EAA7170)
62   RTTI typeinfo:   class itk::ShapeLabelObject<unsigned long,2>
63   Reference Count: 1
64   LineContainer: 000002469EAA7180
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 (000002469EAA71B0)
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 ----------------------------------------
  1. 统计灰度信息
1 typedef itk::BinaryImageToStatisticsLabelMapFilter< ImageType, ImageType > ConverterType;
2 ConverterType::Pointer converter = ConverterType::New();
3 converter->SetInput(reader->GetOutput());
4 converter->SetFeatureImage(reader2->GetOutput());
5 converter->SetInputForegroundValue(1);
6 converter->SetFullyConnected(false);
7 converter->Update();
8 converter->GetOutput()->PrintLabelObjects();
  1. 过滤连通区域
 1 typedef unsigned long LabelType;
 2 typedef itk::ShapeLabelObject< LabelType, 2 >                                    LabelObjectType;
 3 typedef itk::LabelMap< LabelObjectType >                                        LabelMapType;
 4 typedef itk::BinaryImageToShapeLabelMapFilter< ImageType, LabelMapType >        I2LType;
 5 I2LType::Pointer i2l = I2LType::New();
 6 i2l->SetInput(mask);
 7 i2l->SetFullyConnected(false);
 8 i2l->SetInputForegroundValue(1);
 9 i2l->SetOutputBackgroundValue(0);
10 i2l->Update();
11 
12 LabelMapType::Pointer labelMap = i2l->GetOutput();
13 for (unsigned int label = 1; label <= labelMap->GetNumberOfLabelObjects(); label++)
14 {
15     const LabelObjectType * labelObject = labelMap->GetLabelObject(label);
16     labelObject->Print(std::cout);
17     std::cout << "----------------------------------------" << std::endl;
18 }
19 
20 std::vector< LabelObjectType::Pointer > filtered_label_objects;
21 for (LabelMapType::Iterator it(labelMap); !it.IsAtEnd(); ++it)
22 {
23     // 过滤条件
24     if (it.GetLabelObject()->GetRoundness() < 0.95)
25         filtered_label_objects.push_back(it.GetLabelObject());
26 }
27 
28 for (int i = 0; i < filtered_label_objects.size(); i++)
29 {
30     labelMap->RemoveLabelObject(filtered_label_objects[i]);
31 }
32 
33 typedef itk::LabelMapToBinaryImageFilter< LabelMapType, ImageType> L2IType;
34 L2IType::Pointer l2i = L2IType::New();
35 l2i->SetInput(labelMap);
36 l2i->Update();
37 
38 using WriterType = itk::ImageFileWriter<ImageType>;
39 WriterType::Pointer writer = WriterType::New();
40 writer->SetFileName("mask.mha");
41 writer->SetInput(l2i->GetOutput());
42 writer->SetImageIO(itk::MetaImageIO::New());
43 writer->Update();

效果如下:

总结
通过连通域形状分析可以过滤到阈值分割中的错误部分,另外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 加权主轴

 

posted on 2023-07-13 14:28  一杯清酒邀明月  阅读(300)  评论(0编辑  收藏  举报