滚回来更新一篇文章,和各位交流一下
待处理点云:
数量级:百万
类型:零部件
描述:弯曲表面上有一些凸起在上面,需要提取凸起和平面接触的一圈点云,作为焊接的加工点
参考:
https://zhuanlan.zhihu.com/p/32111069
其实这篇文章也算是全面了,思路和他的差不多,只是算法不太一样,主要是前处理点云数据这里不太一样
首先是体素栅格滤波,待处理点云数据不均匀,且存在点云重影的问题,拟合算法效果不太好:
体素栅格:
pcl::VoxelGrid<pcl::PointXYZ> sor;
sor.setInputCloud(cloudA);
sor.setLeafSize(1.2f, 1.2f, 1.2f);//设置滤波时创建的体素大小为1.2cm立方体
sor.filter(*cloud_filtered);
高斯:
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>); //kdtree搜索
pcl::PointCloud<pcl::PointNormal> mls_points;
pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;
mls.setComputeNormals(true);// 最小二乘计算中
mls.setInputCloud(cloud);
mls.setPolynomialFit(true); //多项式拟合提高精度,
mls.setPolynomialOrder(2);//2次多项式
mls.setSearchMethod(tree);
mls.setSearchRadius(0.05);//半径
mls.setSqrGaussParam(10);
前处理最好能处理点云达到需求,保持轮廓的情况下点云数量级越小越好
正式处理:
和知乎文章一样
1.导入点云:
//导入pcd
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("xx.pcd", *cloudA) == -1)
{
PCL_ERROR("未导入点云\n");
return -1;
}
2.法线计算:
//先计算法线
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
ne.setRadiusSearch(1);//搜索半径1cm
ne.compute(*normals);
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloudA, *normals, *cloud_with_normals);
3.提取平面:采用RANSAC提取平面
setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_NORMAL_PLANE);
seg.setNormalDistanceWeight(0.1);//法线权重系数0.1
seg.setMethodType(pcl::SAC_RANSAC);
seg.setMaxIterations(1000); //迭代的次数1000
seg.setDistanceThreshold(0.5); //内点到模型的距离最大0.5
4.边界提取
normEst.setKSearch(9); //法向估计的点数
normEst.compute(*normals1);
est.setInputCloud(cloud_filtered);
est.setInputNormals(normals1);
est.setSearchMethod(tree1);
est.setKSearch(20);
est.compute(boundaries);
到这里已经有效果了:
z
知乎文章也是到这一步:
这位大神说后面需要去掉边框,和我的问题一样,大神不说那我来说拉:
直通滤波:
pcl::PassThrough<pcl::PointXYZ> pass_x;
pass_x.setInputCloud(BoundPoints);
pass_x.setFilterFieldName("x");
pass_x.setFilterLimits(min.x + 10, max.x - 20);
pass_x.filter(*cloud_filtered_x);
最终效果:
搞定,下次还不知道什么时候有时间来更新啊