关于编译部分可以参考我的:VTK学习笔记(十)基于VTK和ITK程序
最大圆度概念:
圆度计算(Circularity,Roundness)
Roundness = (4 * CV_PI * Area) / (Perimeter * Perimeter )
double getRoundness(std::vector<cv::Point> contour)
{
double factor = (cv::contourArea(contour) * 4 * CV_PI) / (pow(cv::arcLength(contour, true), 2));
return factor;
}
#include "itkImage.h"
#include
#include
#include "itkScalarConnectedComponentImageFilter.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void CreateImage(itk::Image<unsigned char, 2>* const image)
{
// Create an image with 2 connected components
itk::Image<unsigned char, 2>::IndexType start = { {0,0} };
start[0] = 0;
start[1] = 0;
itk::Image<unsigned char, 2>::SizeType size;
unsigned int NumRows = 100;
unsigned int NumCols = 200;
size[0] = NumRows;
size[1] = NumCols;
typename itk::Image<unsigned char, 2>::RegionType region(start, size);
image->SetRegions(region);
image->Allocate(true);// 全0的像素(黑色)
// Make a square
for (itk::Image<unsigned char, 2>::IndexValueType r = 5; r < 40; r++)
{
for (itk::Image<unsigned char, 2>::IndexValueType c = 10; c < 50; c++)
{
itk::Image<unsigned char, 2>::IndexType pixelIndex = { {r,c} };
image->SetPixel(pixelIndex, 100);//灰色
}
}
// Make another square
for (typename itk::Image<unsigned char, 2>::IndexValueType r = 50; r < 70; r++)
{
for (typename itk::Image<unsigned char, 2>::IndexValueType c = 50; c < 80; c++)
{
typename itk::Image<unsigned char, 2>::IndexType pixelIndex = { {r,c} };
image->SetPixel(pixelIndex, 255);//白色
}
}
}
void print(const std::string& file, itk::Image<unsigned char, 2>* image)
{
ofstream fout(file);
auto size = image->GetBufferedRegion().GetSize();
for (auto i = 0; i < size[0]; i++)
{
for (auto j = 0; j < size[1]; j++)
{
itk::Image<unsigned char, 2>::IndexType index{ {i,j} };
auto c = image->GetPixel(index);
fout << (int)c;
}
fout << std::endl;
}
}
using ImageType = itk::Image<unsigned char, 2>;
ImageType::Pointer CreateMaskImage()
{
ImageType::Pointer image = ImageType::New();
ImageType::IndexType start;
start.Fill(0);
ImageType::SizeType size;
size.Fill(128);
ImageType::RegionType region;
region.SetSize(size);
region.SetIndex(start);
image->SetRegions(region);
image->Allocate();
using IteratorType = itk::ImageRegionIteratorWithIndex< ImageType >;
IteratorType it(image, image->GetRequestedRegion());
for (it.GoToBegin(); !it.IsAtEnd(); ++it)
{
ImageType::IndexType idx = it.GetIndex();
// 创建空心圆 C=(50,50),R=15,r=5
if ((idx[0] - 50) * (idx[0] - 50) + (idx[1] - 50) * (idx[1] - 50) < 225 &&
(idx[0] - 50) * (idx[0] - 50) + (idx[1] - 50) * (idx[1] - 50) > 25)
it.Set(1);
// 创建圆 C=(70,80),r=7
else if ((idx[0] - 70) * (idx[0] - 70) + (idx[1] - 80) * (idx[1] - 80) < 49)
it.Set(1);
// 创建矩形 C=(100,100),W(120,110)
else if (idx[0] >= 100 && idx[0] <= 120 &&
idx[1] >= 100 && idx[1] <= 110)
it.Set(1);
else
it.Set(0);
}
return image;
}
int main(int argc, char *argv[])
{
// 1、创建二值图像
ImageType::Pointer image = CreateMaskImage();//
//将itk图片转换成vtk图片
auto imageToVtkImage = itk::ImageToVTKImageFilter<itk::Image<unsigned char, 2>>::New();
imageToVtkImage->SetInput(image.GetPointer());
imageToVtkImage->Update();// 只有更新之后,后续使用者才可以拿到真正的数据
//保存vtk图片为png文件
vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
writer->SetFileName("D:/documents/vs2019/itk_tutorial/connectcompent/build/RelWithDebInfo/1CreateImage.png");
writer->SetInputData(imageToVtkImage->GetOutput());
writer->Write();
//保存vtk图片像素值到文本文件
print("D:/documents/vs2019/itk_tutorial/connectcompent/build/RelWithDebInfo/1CreateImage.txt", image.GetPointer());
// 2、过滤连通区域
typedef unsigned long LabelType;
typedef itk::ShapeLabelObject< LabelType, 2 > LabelObjectType;
typedef itk::LabelMap< LabelObjectType > LabelMapType;
typedef itk::BinaryImageToShapeLabelMapFilter< ImageType, LabelMapType > I2LType;
I2LType::Pointer i2l = I2LType::New();
i2l->SetInput(image);
i2l->SetFullyConnected(false);
i2l->SetInputForegroundValue(1);
i2l->SetOutputBackgroundValue(0);
i2l->Update();
LabelMapType::Pointer labelMap = i2l->GetOutput();
for (unsigned int label = 1; label <= labelMap->GetNumberOfLabelObjects(); label++)
{
const LabelObjectType* labelObject = labelMap->GetLabelObject(label);
labelObject->Print(std::cout);
std::cout << "----------------------------------------" << std::endl;
}
std::vector< LabelObjectType::Pointer > filtered_label_objects;
for (LabelMapType::Iterator it(labelMap); !it.IsAtEnd(); ++it)
{
// 过滤条件
if (it.GetLabelObject()->GetRoundness() < 0.95)
filtered_label_objects.push_back(it.GetLabelObject());
}
for (int i = 0; i < filtered_label_objects.size(); i++)
{
labelMap->RemoveLabelObject(filtered_label_objects[i]);
}
typedef itk::LabelMapToBinaryImageFilter< LabelMapType, ImageType> L2IType;
L2IType::Pointer l2i = L2IType::New();
l2i->SetInput(labelMap);
l2i->Update();
using WriterType = itk::ImageFileWriter<ImageType>;
WriterType::Pointer writer1 = WriterType::New();
writer1->SetFileName("mask.mha");
writer1->SetInput(l2i->GetOutput());
writer1->SetImageIO(itk::MetaImageIO::New());
writer1->Update();
return EXIT_SUCCESS;
}
因为是二值图,像素值只有0和1,直接查看颜色是黑色的,导入slicer中查看。
直接查看:
slicer中查看:
最终保留的圆度最大文件mask.mha,使用slicer打开:
ShapeLabelObject (0000022C062D43F0)
RTTI typeinfo: class itk::ShapeLabelObject<unsigned long,2>
Reference Count: 1
LineContainer: 0000022C062D4400
Label: 1
NumberOfPixels: 616
PhysicalSize: 616
Perimeter: 127.254
NumberOfPixelsOnBorder: 0
PerimeterOnBorder: 0
PerimeterOnBorderRatio: 0
Elongation: 1
Flatness: 1
Roundness: 0.691393
Centroid: [50, 50]
BoundingBox: ImageRegion (0000022C062D4430)
Dimension: 2
Index: [36, 36]
Size: [29, 29]
EquivalentSphericalRadius: 14.0028
EquivalentSphericalPerimeter: 87.9823
EquivalentEllipsoidDiameter: [28.0056, 28.0056]
PrincipalMoments: [61.9156, 61.9156]
PrincipalAxes:
1 0
0 1
FeretDiameter: 0
m_OrientedBoundingBoxSize: [0, 0]
m_OrientedBoundingBoxOrigin: [0, 0]
----------------------------------------
ShapeLabelObject (0000022C062D3630)
RTTI typeinfo: class itk::ShapeLabelObject<unsigned long,2>
Reference Count: 1
LineContainer: 0000022C062D3640
Label: 2
NumberOfPixels: 145
PhysicalSize: 145
Perimeter: 41.524
NumberOfPixelsOnBorder: 0
PerimeterOnBorder: 0
PerimeterOnBorderRatio: 0
Elongation: 1
Flatness: 1
Roundness: 1.02799
Centroid: [70, 80]
BoundingBox: ImageRegion (0000022C062D3670)
Dimension: 2
Index: [64, 74]
Size: [13, 13]
EquivalentSphericalRadius: 6.79374
EquivalentSphericalPerimeter: 42.6863
EquivalentEllipsoidDiameter: [13.5875, 13.5875]
PrincipalMoments: [11.5172, 11.5172]
PrincipalAxes:
1 0
0 1
FeretDiameter: 0
m_OrientedBoundingBoxSize: [0, 0]
m_OrientedBoundingBoxOrigin: [0, 0]
----------------------------------------
ShapeLabelObject (0000022C062D4170)
RTTI typeinfo: class itk::ShapeLabelObject<unsigned long,2>
Reference Count: 1
LineContainer: 0000022C062D4180
Label: 3
NumberOfPixels: 231
PhysicalSize: 231
Perimeter: 59.5651
NumberOfPixelsOnBorder: 0
PerimeterOnBorder: 0
PerimeterOnBorderRatio: 0
Elongation: 1.91485
Flatness: 1.91485
Roundness: 0.904522
Centroid: [110, 105]
BoundingBox: ImageRegion (0000022C062D41B0)
Dimension: 2
Index: [100, 100]
Size: [21, 11]
EquivalentSphericalRadius: 8.57494
EquivalentSphericalPerimeter: 53.8779
EquivalentEllipsoidDiameter: [12.3935, 23.7317]
PrincipalMoments: [10, 36.6667]
PrincipalAxes:
0 1
-1 -0
FeretDiameter: 0
m_OrientedBoundingBoxSize: [0, 0]
m_OrientedBoundingBoxOrigin: [0, 0]
----------------------------------------
TK还提供了itk::BinaryImageToStatisticsLabelMapFilter类,可以提供原图区域的统计信息。
itk::ShapeLabelObject提供的形状信息包括:
NumberOfPixels 像素数
PhysicalSize 物理尺寸
Perimeter 周长
NumberOfPixelsOnBorder 边界像素数
PerimeterOnBorder 边界周长
PerimeterOnBorderRatio 边界周长比
Elongation 伸长率
Flatness 平整度
Roundness 圆度
Centroid 质心
BoundingBox 包围盒
EquivalentSphericalRadius 等效球面半径
EquivalentSphericalPerimeter 等效球面周长
EquivalentEllipsoidDiameter 等效椭球直径
PrincipalMoments 主力矩
PrincipalAxes 主轴
FeretDiameter
itk::StatisticsLabelObject提供的统计信息包括:
Minimum
Maximum
Mean
Sum
StandardDeviation 标准差
Variance 方差
Median
Skewness 偏态
Kurtosis 峰度
WeightedElongation 加权伸长率
WeightedFlatness 加权平面度
MaximumIndex
MinimumIndex
CenterOfGravity 重心
WeightedPrincipalMoments 加权主力矩
WeightedPrincipalAxes 加权主轴
参考:ITK连通域分析
参考: