PCL 垂距法实现点云精简
目录一、垂距法二、代码实现三、结果展示一、垂距法垂距法是道格拉斯普客算法的一种非递归、单遍扫描变体。它维护一个“当前有效基线”从上一个保留点指向当前候选点逐个检查中间点到该基线的垂距若超过阈值则保留该中间点并更新基线起点。二、代码实现#includeiostream#includevector#includecmath#includepcl/io/pcd_io.h#includepcl/point_types.h#includepcl/visualization/pcl_visualizer.hdoubleperpendicularDistance(constpcl::PointXYZA,constpcl::PointXYZB,constpcl::PointXYZP){doubledxB.x-A.x,dyB.y-A.y,dzB.z-A.z;doublelenstd::sqrt(dx*dxdy*dydz*dz);if(len1e-12)return0.0;doublecross_xdy*(P.z-A.z)-dz*(P.y-A.y);doublecross_ydz*(P.x-A.x)-dx*(P.z-A.z);doublecross_zdx*(P.y-A.y)-dy*(P.x-A.x);returnstd::sqrt(cross_x*cross_xcross_y*cross_ycross_z*cross_z)/len;}pcl::PointCloudpcl::PointXYZperpendicularSimplify(constpcl::PointCloudpcl::PointXYZcloud,doubledistance_threshold){if(cloud.empty())returnpcl::PointCloudpcl::PointXYZ();std::vectorpcl::PointXYZpts(cloud.begin(),cloud.end());intnpts.size();std::vectorboolkept(n,false);kept[0]kept[n-1]true;intanchor0;// 当前基线的起点索引intfloater2;// 当前基线的终点索引候选点while(floatern){// 检查 anchor 到 floater 之间所有点boolfoundExceedfalse;for(intianchor1;ifloater;i){doubledperpendicularDistance(pts[anchor],pts[floater],pts[i]);if(ddistance_threshold){// 保留前一个点floater-1作为新锚点kept[floater-1]true;anchorfloater-1;floateranchor2;foundExceedtrue;break;}}if(!foundExceed){// 所有中间点都在阈值内继续向前移动floaterfloater;}}pcl::PointCloudpcl::PointXYZout;out.reserve(std::count(kept.begin(),kept.end(),true));for(inti0;in;i){if(kept[i])out.push_back(pts[i]);}returnout;}intmain(){pcl::PointCloudpcl::PointXYZ::Ptrcloud(newpcl::PointCloudpcl::PointXYZ);if(pcl::io::loadPCDFilepcl::PointXYZ(sorted_cloud.pcd,*cloud)-1){std::cerr错误无法读取点云文件std::endl;return-1;}std::cout原始点数: cloud-size()std::endl;doubledist_thresh0.03;// 垂距阈值米pcl::PointCloudpcl::PointXYZsimplifiedperpendicularSimplify(*cloud,dist_thresh);std::cout简化后点数: simplified.size()std::endl;std::cout简化比例: (double)simplified.size()/cloud-size()*100%std::endl;pcl::io::savePCDFileBinary(simplified_perp.pcd,simplified);std::cout结果已保存至 simplified_perp.pcdstd::endl;// 可视化pcl::visualization::PCLVisualizerviewer(u8垂距法简化);viewer.addPointCloudpcl::PointXYZ(cloud,original);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,1.0,0.0,0.0,original);viewer.addPointCloudpcl::PointXYZ(simplified.makeShared(),simplified);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0.0,1.0,0.0,simplified);viewer.spin();return0;}参数调优threshold_弦高阈值是核心参数。阈值越大简化程度越高丢失的细节越多阈值越小保留的点越多计算量越大。建议根据点云的平均点间距mean_distance来设定通常为0.1 ~ 0.5倍的平均间距。三、结果展示