RANSAC算法拟合平面实现

该博客介绍了基于RANSAC(随机样本一致)算法的平面检测原理和实现过程。首先确定迭代次数,然后在每次迭代中随机选取三个点构建平面方程,并计算所有点到平面的距离,统计符合阈值的点(inliers)。通过比较各次迭代得到的inliers数量,选择最多的作为最佳平面。提供的代码实现了这一过程,适用于点云数据的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理:---------------基于ransac算法平面检测:
1、确定迭代次数;
2、在迭代次数内:
2.1 随机选择三个点组成平面(判断三个点是否共线);
2.2 构造坐标矩阵;
2.3 求平面方程;
2.4 求所有点到平面的距离;
2.5 统计inlier个数(距离小于阈值);
3、迭代选择inlier个数最多的平面。

已知三个点坐标为P1(x1,y1,z1), P2(x2,y2,z2), P3(x3,y3,z3),求过他们的平面方程:
设方程为A(x - x1) + B(y - y1) + C(z - z1) = 0 (点法式) (也可设为过另外两个点),则有
A = (y3 - y1)(z3 - z1) - (z2 -z1)(y3 - y1);
B = (x3 - x1)(z2 - z1) - (x2 - x1)(z3 - z1);
C = (x2 - x1)(y3 - y1) - (x3 - x1)(y2 - y1);

实现:

/**
 * @description:	RANSAC算法拟合平面
 * @param cloud		输入点云
 * @param max_iter	最大迭代次数
 * @param threshold	距离阈值
 */
void ransac(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, int max_iter, float threshold)
{
	srand(time(0)); 
	int size_old = 3;
	double a_final, b_final, c_final, d_final; 

	while (--max_iter) 
	{
		std::vector<int> index;
		for (int k = 0; k < 3; ++k)
		{
			index.push_back(rand() % cloud->size());
		}		
		auto idx = index.begin();
		double x1 = cloud->points[*idx].x, y1 = cloud->points[*idx].y, z1 = cloud->points[*idx].z; 
		++idx;
		double x2 = cloud->points[*idx].x, y2 = cloud->points[*idx].y, z2 = cloud->points[*idx].z;
		++idx;
		double x3 = cloud->points[*idx].x, y3 = cloud->points[*idx].y, z3 = cloud->points[*idx].z;

		double a = (y2 - y1)*(z3 - z1) - (z2 - z1)*(y3 - y1);
		double b = (z2 - z1)*(x3 - x1) - (x2 - x1)*(z3 - z1);
		double c = (x2 - x1)*(y3 - y1) - (y2 - y1)*(x3 - x1);
		double d = -(a*x1 + b*y1 + c*z1);

		for (auto iter = cloud->begin(); iter != cloud->end(); ++iter)
		{ 
			double dis = fabs(a*iter->x + b*iter->y + c*iter->z + d) / sqrt(a*a + b*b + c*c);
			if (dis < threshold)	index.push_back(iter - cloud->begin());
		}

		if (index.size() > size_old)
		{
			size_old = index.size();
			a_final = a; b_final = b; c_final = c; d_final = d;
		}
	}
    std::cout << a_final << " " << b_final << " " << c_final << " " << d_final << std::endl;
}

代码传送门:https://github.com/taifyang/PCL-algorithm

### 使用RANSAC算法进行平面拟合 #### 平面拟合原理概述 RANSAC(Random Sample Consensus)是一种迭代方法,旨在从一组观测数据中估计数学模型的参数,特别适用于存在大量异常值的情况。对于平面拟合任务而言,目标是从三维空间中的点集中找出最能代表这些点的一个平面。 具体来说,在每次迭代过程中,随机选取三个不共线的点来定义一个假设的平面,并计算其余所有点到此平面上的距离。如果某个点到该平面的距离小于设定的阈值,则认为这个点属于内点集(inliers)。经过多轮这样的操作之后,拥有最多内点的那个平面即被认为是最优解[^1]。 #### Python 实现示例 下面展示了一个使用Python和NumPy库实现简单版RANSAC来进行平面拟合的例子: ```python import numpy as np def fit_plane_ransac(points, threshold=0.01, max_iterations=1000): best_inliers = None best_model = None n_points = points.shape[0] for _ in range(max_iterations): # Randomly select three non-collinear points to form a plane. indices = np.random.choice(n_points, size=3, replace=False) p1, p2, p3 = points[indices] # Check collinearity by computing the volume of parallelepiped formed by vectors (p2- p1 v2 = p3 - p1 cross_product = np.cross(v1, v2) if np.linalg.norm(cross_product) < 1e-6: continue normal_vector = cross_product / np.linalg.norm(cross_product) d = -np.dot(normal_vector, p1) model_parameters = (*normal_vector, d) distances = abs(np.dot(points, normal_vector) + d) current_inliers = points[(distances <= threshold)] if best_inliers is None or len(current_inliers) > len(best_inliers): best_inliers = current_inliers.copy() best_model = model_parameters return best_model, best_inliers if __name__ == "__main__": from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111, projection='3d') # Generate some sample data with noise and outliers. X, Y = np.meshgrid(range(-5, 5), range(-5, 5)) Z_clean = 2 * X + 3 * Y + 7 Z_noisy = Z_clean + np.random.normal(scale=0.5, size=X.shape) outlier_indices = np.random.randint(low=0, high=len(Z_noisy.ravel()), size=int(len(Z_noisy.ravel())*0.1)) Z_outliers = np.zeros_like(Z_noisy).ravel() Z_outliers[outlier_indices] += np.random.uniform(low=-10., high=10., size=outlier_indices.size) Z_final = Z_noisy.ravel() + Z_outliers.reshape(X.shape) point_cloud = np.vstack((X.ravel(), Y.ravel(), Z_final)).T fitted_params, inliers = fit_plane_ransac(point_cloud) A, B, C, D = fitted_params xx, yy = np.meshgrid([-10, 10], [-10, 10]) zz = (-A * xx - B * yy - D) / C ax.scatter(*point_cloud.T, c="blue", marker="o", label="Original Points") ax.plot_surface(xx, yy, zz, alpha=.5, color="red") plt.show() ``` 这段代码首先生成了一些带有噪声和平面外离群点的人工数据作为测试样本。接着调用了`fit_plane_ransac()`函数执行RANSAC过程寻找最优平面,并最终绘制出了原始散点图以及由RANSAC得到的最佳拟合平面图像[^2]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

给算法爸爸上香

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

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

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

打赏作者

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

抵扣说明:

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

余额充值