ITK/VTK实现聚类

本文介绍如何使用ITK进行K均值聚类并通过VTK进行可视化。

头文件引入

ITK用于进行聚类分析,VTK用于可视化。itkVector用于定义点的坐标向量,itkListSample用来存储数据样本。vtkActor和vtkPolyDataMapper等类用于渲染和展示聚类后的点云。

复制代码
#include <itkDecisionRule.h>
#include <itkVector.h>
#include <itkListSample.h>
#include <itkKdTree.h>
#include <itkWeightedCentroidKdTreeGenerator.h>
#include <itkKdTreeBasedKmeansEstimator.h>
#include <itkMinimumDecisionRule.h>
#include <itkEuclideanDistanceMetric.h>
#include <itkDistanceToCentroidMembershipFunction.h>
#include <itkSampleClassifierFilter.h>
#include <itkNormalVariateGenerator.h>
#include <vtkVersion.h>
#include <vtkActor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkVertexGlyphFilter.h>

生成样本点集

使用ITK的NormalVariateGenerator生成两个正态分布的点集。每个点是一个三维向量,两个点集的均值分别为100和200,标准差为30。

复制代码
typedef itk::Vector< double, 3 > MeasurementVectorType;  // 定义三维向量
typedef itk::Statistics::ListSample< MeasurementVectorType > SampleType;  // 定义点集样本
SampleType::Pointer sample = SampleType::New();  // 创建样本实例

typedef itk::Statistics::NormalVariateGenerator NormalGeneratorType;
NormalGeneratorType::Pointer normalGenerator = NormalGeneratorType::New();

normalGenerator->Initialize(101);  // 初始化随机生成器

MeasurementVectorType mv;
double mean = 100;
double standardDeviation = 30;

// 生成第一个分布的点集
for (unsigned int i = 0; i < 100; ++i)
{
    mv[0] = (normalGenerator->GetVariate() * standardDeviation) + mean;
    mv[1] = (normalGenerator->GetVariate() * standardDeviation) + mean;
    mv[2] = (normalGenerator->GetVariate() * standardDeviation) + mean;
    sample->PushBack(mv);  // 将生成的点加入样本
}

// 生成第二个分布的点集
normalGenerator->Initialize(3024);
mean = 200;
standardDeviation = 30;
for (unsigned int i = 0; i < 100; ++i)
{
    mv[0] = (normalGenerator->GetVariate() * standardDeviation) + mean;
    mv[1] = (normalGenerator->GetVariate() * standardDeviation) + mean;
    mv[2] = (normalGenerator->GetVariate() * standardDeviation) + mean;
    sample->PushBack(mv);
}

Kd树生成与K均值聚类

使用ITK的Kd树来加速聚类计算。首先,使用WeightedCentroidKdTreeGenerator生成Kd树,接着用KdTreeBasedKmeansEstimator进行K均值聚类。

复制代码
typedef itk::Statistics::WeightedCentroidKdTreeGenerator< SampleType > TreeGeneratorType;
TreeGeneratorType::Pointer treeGenerator = TreeGeneratorType::New();

treeGenerator->SetSample(sample);  // 设置样本
treeGenerator->SetBucketSize(16);  // 设置桶大小,控制Kd树的深度
treeGenerator->Update();  // 生成Kd树

typedef itk::Statistics::KdTreeBasedKmeansEstimator<TreeGeneratorType::KdTreeType> EstimatorType;
EstimatorType::Pointer estimator = EstimatorType::New();

// 初始聚类中心的参数设置
EstimatorType::ParametersType initialMeans(6);
initialMeans[0] = 0.0; initialMeans[1] = 0.0; initialMeans[2] = 0.0;  // 第一类中心
initialMeans[3] = 5.0; initialMeans[4] = 5.0; initialMeans[5] = 5.0;  // 第二类中心

estimator->SetParameters(initialMeans);  // 设置初始中心
estimator->SetKdTree(treeGenerator->GetOutput());
estimator->SetMaximumIteration(200);  // 设置最大迭代次数
estimator->SetCentroidPositionChangesThreshold(0.0);  // 设置聚类终止条件
estimator->StartOptimization();  // 开始K均值聚类

EstimatorType::ParametersType estimatedMeans = estimator->GetParameters();  // 获取聚类后的中心点

