Cloudcompare 点到平面的距离以及点到平面的投影点

本文详细介绍了CloudCompare软件中计算点云到平面距离及投影点坐标的实现方法。通过源码解读,展示了从点云分块、计算距离到求解投影点坐标的步骤。在距离计算中,软件采用了点到平面距离公式,并考虑了点到最近点的距离,以提高鲁棒性。此外,还讨论了如何在软件中设置参数以获取投影点坐标。
摘要由CSDN通过智能技术生成

引言

在这里插入图片描述 在这里插入图片描述

对比两组点云的相似度,一般都是使用距离来量化重合度-重合度越高越相似。
最简单直接的方法 (左图):求一组点云上的点到另一组点云上最近点的距离,但是由于部分点云的缺失,可能有很大误差。兼顾误差和效率的方法 (中间图),并且对噪声鲁棒:求点到平面的距离1
本文重点介绍Cloudcompare-2.11.3中以下两点:

  • 计算点到平面的距离(平面-由参考点云上的部分点拟合求得)
  • 求得点到平面的投影点坐标

一、软件操作

选中两个点云 -> Tools -> Distances -> Cloud/Cloud Dist:
在这里插入图片描述
设置局部建模为平面,并且选上split X,Y and Z components便于求投影点坐标:
在这里插入图片描述 在这里插入图片描述
然后点计算 -> OK 即可:
在这里插入图片描述
最后保存为txt 选中点云 -> File -> Save:
在这里插入图片描述在这里插入图片描述
建议选中 columns title, 要不然真不知道txt文档每一列是什么意思

二、源码解读

2.1 准备工作

忽略许多if等语句
直入正题 CCLib::DistanceComputationTools::computeCloud2CloudDistance
里面调用八叉树加速搜索计算comparedOctree->executeFunctionForAllCellsAtLevel ,需要选择距离计算方式:

params.localModel == NO_MODEL ? computeCellHausdorffDistance : computeCellHausdorffDistanceWithLocalModel,

大致过程:将点云分为若干个Cell (块),每分好一个Cell就调用计算距离的函数,并创建新的Cell

// 略................... 这里以单线程为例
//for each point
for (; p != m_thePointsAndTheirCellCodes.end(); ++p){
	//check if it belongs to the current cell
	CellCode nextCode = (p->theCode >> bitDec);
	if (nextCode != cell.truncatedCode){
		//if not, we call the user function on the previous cell
		result = (*func)(cell, additionalParameters, &nprogress);
		if (!result)
			break;

		//and we start a new cell
		cell.index += cell.points->size();
		cell.points->clear();
		cell.truncatedCode = nextCode;
	}
	cell.points->addPointIndex(p->theIndex); 
}
//don't forget last cell!
if (result)
	result = (*func)(cell, additionalParameters, &nprogress);
// 略...................

*func计算距离的函数,点到平面的距离函数为computeCellHausdorffDistanceWithLocalModel

2.2 计算距离

computeCellHausdorffDistanceWithLocalModel中会计算Cell中每个点云到参考点云的距离
主要包含三个部分:初始化、局部建模 (local model)、距离计算
需要注意:每个点云对应参考点云的一个local model,但是local model可对应多个点云 (避免重复计算)。
重点关注距离计算

  • 没有local model就退化成了最近点距离
  • 有local model计算点到平面的距离 distToModel
  • 如果点到参考点上最近点的距离 distToNearestPoint 小于 distToModel,那么就用distToNearestPoint (稳健)
//if we have a local model
if (lm)
{
	CCVector3 nearestModelPoint;
	ScalarType distToModel = lm->computeDistanceFromModelToPoint(&nNSS.queryPoint, computeSplitDistances ? &nearestModelPoint : nullptr);

	//we take the best estimation between the nearest neighbor and the model!
	//this way we only reduce any potential noise (that would be due to sampling)
	//instead of 'adding' noise if the model is badly shaped
	if (distToNearestPoint <= distToModel)
	{
		distPt = distToNearestPoint;
	}
	else
// 略.......................

具体计算点到平面的距离,就是这个公式了2:点到平面距离

ScalarType DistanceComputationTools::computePoint2PlaneDistance(const CCVector3* P,
																const PointCoordinateType* planeEquation)
{
	//point to plane distance: d = (a0*x+a1*y+a2*z - a3) / sqrt(a0^2+a1^2+a2^2)
	assert(std::abs(CCVector3::vnorm(planeEquation) - PC_ONE) <= std::numeric_limits<PointCoordinateType>::epsilon());

	return static_cast<ScalarType>((CCVector3::vdot(P->u, planeEquation) - planeEquation[3])/*/CCVector3::vnorm(planeEquation)*/); //norm == 1.0!
}

2.3 投影点坐标

2.2末尾提到了computePoint2PlaneDistance,知道距离dist (可能是负的) 以后就可以求投影点坐标:

ScalarType computeDistanceFromModelToPoint(const CCVector3* P, CCVector3* nearestPoint = nullptr) const override{
	ScalarType dist = DistanceComputationTools::computePoint2PlaneDistance(P, m_eq);
	if (nearestPoint){       // dist在三个轴平面上的投影长度
		*nearestPoint = *P - dist * CCVector3(m_eq);
	}
	return std::abs(dist);
}

点到投影点的向量和平面的法向量是平行的,可以手推公式。或者简单点画个图就明白了:核心就是求dist在三个坐标轴平面的投影 d i s t ⋅ C C V e c t o r 3 ( m e q ) dist \cdot CCVector3(m_eq) distCCVector3(meq),注意平面法向量(m_eq前三个数)已经是归一化后的

  • 源码并没有保存投影点的坐标 nearestPoint,而是变成了相对点坐标的三个分量 X, Y, Z的距离。所以选择split X,Y and Z components之后,求投影点坐标还需要逆操作:
    n e a r e s t P o i n t = n N S S . q u e r y P o i n t − ( X , Y , Z ) nearestPoint = nNSS.queryPoint - (X, Y, Z) nearestPoint=nNSS.queryPoint(X,Y,Z)
if (computeSplitDistances){
	unsigned index = cell.points->getPointGlobalIndex(i);
	if (params->splitDistances[0])
		params->splitDistances[0]->setValue(index, static_cast<ScalarType>(nNSS.queryPoint.x - nearestPoint.x));
	if (params->splitDistances[1])
		params->splitDistances[1]->setValue(index, static_cast<ScalarType>(nNSS.queryPoint.y - nearestPoint.y));
	if (params->splitDistances[2])
		params->splitDistances[2]->setValue(index, static_cast<ScalarType>(nNSS.queryPoint.z - nearestPoint.z));
}

  1. cloudcompare - Distances_Computation官方说明 ↩︎

  2. 点到平面距离 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大米粥哥哥

感谢认可!

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

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

打赏作者

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

抵扣说明:

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

余额充值