ransac拟合平面,代替open3d的segment_plane

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

0.open3d打包太大了,所以决定网上找找代码

使用open3d拟合平面并且求平面的法向量,open3d打包大概1个g的大小。

import open3d as o3d
  pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(points)

    #
    # 使用RANSAC算法拟合平面
    plane_model, inliers = pcd.segment_plane(
        distance_threshold, ransac_n, num_iterations, probability
    )
     plane_normal = np.array(plane_model[:3])
    plane_normal /= np.linalg.norm(plane_normal)
    X_normal = [1, 0, 0]
    Y_normal = [0, 1, 0]
    Z_normal = [0, 0, 1]
    # 计算夹角(单位为弧度)
    angle = np.arccos(np.dot(plane_normal, X_normal))
    # 将夹角转换为角度
    X_angel = degrees(angle)

    # 计算夹角(单位为弧度)
    angle = np.arccos(np.dot(plane_normal, Y_normal))
    # 将夹角转换为角度
    Y_angel = degrees(angle)

    # 计算夹角(单位为弧度)
    angle = np.arccos(np.dot(plane_normal, Z_normal))
    # 将夹角转换为角度
    Z_angel = degrees(angle)

1.找了一个git上的代码

https://github.com/leomariga/pyRANSAC-3D/blob/master/pyransac3d/plane.py

import random

import numpy as np


class Plane:
    """
    Implementation of planar RANSAC.

    Class for Plane object, which finds the equation of a infinite plane using RANSAC algorithim.

    Call `fit(.)` to randomly take 3 points of pointcloud to verify inliers based on a threshold.

    ![Plane](https://raw.githubusercontent.com/leomariga/pyRANSAC-3D/master/doc/plano.gif "Plane")

    ---
    """

    def __init__(self):
        self.inliers = []
        self.equation = []

    def fit(self, pts, thresh=0.05, minPoints=100, maxIteration=1000):
        """
        Find the best equation for a plane.

        :param pts: 3D point cloud as a `np.array (N,3)`.
        :param thresh: Threshold distance from the plane which is considered inlier.
        :param maxIteration: Number of maximum iteration which RANSAC will loop over.
        :returns:
        - `self.equation`:  Parameters of the plane using Ax+By+Cy+D `np.array (1, 4)`
        - `self.inliers`: points from the dataset considered inliers

        ---
        """
        n_points = pts.shape[0]
        best_eq = []
        best_inliers = []

        for it in range(maxIteration):

            # Samples 3 random points
            id_samples = random.sample(range(0, n_points), 3)
            pt_samples = pts[id_samples]

            # We have to find the plane equation described by those 3 points
            # We find first 2 vectors that are part of this plane
            # A = pt2 - pt1
            # B = pt3 - pt1

            vecA = pt_samples[1, :] - pt_samples[0, :]
            vecB = pt_samples[2, :] - pt_samples[0, :]

            # Now we compute the cross product of vecA and vecB to get vecC which is normal to the plane
            vecC = np.cross(vecA, vecB)

            # The plane equation will be vecC[0]*x + vecC[1]*y + vecC[0]*z = -k
            # We have to use a point to find k
            vecC = vecC / np.linalg.norm(vecC)
            k = -np.sum(np.multiply(vecC, pt_samples[1, :]))
            plane_eq = [vecC[0], vecC[1], vecC[2], k]

            # Distance from a point to a plane
            # https://mathworld.wolfram.com/Point-PlaneDistance.html
            pt_id_inliers = []  # list of inliers ids
            dist_pt = (
                plane_eq[0] * pts[:, 0] + plane_eq[1] * pts[:, 1] + plane_eq[2] * pts[:, 2] + plane_eq[3]
            ) / np.sqrt(plane_eq[0] ** 2 + plane_eq[1] ** 2 + plane_eq[2] ** 2)

            # Select indexes where distance is biggers than the threshold
            pt_id_inliers = np.where(np.abs(dist_pt) <= thresh)[0]
            if len(pt_id_inliers) > len(best_inliers):
                best_eq = plane_eq
                best_inliers = pt_id_inliers
            self.inliers = best_inliers
            self.equation = best_eq

        return self.equation, self.inliers

2.改进代码

2.1 提速

用的时候发现代码的速度比open3d的慢了50ms左右。找了一圈找到方法了
https://zhuanlan.zhihu.com/p/62238520
就是替换循环次数

import random

import numpy as np


