滾回來更新一篇文章,和各位交流一下
待處理點雲:
數量級:百萬
類型:零部件
描述:彎曲表面上有一些凸起在上面,需要提取凸起和平面接觸的一圈點雲,作爲焊接的加工點
參考:
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);
最終效果:
搞定,下次還不知道什麼時候有時間來更新啊