CloudCompare——拟合空间球

这篇具有很好参考价值的文章主要介绍了CloudCompare——拟合空间球。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

CloudCompare——拟合空间球,CloudCompare,c++,算法,开发语言,3d,计算机视觉

本文由CSDN点云侠原创,CloudCompare——拟合空间球,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT生成的文章。

1.拟合球

  源码里用到了四点定球,具体计算原理如下

  已知空间内不共面的四个点,设其坐标为 A ( x 1 , y 1 , z 1 ) A(x_1,y_1,z_1) A(x1,y1,z1) B ( x 2 , y 2 , z 2 ) B(x_2,y_2,z_2) B(x2,y2,z2) C ( x 3 , y 3 , z 3 ) 、 D ( x 4 , y 4 , z 4 ) C(x_3,y_3,z_3)、D(x_4,y_4,z_4) C(x3,y3,z3)D(x4,y4,z4),设半径为 r r r,球心 O O O坐标为 ( x , y , z ) (x,y,z) (x,y,z)。利用四点到球心距离相等的性质得到如下四个方程。
( x − x 1 ) 2 + ( y − y 1 ) 2 + ( z − z 1 ) 2 = r 2 ; ( x − x 2 ) 2 + ( y − y 2 ) 2 + ( z − z 2 ) 2 = r 2 ; ( x − x 3 ) 2 + ( y − y 3 ) 2 + ( z − z 3 ) 2 = r 2 ; ( x − x 4 ) 2 + ( y − y 4 ) 2 + ( z − z 4 ) 2 = r 2 ; (x-x_1)^2 + (y-y_1)^2 +(z-z_1)^2 =r^2;\\ (x-x_2)^2 + (y-y_2)^2 +(z-z_2)^2 =r^2;\\ (x-x_3)^2 + (y-y_3)^2 +(z-z_3)^2 =r^2;\\ (x-x_4)^2 + (y-y_4)^2 +(z-z_4)^2 =r^2; (xx1)2+(yy1)2+(zz1)2=r2;(xx2)2+(yy2)2+(zz2)2=r2;(xx3)2+(yy3)2+(zz3)2=r2;(xx4)2+(yy4)2+(zz4)2=r2;

展开得:
x 2 + y 2 + z 2 − 2 ( x 1 x + y 1 y + z 1 z ) + x 1 2 + y 1 2 + z 1 2 = r 2 ① x 2 + y 2 + z 2 − 2 ( x 2 x + y 2 y + z 2 z ) + x 2 2 + y 2 2 + z 2 2 = r 2 ② x 2 + y 2 + z 2 − 2 ( x 3 x + y 3 y + z 3 z ) + x 3 2 + y 3 2 + z 3 2 = r 2 ③ x 2 + y 2 + z 2 − 2 ( x 4 x + y 4 y + z 4 z ) + x 4 2 + y 4 2 + z 4 2 = r 2 ④ x^2 + y^2 + z^2- 2(x_1x+y_1y+z_1z)+x_1^2+y_1^2 + z_1^2 = r^2 ①\\ x^2 + y^2 + z^2- 2(x_2x+y_2y+z_2z)+x_2^2+y_2^2 + z_2^2 = r^2②\\ x^2 + y^2 + z^2- 2(x_3x+y_3y+z_3z)+x_3^2+y_3^2 + z_3^2 = r^2③\\ x^2 + y^2 + z^2- 2(x_4x+y_4y+z_4z)+x_4^2+y_4^2 + z_4^2 = r^2④ x2+y2+z22(x1x+y1y+z1z)+x12+y12+z12=r2x2+y2+z22(x2x+y2y+z2z)+x22+y22+z22=r2x2+y2+z22(x3x+y3y+z3z)+x32+y32+z32=r2x2+y2+z22(x4x+y4y+z4z)+x42+y42+z42=r2

