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();  // 开始渲染交互

渲染效果

相关推荐
罗西的思考1 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX2 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面2 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号2 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽3 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI3 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者4 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者4 小时前
【征程6】校准量化中HistogramObserver解析
算法
OuO-25 小时前
笔试强训 Day 34:ISBN 号码、kotori 和迷宫、矩阵最长递增路径
java·算法·矩阵
程序喵大人6 小时前
【C++进阶】STL算法与函数对象 - 04 find、count和any_of把查询写成意图
开发语言·c++·算法