vtkIterativeClosestPointTransform
ICP 算法的实现。
使用迭代最近点 (ICP) 算法匹配两个表面。该算法的核心是将一个表面中的每个顶点与另一个表面的最近表面点进行匹配,然后应用变换来修改一个表面以最佳匹配另一个表面(在最小二乘意义上)。这必须进行迭代才能获得表面的正确收敛。
注意
使用 vtkTransformPolyDataFilter 将生成的 ICP 变换应用于您的数据。您也可以将其设置为演员的用户变换。
此类在内部使用 vtkLandmarkTransform 来计算最佳拟合。使用 GetLandmarkTransform 成员获取指向该变换的指针并设置其参数。例如,您可以通过检查 vtkLandmarkTransform 文档中的 SetMode 成员来限制解决方案的自由度数(即刚体、相似性等)。
-
设置源点云和目标点云:
- 使用
SetSource
方法设置源点云。 - 使用
SetTarget
方法设置目标点云。
- 使用
-
配置算法参数:
MaximumNumberOfIterations
:设置/获取最大迭代次数。默认值为 50。CheckMeanDistance
:强制算法检查两次迭代之间的平均距离。MaximumMeanDistance
: 设置/获取两次迭代之间的最大平均距离。如果平均距离低于此值,则收敛停止。默认值为 0.01。MeanDistanceMode
: 指定平均距离模式。此模式表示如何计算平均距离。RMS 模式是最近点距离平方和的平均值的平方根。绝对值模式是最近点距离绝对值和的平均值。默认值为 VTK_ICP_MODE_RMS.MaximumNumberOfLandmarks
:设置/获取数据集中采样的地标的最大数量。如果数据集很密集,则通常不需要所有点来计算 ICP 变换。默认值为 200。SetStartByMatchingCentroids
:通过将源质心转换为目标质心来启动该过程。默认为关闭。LandmarkTransform
:获取内部地标变换。使用它来约束解决方案的自由度数量(即刚体、相似性等)。
-
执行变换:
- 调用
Update
方法执行 ICP 算法。
- 调用
示例代码
以下是一个简单的示例,展示如何使用 vtkIterativeClosestPointTransform
进行点云配准:
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkIterativeClosestPointTransform.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransformFilter.h>
int main() {
// 创建源点云
vtkSmartPointer<vtkPoints> sourcePoints = vtkSmartPointer<vtkPoints>::New();
sourcePoints->InsertNextPoint(0.0, 0.0, 0.0);
sourcePoints->InsertNextPoint(1.0, 0.0, 0.0);
sourcePoints->InsertNextPoint(0.0, 1.0, 0.0);
vtkSmartPointer<vtkPolyData> source = vtkSmartPointer<vtkPolyData>::New();
source->SetPoints(sourcePoints);
// 创建目标点云
vtkSmartPointer<vtkPoints> targetPoints = vtkSmartPointer<vtkPoints>::New();
targetPoints->InsertNextPoint(1.0, 1.0, 0.0);
targetPoints->InsertNextPoint(2.0, 1.0, 0.0);
targetPoints->InsertNextPoint(1.0, 2.0, 0.0);
vtkSmartPointer<vtkPolyData> target = vtkSmartPointer<vtkPolyData>::New();
target->SetPoints(targetPoints);
// 创建 ICP 变换
vtkSmartPointer<vtkIterativeClosestPointTransform> icp = vtkSmartPointer<vtkIterativeClosestPointTransform>::New();
icp->SetSource(source);
icp->SetTarget(target);
icp->SetMaximumNumberOfIterations(50);
icp->StartByMatchingCentroidsOn();
icp->Update();
// 获取变换矩阵
vtkSmartPointer<vtkMatrix4x4> matrix = icp->GetMatrix();
// 应用变换
vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
transformFilter->SetInputData(source);
transformFilter->SetTransform(icp);
transformFilter->Update();
// 创建渲染器和窗口
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
// 创建源点云的 Actor
vtkSmartPointer<vtkPolyDataMapper> sourceMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
sourceMapper->SetInputData(source);
vtkSmartPointer<vtkActor> sourceActor = vtkSmartPointer<vtkActor>::New();
sourceActor->SetMapper(sourceMapper);
sourceActor->GetProperty()->SetColor(1.0, 0.0, 0.0); // 红色
// 创建变换后的源点云的 Actor
vtkSmartPointer<vtkPolyDataMapper> transformedSourceMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
transformedSourceMapper->SetInputConnection(transformFilter->GetOutputPort());
vtkSmartPointer<vtkActor> transformedSourceActor = vtkSmartPointer<vtkActor>::New();
transformedSourceActor->SetMapper(transformedSourceMapper);
transformedSourceActor->GetProperty()->SetColor(0.0, 1.0, 0.0); // 绿色
// 创建目标点云的 Actor
vtkSmartPointer<vtkPolyDataMapper> targetMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
targetMapper->SetInputData(target);
vtkSmartPointer<vtkActor> targetActor = vtkSmartPointer<vtkActor>::New();
targetActor->SetMapper(targetMapper);
targetActor->GetProperty()->SetColor(0.0, 0.0, 1.0); // 蓝色
// 添加 Actor 到渲染器
renderer->AddActor(sourceActor);
renderer->AddActor(transformedSourceActor);
renderer->AddActor(targetActor);
renderer->SetBackground(1.0, 1.0, 1.0); // 白色背景
// 渲染
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}
解释
- 创建点云:分别创建源点云和目标点云,并存储在
vtkPolyData
对象中。 - 创建 ICP 变换:实例化
vtkIterativeClosestPointTransform
,并设置源点云和目标点云。 - 配置 ICP 参数:设置最大迭代次数和是否从质心匹配开始。
- 执行变换:调用
Update
方法执行 ICP 算法。 - 获取变换矩阵:使用
GetMatrix
方法获取变换矩阵。 - 应用变换:使用
vtkTransformFilter
将变换应用到源点云。 - 可视化:创建渲染器和窗口,添加源点云、变换后的源点云和目标点云的 Actor,并渲染结果。
通过上述步骤,你可以使用 vtkIterativeClosestPointTransform
进行点云配准,并可视化配准结果。
vtkLandmarkTransform
由两个对应点集指定的线性变换
vtkLandmarkTransform 由两组地标定义,计算出的变换在最小二乘意义上给出了将一个映射到另一个的最佳拟合。索引被视为对应,因此第一组中的点 1 将映射到第二组中的点 1 附近,等等。调用 SetSourceLandmarks 和 SetTargetLandmarks 来指定两组地标,确保它们具有相同数量的点。
警告
每当您添加、减去或设置点时,都必须在 vtkPoints 对象上调用 Modified(),否则转换可能不会更新。