class Plane:
    """
    Implementation of planar RANSAC.

    Class for Plane object, which finds the equation of a infinite plane using RANSAC algorithim.

    Call `fit(.)` to randomly take 3 points of pointcloud to verify inliers based on a threshold.

    ![Plane](https://raw.githubusercontent.com/leomariga/pyRANSAC-3D/master/doc/plano.gif "Plane")

    ---
    """

    def __init__(self):
        self.inliers = []
        self.equation = []

    def fit(self, pts, thresh=0.05, minPoints=100, maxIteration=1000, P=0.99):
        """
        Find the best equation for a plane.

        :param pts: 3D point cloud as a `np.array (N,3)`.
        :param thresh: Threshold distance from the plane which is considered inlier.
        :param maxIteration: Number of maximum iteration which RANSAC will loop over.
        :param P: desired probability that we get a good sample
        :returns:
        - `self.equation`:  Parameters of the plane using Ax+By+Cy+D `np.array (1, 4)`
        - `self.inliers`: points from the dataset considered inliers

        ---
        """
        n_points = pts.shape[0]
        best_eq = []
        best_inliers = []
        i = 0
        while True:
            if i < maxIteration:
                i += 1
                # Samples 3 random points
                id_samples = random.sample(range(0, n_points), 3)
                pt_samples = pts[id_samples]

                # We have to find the plane equation described by those 3 points
                # We find first 2 vectors that are part of this plane
                # A = pt2 - pt1
                # B = pt3 - pt1

                vecA = pt_samples[1, :] - pt_samples[0, :]
                vecB = pt_samples[2, :] - pt_samples[0, :]

                # Now we compute the cross product of vecA and vecB to get vecC which is normal to the plane
                vecC = np.cross(vecA, vecB)

                # The plane equation will be vecC[0]*x + vecC[1]*y + vecC[0]*z = -k
                # We have to use a point to find k
                vecC = vecC / np.linalg.norm(vecC)
                k = -np.sum(np.multiply(vecC, pt_samples[1, :]))
                plane_eq = [vecC[0], vecC[1], vecC[2], k]

                # Distance from a point to a plane
                # https://mathworld.wolfram.com/Point-PlaneDistance.html
                pt_id_inliers = []  # list of inliers ids
                dist_pt = (
                                  plane_eq[0] * pts[:, 0] + plane_eq[1] * pts[:, 1] + plane_eq[2] * pts[:, 2] +
                                  plane_eq[3]
                          ) / np.sqrt(plane_eq[0] ** 2 + plane_eq[1] ** 2 + plane_eq[2] ** 2)

                # Select indexes where distance is biggers than the threshold
                pt_id_inliers = np.where(np.abs(dist_pt) <= thresh)[0]
                #https://www.cse.psu.edu/~rtc12/CSE486/lecture15.pdf
                #speed up
                if len(pt_id_inliers) > len(best_inliers):
                    maxIteration = math.log(1 - P) / math.log(1 - pow(len(pt_id_inliers) / n_points, 3))
                    best_eq = plane_eq
                    best_inliers = pt_id_inliers

                self.inliers = best_inliers
                self.equation = best_eq

                if len(pt_id_inliers) > minPoints:
                    break

        return self.equation, self.inliers

2.2 提升精度

经过测试发现,拟合的平面的精度还是比open3d差。然后使用最小二乘法在求一次平面了文章来源地址https://www.toymoban.com/news/detail-678654.html

def ransac_fitplan(pts, thresh=5,num_iterations=1000):
    # # 希望的得到正确模型的概率
    n_points = pts.shape[0]
    best_inliers = []
    P = 0.9999
    i=0
    while True:
        if i<num_iterations:
            i+=1
            # 随机在数据中红选出两个点去求解模型
            id_samples = random.sample(range(0, n_points), 3)
            pt_samples = pts[id_samples]
            vecA = pt_samples[1, :] - pt_samples[0, :]
            vecB = pt_samples[2, :] - pt_samples[0, :]

            # Now we compute the cross product of vecA and vecB to get vecC which is normal to the plane
            vecC = np.cross(vecA, vecB)
            # The plane equation will be vecC[0]*x + vecC[1]*y + vecC[0]*z = -k
            # We have to use a point to find k
            vecC = vecC / np.linalg.norm(vecC)
            k = -np.sum(np.multiply(vecC, pt_samples[1, :]))
            plane_eq = [vecC[0], vecC[1], vecC[2], k]

            pt_id_inliers = []  # list of inliers ids
            dist_pt = (
                              plane_eq[0] * pts[:, 0] + plane_eq[1] * pts[:, 1] + plane_eq[2] * pts[:, 2] + plane_eq[3]
                      ) / np.sqrt(plane_eq[0] ** 2 + plane_eq[1] ** 2 + plane_eq[2] ** 2)

            # Select indexes where distance is biggers than the threshold
            pt_id_inliers = np.where(np.abs(dist_pt) <= thresh)[0]
            if len(pt_id_inliers) > len(best_inliers):
                num_iterations = math.log(1 - P) / math.log(1 - pow(len(pt_id_inliers) / n_points, 3))
                best_inliers = pt_id_inliers
            # 判断是否当前模型已经符合超过一半的点
            if len(pt_id_inliers) > 0.5*n_points:
                break
        else:
            break
    # 最小二乘法拟合平面
    X = np.column_stack((pts[:, :2], np.ones(pts.shape[0])))
    coefficients, _, _, _ = lstsq(X[best_inliers, :], pts[best_inliers, 2])
    return coefficients,best_inliers

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

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

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