分别作①-②、③ - ④、② - ③得:
( x 1 − x 2 ) x + ( y 1 − y 2 ) y + ( z 1 − z 2 ) z = 1 / 2 ( x 1 2 − x 2 2 + y 1 2 − y 2 2 + z 1 2 − z 2 2 ) ( x 3 − x 4 ) x + ( y 3 − y 4 ) y + ( z 3 − z 4 ) z = 1 / 2 ( x 3 2 − x 4 2 + y 3 2 − y 4 2 + z 3 2 − z 4 2 ) ( x 2 − x 3 ) x + ( y 2 − y 3 ) y + ( z 2 − z 3 ) z = 1 / 2 ( x 2 2 − x 3 2 + y 2 2 − y 3 2 + z 2 2 − z 3 2 ) (x_1-x_2)x+(y_1-y_2)y+(z_1-z_2)z=1/2(x_1^2 -x_2^2 + y_1^2 -y_2^2 + z_1^2 -z_2^2 )\\ (x_3-x_4)x+(y_3-y_4)y+(z_3-z_4)z=1/2(x_3^2 -x_4^2 + y_3^2 -y_4^2 + z_3^2 -z_4^2 )\\ (x_2-x_3)x+(y_2-y_3)y+(z_2-z_3)z=1/2(x_2^2 -x_3^2 + y_2^2 -y_3^2 + z_2^2 -z_3^2 )\\ (x1x2)x+(y1y2)y+(z1z2)z=1/2(x12x22+y12y22+z12z22)(x3x4)x+(y3y4)y+(z3z4)z=1/2(x32x42+y32y42+z32z42)(x2x3)x+(y2y3)y+(z2z3)z=1/2(x22x32+y22y32+z22z32)

其对应的系数行列式可设为:

D = ∣ a b c a 1 b 1 c 1 a 2 b 2 c 2 ∣ D=\left| \begin{matrix} a & b & c\\ a_1 & b_1 & c_1 \\ a_2 & b_2 & c_2 \end{matrix} \right| D= aa1a2bb1b2cc1c2

则: a = ( x 1 − x 2 ) , b = ( y 1 − y 2 ) , c = ( z 1 − z 2 ) , a 1 = ( x 3 − x 4 ) , b 1 = ( y 3 − y 4 ) , c 1 = ( z 3 − z 4 ) , a 2 = ( x 2 − x 3 ) , b 2 = ( y 2 − y 3 ) , c 2 = ( z 2 − z 3 ) a=(x_1-x_2),b=(y_1-y_2),c=(z_1-z_2),\\a_1=(x_3-x_4),b_1=(y_3-y_4),c_1=(z_3-z_4),\\ a_2=(x_2-x_3),b_2=(y_2-y_3),c_2=(z_2-z_3) a=(x1x2),b=(y1y2),c=(z1z2),a1=(x3x4),b1=(y3y4)c1=(z3z4),a2=(x2x3),b2=(y2y3)c2=(z2z3)

常数项行列式为:

L = ∣ P Q R ∣ L=\left| \begin{matrix} P\\ Q \\ R \end{matrix} \right| L= PQR

则:
P = 1 2 ( x 1 2 − x 2 2 + y 1 2 − y 2 2 + z 1 2 − z 2 2 ) P=\frac{1}{2}(x_1^2 -x_2^2 + y_1^2 -y_2^2 + z_1^2 - z_2^2 ) P=21(x12x22+y12y22+z12z22)
Q = 1 2 ( x 3 2 − x 4 2 + y 3 2 − y 4 2 + z 3 2 − z 4 2 ) Q=\frac{1}{2}(x_3^2 -x_4^2 + y_3^2 -y_4^2 + z_3^2 - z_4^2 ) Q=21(x32x42+y32y42+z32z42)
R = 1 2 ( x 2 2 − x 3 2 + y 2 2 − y 3 2 + z 2 2 − z 3 2 ) R=\frac{1}{2}(x_2^2 -x_3^2 + y_2^2 -y_3^2 + z_2^2 - z_3^2 ) R=21(x22x32+y22y32+z22z32)

现设:
D x = ∣ P b c Q b 1 c 1 R b 2 c 2 ∣ Dx=\left| \begin{matrix} P & b & c\\ Q & b_1 & c_1 \\ R & b_2 & c_2 \end{matrix} \right| Dx= PQRbb1b2cc1c2

