前言
最近在处理双目相机拍摄后的图像,第一个功能是读取保存的ply文件,并在qt的控件上进行显示。前期计划采用pcl读取,pcl显示,最后结合到vtk控件上的形式。原因是双目相机保存的ply文件,vtk无法直接读取。但是在结合过程中一直出现报错,而且是各种奇怪的报错。
于是后面想到一条思路,vtk不能读取文件,那就用pcl读取,读取后的数据vtk不能直接显示,那就转化成vtk能够显示的格式。
PCL 和 VTK 显示 PLY 文件的区别主要在于两者的设计理念和底层数据结构的不同。PCL 是专门为点云处理设计的库,而 VTK 是一个通用的图形和科学数据可视化库。它们在显示点云时使用不同的数据结构和渲染管线。
1.主要区别
PCL (Point Cloud Library) 点云表示:
- PCL 使用
pcl::PointCloud<T>
类来表示点云,其中T
是点的类型(如pcl::PointXYZ
)。 - PCL 的
PointCloud
是一种数据结构,专门用于存储大量的三维点,并且非常适合用于点云处理任务。 - PCL 通过其可视化器(
pcl::visualization::PCLVisualizer
)直接显示点云,而无需对点云做过多的转换。
VTK (Visualization Toolkit) 点云表示:
- VTK 的核心数据结构之一是
vtkPolyData
,它可以存储几何数据(点、线、面等)。 vtkPolyData
可以不仅存储点云,还可以存储顶点、边、表面等数据结构,非常灵活。- 为了将 PCL 的
PointCloud
数据转换为 VTK 的vtkPolyData
,你需要将每个 PCL 点(pcl::PointXYZ
)转换为 VTK 的点(vtkPoints
),并且还要将这些点包装为 VTK 单元格(vtkVertex
)进行渲染。
2.转换步骤
首先是读取数据,filePath填写自己的ply文件路径就可以。
要注意的是<pcl::PointXYZ>并不是固定的,可以根据你的ply文件格式来,如果不写的话就是让pcl自动识别ply文件格式。
if (pcl::io::loadPLYFile<pcl::PointXYZ>(filePath, *cloud) == -1) {
PCL_ERROR("Couldn't read file %s \n", filePath.c_str());
return -1;
}
去除多余的NaN点,双目相机直接保存的ply文件很大,其中大部分都是占位用的NaN点,为了加载的快一点最好还是去除。
std::vector<int> indices; // 该向量存储的是有效点的索引
pcl::removeNaNFromPointCloud(*cloud, *cloud, indices);
接下来是转化步骤,这部分代码将 PCL 点云的每个点(
pcl::PointXYZ
)逐个提取出来,转换为 VTK 的vtkPoints
对象。VTK 需要使用自己的vtkPoints
数据结构来存储点的三维坐标。这里是转化的第一步。
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
for (size_t i = 0; i < cloud->points.size(); ++i) {
points->InsertNextPoint(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
}
这里的
vtkPolyData
是 VTK 中用于存储几何数据的核心类之一。它可以存储点、线、面等几何形状。在这里将之前的vtkPoints
添加到vtkPolyData
中,表示点云的几何数据。
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
在 VTK 中,点不仅仅是几何数据,还需要定义顶点(
vtkVertex
)来进行渲染。顶点是 VTK 的单元格(Cell
),而每个单元格包含一组点。这里的代码将每个点定义为一个顶点,并将它们添加到vtkPolyData
的单元格数组中。 这里实际是转化的第二步。
vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();
for (vtkIdType i = 0; i < points->GetNumberOfPoints(); i++) {
vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New();
vertex->GetPointIds()->SetId(0, i);
vertices->InsertNextCell(vertex);
}
polyData->SetVerts(vertices);
3.为什么要转换
-
不同的数据结构:PCL 使用
pcl::PointCloud
来存储点云,而 VTK 使用vtkPolyData
来存储几何数据。为了让 VTK 能够理解和渲染 PCL 点云,必须将数据从pcl::PointCloud
转换为 VTK 的vtkPoints
和vtkPolyData
。 -
渲染差异:PCL 的
PCLVisualizer
直接使用pcl::PointCloud
进行渲染,不需要中间转换。而 VTK 则需要将点云数据封装为vtkPolyData
和顶点数组,这样它的渲染引擎才能正确地理解和显示这些数据。
总结
- PCL 显示点云:直接使用
pcl::PointCloud
,适合点云处理和简单的点云可视化。 - VTK 显示点云:需要将点云转换为
vtkPolyData
格式,适合需要更复杂的数据处理和几何渲染的情况。 - 如果出现pcl和vtk联动有问题的情况,可以考虑以上方法,只使用pcl进行读取,其余步骤全部由vtk完成。