1、背景介绍
很多边缘提取算法提取的边缘点为无序点云,如下图所示,无序点云不利于后续各种应用,比如根据边缘计算点云面积、点云轮廓线规则化等。若对点云进行排序,则可以进行上述引用。但实际上,点云形状错综复杂,对点云进行排序难度会比较大。此次博客介绍一种针对简单形状点云的边缘点排序原理,对于复杂形状点云,仅供参考。
图 1 边缘点无序与有序示例
2、原理介绍
对于形状简单的点云,可以使用与某一方向的夹角,按照夹角大小进行排序,实现点的排序,如下图所示。
图 2 轮廓点与起始方向夹角示意图
对点进行排序的步骤如下:
(1)中心计算:统计所有点的平均坐标作为中心
(2)计算旋转角:以y轴为起始方向,计算每个轮廓点与y轴的夹角,得到夹角集合
(3)角度排序:对角度从小到大进行排序,按照排序后的角度对轮廓点进行排序,即实现角度排序
****在对角度排序时,使用for循环找到角度停止即可,可以提高排序效率。
for (int i = 0; i < sortedangles.size(); i++)//依据角度寻找点{for (int j = 0; j < allangles.size(); j++){if (sortedangles[i] == allangles[j]){result.push_back(unorderpt[j]);break;//终止}}}
3、测试
源代码下载链接:简单形状点云轮廓点排序(旋转角)-CSDN博客
本程序在PCL配置好的环境下进行运行,只需要将配置好的环境下,将利用旋转角对点排序.cpp添加到源文件目录下运行即可。
3.1 可视化未排序前结果
测试主函数代码如下:
//未排序前的点,进行连接
void main()
{//(1)读入边缘点vector<pcl::PointXYZ> boundpts;string filepath = "D:\\testdata\\testdata_01_boud.txt";std::ifstream pointsFile(filepath, std::ios::in);pcl::PointXYZ point;char line[128];double x, y, z;int r, g, b;while (pointsFile.getline(line, sizeof(line))){std::stringstream word(line);word >> x;word >> y;word >> z;word >> r;word >> g;word >> b;point.x = x;point.y = y;point.z = z;if (r == 255 && g == 0 && b == 0)//边缘点(为红色点){pcl::PointXYZ onept;onept.x = x;onept.y = y;onept.z = z;boundpts.push_back(onept);}}pcl::visualization::PCLVisualizer viewer("point connect");viewer.setBackgroundColor(0, 0, 0);//(2)可视化pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);cloud->width = boundpts.size();cloud->height = 1;cloud->is_dense = false;cloud->resize(cloud->width*cloud->height);for (int i = 0; i < cloud->width; i++){cloud->points[i].x = boundpts[i].x;cloud->points[i].y = boundpts[i].y;cloud->points[i].z = boundpts[i].z;}//(3)增加点pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 255, 0, 0);viewer.addPointCloud<pcl::PointXYZ>(cloud, single_color, "sample cloud");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");//(4)增加多边形pcl::PlanarPolygon<pcl::PointXYZ> polygon;pcl::PointCloud<pcl::PointXYZ> contour;contour.width = boundpts.size();contour.height = 1;contour.is_dense = false;contour.resize(contour.height*contour.width);for (int i = 0; i < boundpts.size(); i++){contour.points[i] = boundpts[i];}polygon.setContour(contour);viewer.addPolygon(polygon, 0, 255, 0, "ploygon", 0);while (!viewer.wasStopped()){viewer.spinOnce(1);}
}
无序点连接可视化结果如下,可以发现点之间无序,其顺序与原始点云文件中点的顺序有关,影响厚后续处理。
3.2 可视化排序后点
测试主函数代码如下:
//测试排序后点,将其连接起来
void main()
{//(1)读入边缘点vector<pcl::PointXYZ> boundpts;string filepath = "D:\\testdata\\testdata_01_boud.txt";std::ifstream pointsFile(filepath, std::ios::in);pcl::PointXYZ point;char line[128];double x, y, z;int r, g, b;while (pointsFile.getline(line, sizeof(line))){std::stringstream word(line);word >> x;word >> y;word >> z;word >> r;word >> g;word >> b;point.x = x;point.y = y;point.z = z;if (r == 255 && g == 0 && b == 0)//边缘点(为红色点){pcl::PointXYZ onept;onept.x = x;onept.y = y;onept.z = z;boundpts.push_back(onept);}}//(2)对边缘点排序vector<pcl::PointXYZ> orderpts = Orderpts(boundpts);//(3)对点进行连接,测试点是否排序了pcl::visualization::PCLVisualizer viewer("point connect");viewer.setBackgroundColor(0, 0, 0);//(3)可视化pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);cloud->width = orderpts.size();cloud->height = 1;cloud->is_dense = false;cloud->resize(cloud->width*cloud->height);for (int i = 0; i < cloud->width; i++){cloud->points[i].x = orderpts[i].x;cloud->points[i].y = orderpts[i].y;cloud->points[i].z = orderpts[i].z;}//(4)增加点pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 255, 0, 0);viewer.addPointCloud<pcl::PointXYZ>(cloud, single_color, "sample cloud");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");//(5)增加多边形pcl::PlanarPolygon<pcl::PointXYZ> polygon;pcl::PointCloud<pcl::PointXYZ> contour;contour.width = orderpts.size();contour.height = 1;contour.is_dense = false;contour.resize(contour.height*contour.width);for (int i = 0; i < orderpts.size(); i++){contour.points[i] = orderpts[i];}polygon.setContour(contour);viewer.addPolygon(polygon, 0, 255, 0, "ploygon", 0);while (!viewer.wasStopped()){viewer.spinOnce(1);}
}
可视化结果如下,可以发现点被有序进行排列,是有序形式
4、小结
基于旋转角度进行点云排序的方法,对于图形简单的点云是有效的,比如圆、长方形、三角形等,对于复杂的,如有孔洞形式、有凹凸形式,则该方法不适用。