vtk 读取ply或者stl点云进行ICP配准(不可直接使用vtkPolyData)

在vtk中,读取ply或stl文件使用ICP进行点云配准时,需要注意不要直接使用vtkPolyData进行配准,这种方式会报错。
vtkPLYReader读取的文件可能仅包含点数据,而没有显式的顶点定义。例如,PLY文件可能只列出点的坐标,而没有指定每个点是一个顶点。这时候,vtkPolyData中的Cells部分是空的,导致ICP无法找到单元,进而报错。
vtkVertexGlyphFilter的作用是将点数据转换为顶点单元,每个点生成一个顶点单元。这样,vtkPolyData就包含了必要的单元信息,满足ICP算法的输入要求。因此,使用这个过滤器是必要的步骤。

可参照如下代码完成配准

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include   // 关键修复:添加顶点单元

int main() {
    // 读取源PLY文件
    vtkSmartPointer<vtkPLYReader> readerSource = vtkSmartPointer<vtkPLYReader>::New();
    readerSource->SetFileName("source.ply");
    readerSource->Update();

    // 读取目标PLY文件
    vtkSmartPointer<vtkPLYReader> readerTarget = vtkSmartPointer<vtkPLYReader>::New();
    readerTarget->SetFileName("target.ply");
    readerTarget->Update();

    // --- 关键修复:为点云添加顶点单元 ---
    vtkSmartPointer<vtkVertexGlyphFilter> glyphFilterSource = vtkSmartPointer<vtkVertexGlyphFilter>::New();
    glyphFilterSource->SetInputConnection(readerSource->GetOutputPort());
    glyphFilterSource->Update();

    vtkSmartPointer<vtkVertexGlyphFilter> glyphFilterTarget = vtkSmartPointer<vtkVertexGlyphFilter>::New();
    glyphFilterTarget->SetInputConnection(readerTarget->GetOutputPort());
    glyphFilterTarget->Update();

    // 获取带顶点单元的点云数据
    vtkPolyData* source = glyphFilterSource->GetOutput();
    vtkPolyData* target = glyphFilterTarget->GetOutput();

    // 创建ICP配准器
    vtkSmartPointer<vtkIterativeClosestPointTransform> icp = 
        vtkSmartPointer<vtkIterativeClosestPointTransform>::New();
    icp->SetSource(source);
    icp->SetTarget(target);
    icp->GetLandmarkTransform()->SetModeToRigidBody();
    icp->SetMaximumNumberOfIterations(100);
    icp->StartByMatchingCentroidsOn();
    icp->Modified();
    icp->Update();

    // ...(后续可视化代码与之前相同)
}

关键修改说明
添加 vtkVertexGlyphFilter:
vtkVertexGlyphFilter 会将输入的点坐标转换为顶点单元(每个点对应一个VTK_VERTEX单元)。
必须对 源点云 和 目标点云 都进行此操作,确保输入到ICP算法的数据包含顶点信息。
验证数据有效性:
在调用Update()后,可以通过以下代码检查数据是否包含顶点单元:

if (source->GetNumberOfCells() == 0 || target->GetNumberOfCells() == 0) {
    std::cerr << "错误:点云数据未正确添加顶点单元!" << std::endl;
    return EXIT_FAILURE;
}

你可能感兴趣的:(c++,算法,开发语言)