当前位置:   article > 正文

C++三维点云底面缺损简单识别和修补_三维点云空洞修复

三维点云空洞修复

C++三维点云底面简单识别和修补

前言

三维点云的应用中,经常需要识别底面(如体积计算的参考平面、基坑测量等);而底面点云如果出现缺损、空洞时,又会影响计算,就需要进行修补。

本文通过最简单的方式,快速找到底面并进行修补。当然,由于过于简单,存在着很多限制,比如底面必须位于Z轴最下端,或者可以旋转到Z轴;又比如底面必须是平面。

底面识别

底面识别主要步骤:
1.将点云进行旋转,使Z轴与待修补面垂直;
2.根据一定的X和Y范围,对点云进行分块;
3.统计每个分块的点云信息;
4.同时满足 a)分块内点云最大Z值和最小Z值偏差小于某个值,b)分块内点云数量大于某个值,两个条件的,认定为平面;
5.遍历所有平面,Z值均值最小的平面认定为底面。

  1. 定义统计信息;
// 统计信息
struct data
{
public:
	data()
	{
		i = 0;
		j = 0;
		count = 0;
	}

	int i;			// X坐标索引
	int j;			// Y坐标索引
	int count;		// 统计点数,用于过滤孤立点
	float min;		// 统计X、Y坐标索引范围内点云Z的最小值
	float max;	// 统计X、Y坐标索引范围内点云Z的最大值
	float mean;	// 统计X、Y坐标索引范围内点云Z的平均值
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  1. 处理点云,统计分块点云信息;
// 统计信息
vector<data> vecData;

// 取x和y的整数部分作为索引,相当于将点云分成1m*1m的块
int indexX = tmp_x;
int indexY = tmp_y;
bool found = false;
for(int n = 0; n < vecData.size(); n++)
{
	if (vecData[n].i == indexX && vecData[n].j == indexY)// 队列中已经存在的块
	{
		// 更新统计值
		vecData[n].count = vecData[n].count + 1;
		vecData[n].min = (vecData[n].min > tmp_z) ? tmp_z : vecData[n].min;
		vecData[n].max = (vecData[n].max < tmp_z) ? tmp_z : vecData[n].max;
		vecData[n].mean = (vecData[n].mean * (vecData[n].count - 1) + tmp_z) / vecData[n].count ;
		found = true;
	} 
}

// 队列中不存在的块
if (!found)
{
	data d;
	d.i = tmp_x;
	d.j = tmp_y;
	d.count = 1;
	d.min = tmp_z;
	d.max = tmp_z;
	d.mean = tmp_z;
	vecData.push_back(d);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  1. 根据统计的点云信息,找到底面
// 查找最低平面的Z值
float minZ = 1000;
for(int k = 0; k < vecData.size(); k++)
{
	// 根据点数、最大值、最小值判断是否为有效平面
	if (vecData[k].count > 100 && vecData[k].max - vecData[k].min < 0.1)
	{
		minZ = (minZ > vecData[k].mean) ? vecData[k].mean : minZ;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

平面修补

按照一定的分辨率,使用找到的最小Z值修补平面

float VirtualX = -20;// x范围(本例为-20到0)
float VirtualY = -40;// y范围(本例为-40到0)
while(VirtualY < 0)
{
	while(VirtualX < 0)
	{
		// 模拟点云
		float x = VirtualX;
		float y = VirtualY;
		float z = minZ;
		
		VirtualX += 0.1;// 按照0.1m的分辨率填充
	}
	VirtualX = -20;
	VirtualY += 0.1;// 按照0.1m的分辨率填充
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

说明

  1. 平面修补改为for循环可能更容易理解;
  2. 平面修补范围可以任意设置,可以CreatePolygonRgn函数进行多边形修补。

效果图

  1. 修补前
    修补前点云
  2. 修补后
    修补后点云修补后点云

源代码

虽然源代码比较简单,而且基本上都在本文正文中,但是鉴于近期不少人索要源码,所有提供积分下载方式:源代码

没有积分的,也可以继续评论索要,我看到了就会发送。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/606357
推荐阅读
相关标签
  

闽ICP备14008679号