相关文章

  • Open3D 点云投影到拟合平面:Python 实现详解

    Open3D 点云投影到拟合平面:Python 实现详解 点云是指由大量离散的 3D 点组成的几何图形,常常用于工业检测、三维建模等领域。而拟合平面是指在点云数据中找到一个最适合的平面,该平面能够近似地拟合这些点云数据。将点云投影到拟合平面可以方便地进行分析和处理。本

    2024年02月07日
    浏览(38)
  • Open3D 最小二乘拟合二维多项式曲线

      多项式曲线表示为: p ( x ) = p 1 x n + p 2 x

    2024年02月16日
    浏览(32)
  • 三维点云拟合圆形(附open3d python 代码)

    圆拟合方法可分为以下步骤: 使用  SVD(奇异值分解) 找到平均中心点集的最佳拟合平面。 将均值中心点投影到新的 2D 坐标中的拟合平面上。 使用 最小二乘法 拟合 2D 坐标中的圆并得到圆心和半径。 将圆中心变换回 3D 坐标。现在,拟合圆由其中心、半径和法线向量指定。

    2024年02月06日
    浏览(33)
  • Open3D 实现建筑物点云立面和平面分割提取

    Open3D 实现建筑物点云立面和平面分割提取 点云数据在现实场景中广泛应用,例如建筑物三维重建、智能交通等领域。然而,点云数据量庞大且噪声较多,因此需要对其进行处理和分析。Open3D 是一款开源的跨平台点云处理库,在点云数据预处理、三维重建和可视化等方面有着

    2024年02月07日
    浏览(34)
  • Open3D点云数据处理(二十):最小二乘直线拟合(三维)

    专栏目录:Open3D点云数据处理(Python) 最小二乘三维直线拟合的原理是通过最小化数据点到直线距离的平方和,找到最优的直线模型来拟合给定数据集。这个距离是指数据点到直线的垂线距离。 三维直线通常表示为两个平面的交线,形如 { A

    2024年02月12日
    浏览(32)
  • Open3D 非线性最小二乘拟合二维多项式曲线

      多项式曲线表示为: p ( x ) = p 1 x n + p 2 x

    2024年02月07日
    浏览(36)
  • Open3D点云数据处理(十九):最小二乘直线拟合(矩阵方程法)

    专栏目录:Open3D点云数据处理(Python) 最小二乘直线拟合是一种常用的数据拟合方法,它的目标是找到一条直线,使得该直线和样本数据之间的误差平方和最小。从矩阵方程的角度来看,最小二乘直线拟合可以看作是求解一个超定线性方程组的问题。 具体来说,我们假设有

    2024年02月13日
    浏览(31)
  • 【Open3D】如何在CMake/C++中调用Open3D

    qquad Open3D是点云的开源处理库,支持Python或C++。其Python已有较全的教程,也可以直接使用 pip install open3d 直接进行安装,而若想在C++中调用Open3D则麻烦一些,需要满足以下条件: Open3D git源代码(本教程针对0.16.1的版本) CMake = 3.20 clang = 7 分为以下几步进行: 下载Open3D源代码

    2023年04月18日
    浏览(33)
  • open3d教程(一):open3d的安装和测试(Python版本)

    Open3d:用于3D数据处理的现代库。 Open3D 是一个开源库,支持快速开发处理 3D 数据的软件。 Open3D 前端在 C++ 和 Python 中公开了一组精心挑选的数据结构和算法。后端经过高度优化,并设置为并行化。我们欢迎来自开源社区的贡献。 Open3d的核心功能: 3D数据结构 3D数据处理算法

    2024年02月17日
    浏览(38)
  • 基于Open3D的点云处理17-Open3d的C++版本

    http://www.open3d.org/docs/latest/cpp_api.html http://www.open3d.org/docs/latest/getting_started.html#c http://www.open3d.org/docs/release/cpp_project.html#cplusplus-example-project https://github.com/isl-org/open3d-cmake-find-package https://github.com/isl-org/open3d-cmake-external-project https://github.com/isl-org/Open3D/releases Note: -DBUILD_SHARED_LIBS

    2024年02月09日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包