D y = ∣ a P c a 1 Q c 1 a 2 R c 2 ∣ Dy=\left| \begin{matrix} a & P & c\\ a_1 & Q & c_1 \\ a_2 &R & c_2 \end{matrix} \right| Dy= aa1a2PQRcc1c2

D z = ∣ a b P a 1 b 1 Q a 2 b 2 R ∣ Dz=\left| \begin{matrix} a & b & P\\ a_1 & b_1 & Q \\ a_2 &b_2 & R \end{matrix} \right| Dz= aa1a2bb1b2PQR

由线性代数中的克拉默法则可知:
x = D x D x=\frac{Dx}{D} x=DDx

y = D y D y=\frac{Dy}{D} y=DDy

z = D z D z=\frac{Dz}{D} z=DDz

2.软件操作

  通过菜单栏的'Tools > Fit > Sphere'找到该功能。
CloudCompare——拟合空间球,CloudCompare,c++,算法,开发语言,3d,计算机视觉

  选择一个或多个点云,然后启动此工具。CloudCompare将在每个点云上拟合球体基元。在控制台中,将输出以下信息:

  • center(也可以在球体实体属性中找到球体边界框的中心)
  • radius(也可以在sphere实体属性中找到)
  • 球体拟合RMS(在默认球体实体名称中调用)注意:理论上球体拟合算法可以处理高达50%的异常值。

球形点云
CloudCompare——拟合空间球,CloudCompare,c++,算法,开发语言,3d,计算机视觉
拟合结果
CloudCompare——拟合空间球,CloudCompare,c++,算法,开发语言,3d,计算机视觉
控制台输出
CloudCompare——拟合空间球,CloudCompare,c++,算法,开发语言,3d,计算机视觉

3.算法源码

