简单形状点云轮廓点排序(旋转角)

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、测试

       源代码下载链接:轮廓点排序程序(c++ )

 本程序在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、小结

   基于旋转角度进行点云排序的方法,对于图形简单的点云是有效的,比如圆、长方形、三角形等,对于复杂的,如有孔洞形式、有凹凸形式,则该方法不适用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点云实验室lab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值