利用 ransac 算法拟合平面

本文介绍了一种用于从三维数据点中筛选同一平面上数据点的方法——RANSAC算法,并提供了Matlab实现代码。该算法通过随机抽样一致性原理,从数据集中选取样本点拟合平面模型,反复迭代找出包含最多内点的模型。

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

1.前言

最近项目中遇到一个问题, 老板给了一组数据然后要求获取其中处于同一个平面上的数据点的信息, 很明显就是使用ransac 算法进行处理。

2. ransac算法思想

这里我们使用自己的理解来说明下这个算法。
1. 首先我们从给定的数据集中随机挑选几组数据获取一个模型(最好可以保证随机挑选的数据不重复)
2. 将这个拟合方程作用于所有的数据,根据阈值区分出模型的内点和外点信息
3. 重复多次上述操作,挑选出其中包含内点数目最多的模型

具体的关于ransac 的算法说明可以参考 Random sample consensus

3. 具体实现

3.1 实现效果

这里写图片描述
这里写图片描述
这里写图片描述

3.2 具体代码

SimulatePlane.m

%% 利用ransac 方法从一组三维数据点中找到处于同一个平面上的数据点
% @param W3 输入数据点 4 x N
% @return [W, id_best, plane_best, inliner, outliner] 在同一个平面上的物点,
% 挑选的物点在原始数据集中的标号, 最佳拟合平面表示形式(【a, b, c, d】: ax + by + cz + d = 0, 1 X 4),
% 在平面上的内点数目, 不再平面上的外点数目
%

function [W, id_best, plane_best, inliner_best, outliner_best] = SimulatePlane(W3)
    assert(size(W3, 1) == 4, 'please check your input for W3')

    iterations = 0;
    k = 500;
    W3_len = size(W3, 2);
    dis_limit_xishu = 1.3;
    dis_limit = 0.015;
    inliner_best = 0;

    ids_set = [];
    while iterations < k
        %% 随机 4 点获取平面参数
        while 1
            ids = myrand4(1, W3_len);
            % 去重
            if ~ismember(ids, ids_set, 'rows')
                ids_set = [ids_set; ids];
                break;
            end
        end

        A = W3(:, ids)';
        [uu, dd, vv] = svd(A);
        plane = vv(:,end);
        plane = plane ./ plane(end);
        plane = plane';

        %% 计算内点
        dis = abs(plane * W3);
%         dis_limit_best = min(dis_limit_xishu * mean(dis), dis_limit_best);
%        dis_limit_best = min(dis_limit_xishu * mean(dis), dis_limit);
        dis_limit_best = dis_limit;
        inliner = sum(dis < dis_limit_best);
        outliner = sum(dis >= dis_limit_best);

        if inliner > inliner_best
           plane_best = plane;
           inliner_best = inliner;
           outliner_best = outliner;
        end       

        iterations = iterations + 1;
    end

    %% 找到 best_plane 上的内点
    dis = abs(plane_best * W3);
    id_best = find(dis < dis_limit_best);
    W = W3(:, id_best);
end

function [ids] = myrand4(minlimit, maxlimit)
    ids = [];
    count = 0;
    while count < 4
        id = randi([minlimit, maxlimit], 1, 1);
        if ismember(id, ids)
            continue
        end
        ids = [ids, id];
        count = count + 1;
    end
    ids = sort(ids);
end

相应的图形绘制代码:
参考资料:
http://blog.sina.com.cn/s/blog_5cd4cccf0100q90p.html
http://blog.youkuaiyun.com/wangcj625/article/details/6287735/

close all
        figure
        plot3(W3(1, :), W3(2, :), W3(3, :), '*');
        hold on        
        plot3(W(1, :), W(2, :), W(3, :), 'o');
        hold on
        X = min(W3(1, :)) : 0.5 : max(W3(1, :));
        Y = min(W3(2, :)) : 0.5 : max(W3(2, :));
        [x,y] = meshgrid(X, Y);
        z = -(plane(1)*x + plane(2) * y + plane(4))/plane(3);
        surf(x, y, z)
        hold off
### 使用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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值