一.点云显示模块
根据PCL中国官方论坛上田博士的四篇文章http://www.pclcn.org/bbs/forum.php?mod=viewthread&tid=223&page=1&extra=#pid750,在MFC环境中搭建了基本的点云显示模块。这是后续所有操作的基础。
1.需要解决的问题有:
( 1)由于田博士在帖子里说,PCL-1.6.0-AllInOne-msvc2010-win32中提供的VTK5.8缺少关键文件vtkMFCWindow.h和vktMFC.lib,所以无法实现基于MFC的PCL窗体。因此需要自行下载VTK5.10,用CMake生成工程文件;我下载的CMake版本是2.8.11.1,第一次进行配置的时候,看不到VTK_USE_MFC的选项,通过复选“Advanced”复选框找到了VTK_GUI_SUPPORT选项,勾选这个选项之后单击“Config”按钮,才找到了VTK_USE_MFC的选项;注意,如果不勾选VTK_USE_MFC的选项,就不能生成vtkMFC工程需要的信息;(具体过程参考笔记《VTK安装及源码编译》)。
(2)编译自己的项目时会在下面的代码处,遇到很多编译错误:
std::numeric_limits<double >::max();
std::max();
编译错误的内容是:
“(”: “::”右边的非法标记
错误原因:函数模板max与Visual
C++中的全局的宏max冲突。
从网上找到的解决办法是把“std::numeric_limits<double>::max”用小括号括起来;
(std::numeric_limits<double>::max)();
(std::max)();
还有另外一种解决方法是在冲突的文件的头文件加上:#undef max
#undef min
(3)一些其他的调试问题。
2.修改点云显示模块
田博士修改的代码中点云显示类型是sensor_msgs::PointCloud2
- this->binary_blob.reset();
- binary_blob = sensor_msgs::PointCloud2::Ptr (new
sensor_msgs::PointCloud2); - // read new data
- //*.pcd文件
- pcl::PCDReader pcd_reader;
- if (pcd_reader.read ((char*)_bstr_t(filename.c_str()),
*binary_blob) != 0) //* load the file - {
- MessageBox
(_T("Couldn‘t read PCData file!")); - return;
- }
- }
- if (binary_blob ==
NULL) - {
- MessageBox("Please load PCD file firstly!");
- return;
- }
- else
- {
- //其他句柄
- if (pcl::getFieldIndex(*binary_blob, "rgb") >
0) - {
- color_Handler =
pcl::mfc_visualization::PointCloudColorHandlerRGBField<sensor_msgs::PointCloud2>::Ptr - (new
pcl::mfc_visualization::PointCloudColorHandlerRGBField<sensor_msgs::PointCloud2>
(binary_blob)); - this->viewer->addPointCloud(binary_blob, color_Handler,
sensor_origin, sensor_orientation); - }
- else
- {
- xyz_Handler =
pcl::mfc_visualization::PointCloudGeometryHandlerXYZ<sensor_msgs::PointCloud2>::Ptr - (new
pcl::mfc_visualization::PointCloudGeometryHandlerXYZ<sensor_msgs::PointCloud2>
(binary_blob)); - this->viewer->addPointCloud(binary_blob, xyz_Handler,
sensor_origin, sensor_orientation); - }
- this->viewer->resetCamera();
我们将其修改为pcl::PointCloud<pcl::PointXYZ>:并独立出显示函数
void CPointCloudLabDlg::simplevis
(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
//统计选取点云数
//创建3D窗口并添加点云
viewer->removeAllPointClouds();
viewer->removeAllShapes();
viewer->setBackgroundColor (0,0,0);
viewer->addPointCloud<pcl::PointXYZ> (cloud,
"sample cloud");
viewer->setPointCloudRenderingProperties
(pcl::mfc_visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample
cloud");
viewer->addCoordinateSystem (1.0);
//viewer->initCameraParameters ();
viewer->resetCamera();
}
图1
图2
二.点云滤波
1.直通滤波器
这是一个书桌的场景,滤波之前其可视化结果如图2所示。很明显可以看出其右侧存在一大块噪声数据,对于这种大块的且与主体点云数据存在明显界限的噪声数据,最快的方法就是直接设计一个直通滤波器,该方法简单易用,且效果明显,唯一不足的就是需要手动滤波,即用户必须经过多次尝试,找到噪声数据与主体点云数据的大致边界。图3即为直通滤波之后的结果,直通滤波器设置为保留x坐标在-0.9~0.6之间的点云数据,很明显可以看出书桌左右两部分的大量噪声数据被移除掉了。
图3
对于巷道
图4
2.StatisticOutlierRemoval滤波器移除离群点
直通滤波虽然能快速移除大量的噪声点,但其具有很大的局限性,一是需要手动滤波,需要人为判断噪声点的大致位置,经过多次尝试才能找到大致的滤波范围;二是直通滤波的应用场合有限,除非噪声点与主体点云数据具有明显的界限。下面介绍一种不需要人工判断且能有限移除主体点云周围离群噪声点的方法,可以解决其中部分问题:建立点云数据的拓扑结构,对每个点的邻域进行一个统计分析,并修剪掉那些不符合一定标准的点。我们的稀疏离群点移除方法基于在输人数据中对点到临近点的距离分布的计算。对每个点,我们计算它到它的所有临近点的平均距离。假设得到的结果是一个高斯分布,其形状由均值和标准差决定,平均距离在标准范围(由全
局距离平均值 和方差定义)之外的点,可被定义为离群点并可从数据集中去除掉。使用StatisticOutlierRemoval滤波器移除离群点之前如图3所示,滤波过后如图5所示。
三.点云精简
上面两幅图的右下角都显示了其点的数量。
1.包围盒法
该方法是首先用一个体包围盒来约束点云,将所有的点云数据置于这个包围盒中,然后把这个大包围盒分解成许多大小一致的小盒,选取与各小盒中心点或与中心点最接近的点取代各小盒中全部的点,经过该方法处理过的点云个数即为小盒的个数,该方法操作简单,能有效减少点云数量。
首先设置包围盒长宽高,一般我们就用立方体。边长越长,精简程度越大。
2.基于Alpha Shapes
基于Alpha
Shapes的点云精简算法是笔者在研究三维点云的凸包模型时发现的,三维点云的凸包模型能近似表示物体表面的轮廓,通过提取三维凸包模型的凸包点来构建物体表面,就可以大幅减少点云数据量,但是三维凸包不能真实反映物体的轮廓形貌,当物体表面存在凹陷时,凸包就不能反映出来,因此衍生出一种Alpha
Shapes的概念,该方法能有效保持物体的原貌,其精简精度也易控制。下面对上面的点云进一步简化。
四.点云重建
1.贪婪投影三角化算法
设置参数