GeometricalAnalysisTools::ErrorCode GeometricalAnalysisTools::DetectSphereRobust(
	GenericIndexedCloudPersist* cloud,
	double outliersRatio,
	CCVector3& center,
	PointCoordinateType& radius,
	double& rms,
	GenericProgressCallback* progressCb/*=nullptr*/,
	double confidence/*=0.99*/,
	unsigned seed/*=0*/)
{
	if (!cloud)
	{
		assert(false);
		return InvalidInput;
	}

	unsigned n = cloud->size();
	if (n < 4)
		return NotEnoughPoints;

	assert(confidence < 1.0);
	confidence = std::min(confidence, 1.0 - FLT_EPSILON);

	//we'll need an array (sorted) to compute the medians
	std::vector<PointCoordinateType> values;
	try
	{
		values.resize(n);
	}
	catch (const std::bad_alloc&)
	{
		//not enough memory
		return NotEnoughMemory;
	}

	//number of samples
	unsigned m = 1;
	const unsigned p = 4;
	if (n > p)
	{
		m = static_cast<unsigned>(log(1.0 - confidence) / log(1.0 - pow(1.0 - outliersRatio, static_cast<double>(p))));
	}

	//for progress notification
	NormalizedProgress nProgress(progressCb, m);
	if (progressCb)
	{
		if (progressCb->textCanBeEdited())
		{
			char buffer[64];
			sprintf(buffer, "Least Median of Squares samples: %u", m);
			progressCb->setInfo(buffer);
			progressCb->setMethodTitle("Detect sphere");
		}
		progressCb->update(0);
		progressCb->start();
	}

	//now we are going to randomly extract a subset of 4 points and test the resulting sphere each time
	if (seed == 0)
	{
		std::random_device randomGenerator;   // non-deterministic generator
		seed = randomGenerator();
	}
	std::mt19937 gen(seed);  // to seed mersenne twister.
	std::uniform_int_distribution<unsigned> dist(0, n - 1);
	unsigned sampleCount = 0;
	unsigned attempts = 0;
	double minError = -1.0;
	std::vector<unsigned> indexes;
	indexes.resize(p);
	while (sampleCount < m && attempts < 2*m)
	{
		//get 4 random (different) indexes
		for (unsigned j = 0; j < p; ++j)
		{
			bool isOK = false;
			while (!isOK)
			{
				indexes[j] = dist(gen);
				isOK = true;
				for (unsigned k = 0; k < j && isOK; ++k)
					if (indexes[j] == indexes[k])
						isOK = false;
			}
		}

		assert(p == 4);
		const CCVector3* A = cloud->getPoint(indexes[0]);
		const CCVector3* B = cloud->getPoint(indexes[1]);
		const CCVector3* C = cloud->getPoint(indexes[2]);
		const CCVector3* D = cloud->getPoint(indexes[3]);

		++attempts;
		CCVector3 thisCenter;
		PointCoordinateType thisRadius;
		if (ComputeSphereFrom4(*A, *B, *C, *D, thisCenter, thisRadius) != NoError)
			continue;

		//compute residuals
		for (unsigned i = 0; i < n; ++i)
		{
			PointCoordinateType error = (*cloud->getPoint(i) - thisCenter).norm() - thisRadius;
			values[i] = error*error;
		}
		
		const unsigned int	medianIndex = n / 2;

		std::nth_element(values.begin(), values.begin() + medianIndex, values.end());

		//the error is the median of the squared residuals
		double error = static_cast<double>(values[medianIndex]);

		//we keep track of the solution with the least error
		if (error < minError || minError < 0.0)
		{
			minError = error;
			center = thisCenter;
			radius = thisRadius;
		}

		++sampleCount;

		if (progressCb && !nProgress.oneStep())
		{
			//progress canceled by the user
			return ProcessCancelledByUser;
		}
	}

	//too many failures?!
	if (sampleCount < m)
	{
		return ProcessFailed;
	}

	//last step: robust estimation
	ReferenceCloud candidates(cloud);
	if (n > p)
	{
		//e robust standard deviation estimate (see Zhang's report)
		double sigma = 1.4826 * (1.0 + 5.0 /(n-p)) * sqrt(minError);

		//compute the least-squares best-fitting sphere with the points
		//having residuals below 2.5 sigma
		double maxResidual = 2.5 * sigma;
		if (candidates.reserve(n))
		{
			//compute residuals and select the points
			for (unsigned i = 0; i < n; ++i)
			{
				PointCoordinateType error = (*cloud->getPoint(i) - center).norm() - radius;
				if (error < maxResidual)
					candidates.addPointIndex(i);
			}
			candidates.resize(candidates.size());

			//eventually estimate the robust sphere parameters with least squares (iterative)
			if (RefineSphereLS(&candidates, center, radius))
			{
				//replace input cloud by this subset!
				cloud = &candidates;
				n = cloud->size();
			}
		}
		else
		{
			//not enough memory!
			//we'll keep the rough estimate...
		}
	}

	//update residuals
	{
		double residuals = 0;
		for (unsigned i = 0; i < n; ++i)
		{
			const CCVector3* P = cloud->getPoint(i);
			double e = (*P - center).norm() - radius;
			residuals += e*e;
		}
		rms = sqrt(residuals/n);
	}

	return NoError;
}

4.相关代码

[1]C++实现:PCL RANSAC拟合空间3D球体
[2]python实现:Open3D——RANSAC三维点云球面拟合
[3] Open3D 最小二乘拟合球
[4] Open3D 非线性最小二乘拟合球文章来源地址https://www.toymoban.com/news/detail-785575.html