分类与决策规则

使用分类器对点集进行分类,通过SampleClassifierFilter和MinimumDecisionRule将样本根据聚类结果分为两类。

复制代码
typedef itk::Statistics::DistanceToCentroidMembershipFunction< MeasurementVectorType > MembershipFunctionType;
typedef itk::Statistics::MinimumDecisionRule DecisionRuleType;

DecisionRuleType::Pointer decisionRule = DecisionRuleType::New();
typedef itk::Statistics::SampleClassifierFilter< SampleType > ClassifierType;
ClassifierType::Pointer classifier = ClassifierType::New();

classifier->SetDecisionRule(decisionRule);
classifier->SetInput(sample);  // 输入样本
classifier->SetNumberOfClasses(2);  // 设置分类数量
classifier->Update();  // 执行分类操作

VTK可视化

复制代码
vtkSmartPointer<vtkPoints> points1 = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPoints> points2 = vtkSmartPointer<vtkPoints>::New();

// 根据分类结果将点分配到两个点集中
auto iter = classifier->GetOutput()->Begin();
while (iter != classifier->GetOutput()->End())
{
    if (iter.GetClassLabel() == 100) {
        points1->InsertNextPoint(iter.GetMeasurementVector()[0],
                                 iter.GetMeasurementVector()[1],
                                 iter.GetMeasurementVector()[2]);
    } else {
        points2->InsertNextPoint(iter.GetMeasurementVector()[0],
                                 iter.GetMeasurementVector()[1],
                                 iter.GetMeasurementVector()[2]);
    }
    ++iter;
}

// 渲染分类后的点集
vtkSmartPointer<vtkPolyData> polyData1 = vtkSmartPointer<vtkPolyData>::New();
polyData1->SetPoints(points1);
vtkSmartPointer<vtkPolyDataMapper> mapper1 = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper1->SetInputConnection(glyphFilter1->GetOutputPort());
vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New();
actor1->GetProperty()->SetColor(0, 1, 0);  // 绿色点表示第一类
actor1->GetProperty()->SetPointSize(3);

// 同样设置第二类的点集和渲染属性
vtkSmartPointer<vtkPolyData> polyData2 = vtkSmartPointer<vtkPolyData>::New();
polyData2->SetPoints(points2);
vtkSmartPointer<vtkPolyDataMapper> mapper2 = vtkSmartPointer<vtkPolyDataMapper>::New();
vtkSmartPointer<vtkActor> actor2 = vtkSmartPointer<vtkActor>::New();
actor2->GetProperty()->SetColor(1, 0, 0);  // 红色点表示第二类
actor2->GetProperty()->SetPointSize(3);

// 创建渲染窗口并展示
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor1);  // 添加第一类的点集
renderer->AddActor(actor2);  // 添加第二类的点集
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Start();  // 开始渲染交互

渲染效果

相关推荐
CoovallyAIHub14 分钟前
为什么85%的企业AI项目都失败了?
深度学习·算法·计算机视觉
KarrySmile17 分钟前
Day8--滑动窗口与双指针--1004. 最大连续1的个数 III,1658. 将 x 减到 0 的最小操作数,3641. 最长半重复子数组
数据结构·算法·双指针·滑动窗口·不定长滑动窗口·最大连续1的个数·最长子数组
zc.ovo21 分钟前
图论水题4
c++·算法·图论
KyollBM26 分钟前
【Luogu】每日一题——Day20. P4366 [Code+#4] 最短路 (图论)
算法·图论
qqxhb27 分钟前
零基础数据结构与算法——第七章:算法实践与工程应用-金融算法
算法·风险评估算法·金融算法·交易策略算法·欺诈检测算法
墩墩同学1 小时前
【LeetCode题解】LeetCode 74. 搜索二维矩阵
算法·leetcode·二分查找
SunnyKriSmile1 小时前
输入10个数并求最大值
c语言·算法
汤永红2 小时前
week2-[循环嵌套]数位和为m倍数的数
c++·算法·信睡奥赛
崎岖Qiu4 小时前
leetcode100.相同的树(递归练习题)
算法·leetcode·二叉树·力扣·递归
No0d1es11 小时前
电子学会青少年软件编程(C/C++)5级等级考试真题试卷(2024年6月)
c语言·c++·算法·青少年编程·电子学会·五级