到了这里,关于CloudCompare——拟合空间球的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CloudCompare 二次开发(6)——插件中拖拽添加Qt窗口(区域生长算法为例)

    本文由CSDN点云侠原创,原文链接。爬虫网站自重。   手动拖拽的方式搭建Qt对话框界面的制作流程,以PCL中的点云区域生长算法为例进行制作。 1、将 ....pluginsexample 路径下的 ExamplePlugin 复制一份并修改名字为 CCPointCloudProcess 。 2、创建窗口UI文件 使用任意Qt工程新建对话

    2023年04月11日
    浏览(56)
  • 使用RANSAC算法在点云中拟合原始3D形状:pyRANSAC-3D的介绍和应用

    随机样本共识(RANSAC)是一种强大的算法,用于从数据集中估计数学模型的参数,特别是在数据包含大量异常值时。在3D计算机视觉中,RANSAC常用于从点云数据中拟合原始形状,例如平面、长方体和圆柱体。本文将介绍一个名为pyRANSAC-3D的开源库,它提供了RANSAC算法的Python实现

    2024年02月13日
    浏览(35)
  • QT6+CloudCompare显示3D点云

        CloudCompare是一个三维点云(网格)编辑和处理软件。最初,它被设计用来对稠密的三维点云进行直接比较。它依赖于一种特定的八叉树结构,在进行点云对比这类任务时具有出色的性能。此外,由于大多数点云都是由地面激光扫描仪采集的,CloudCompare的目的是在一台标准

    2023年04月08日
    浏览(48)
  • 苦于实现3D空间自动布局的同学,请参考:3D室内空间布局自动化算法分析(含源码)

    分两步生成给定房间的家具布置: 第一步:根据美学和功能规则,优化房间中家具对象的选择和布置。此过程通过【贪婪成本最小化算法】快速探索家具布局的无限跨维空间 根据室内设计规则形成的成本函数优化全局家具布局和对象选择。在此优化过程中,家具布置会因特

    2024年04月29日
    浏览(69)
  • 【3维视觉】3D空间常用算法(点到直线距离、面法线、二面角)

    3D空间点到直线的距离 三维空间有三个基本元素,点,线,面。那么曲率是如何定义的呢? 点的曲率? 线的曲率? 面的曲率? 设曲面上的曲线在某一点处的切向量为df(X),曲面在这一点处的法向量为N。则曲线的法曲率就是曲线在df(X)和N张成的平面上的投影曲线的曲率。 在

    2024年02月10日
    浏览(39)
  • visionOS空间计算实战开发教程Day 2 使用RealityKit显示3D素材

    我们在​​Day1​​中学习了如何创建一个visionOS应用,但在第一个Demo应用中我们的界面内容还是2D的,看起来和其它应用并没有什么区别。接下来我们先学习如何展示3D素材,苹果为方便开发人员,推出了RealityKit,接下来看如何使用。 首先我们需要一个3D素材,Apple在​​Q

    2024年02月05日
    浏览(35)
  • 三维空间离散点如何拟合平面?

      在点云建模过程中,有时需要对扫描建模的点云进行标定,在实际使用中往往以地面做为参照平面,需要将扫描的三维空间点云进行拟合平面,以便纠正扫描结果。本文对三维空间离散点拟合平面算法进行总结,并给出几种编程语言下的算法实现代码。    (1)最小二

    2024年02月11日
    浏览(46)
  • 计算机语言 之【C++】入门级知识讲解(命名空间,C++输入输出,缺省参数,函数重载,引用,内敛函数,auto关键字,for循环,指针空值nullptr)

    三点睡六点起,阎王夸我好身体 不到三点我不睡,太平间里抢C位 目录: 前言: 本片博客是以学习过C语言之后进入C++学习为前提,讲解C++入门级知识,为C++之后的学习做铺垫 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀

    2024年04月11日
    浏览(134)
  • CloudCompare 二次开发(26)——RANSAC分割多个平面

      使用CloudCompare与PCL编程实现的RANSAC分割多个平面。具体计算原理见:PCL RANSAC分割多个平面。 1、 mainwindow.h 文件 public 中添加: 2、 mainwindow.cpp 文件 void MainWindow::connectActions() 函数中添加:

    2024年01月25日
    浏览(44)
  • CloudCompare 二次开发(13)——点云投影到圆柱

      不依赖任何第三方点云相关库,使用CloudCompare编程实现点云投影到指定圆柱,具体计算原理见:PCL 点云投影到圆柱 1、 mainwindow.h 文件 public 中添加: 2、 mainwindow.cpp 文件 void MainWindow::connectActions() 函数中添加:

    2024年02月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包