Open3D Ransac拟合空间直线

目录

一、概述

1.1实现步骤

1.2优势与局限

二、代码实现

2.1关键代码

2.2完整代码

三、实现效果


前期试读,后续会将博客加入该专栏,欢迎订阅

Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客

一、概述

        RANSAC(RANdom SAmple Consensus)是一种迭代算法,用于从包含大量异常值的数据集中拟合模型。其核心思想是通过在数据集中随机抽取子集来拟合模型,并评估模型的适用性,最终选择内点最多的模型作为最佳拟合。

1.1实现步骤

以下是 RANSAC 拟合空间直线的详细步骤:

  1. 随机采样:从点云数据集中随机选择两个点(最少点数目来拟合直线)。
  2. 拟合模型:使用这两个点拟合一条直线。通过计算方向向量 𝑣和直线上任意一点 𝑝来定义直线。
  3. 计算内点:对于点云数据中的每个点,计算其到拟合直线的距离。距离小于预设阈值的点被认为是内点。
  4. 评估模型:记录内点的数量。如果当前直线模型的内点数量超过之前的最大内点数量,则更新最佳模型和内点集合。
  5. 重复:重复上述步骤若干次(预设的迭代次数),每次都记录最佳模型和内点集合。
  6. 输出结果:迭代结束后,输出内点数量最多的直线模型作为最终结果。

1.2优势与局限

优势:

  • 鲁棒性:能够有效处理数据集中存在的大量噪声和异常值。
  • 简单易用:算法相对简单,易于实现和理解。

局限:

  • 计算效率:当点云数据量较大时,算法的计算时间可能较长。
  • 参数依赖:需要预设距离阈值、采样点数和迭代次数等参数,这些参数的选择对算法性能有较大影响。
  • 模型假设:RANSAC 需要针对不同应用场景选择合适的模型(如直线、平面等),对复杂场景的适应性有限。

二、代码实现

2.1关键代码

def ransac_fit_line(points, distance_threshold=0.1, ransac_n=2, num_iterations=1000):
    """
    使用 RANSAC 算法拟合空间直线。

    参数:
    points (numpy.ndarray): 点云数据,形状为 (N, 3)。
    distance_threshold (float): 内点距离阈值,默认为 0.1。用于判断一个点是否属于拟合的直线。
    ransac_n (int): 每次随机采样的点的数量,默认为 2。用于拟合直线。
    num_iterations (int): RANSAC 算法的迭代次数,默认为 1000。增加迭代次数可以提高找到最佳拟合的概率。

    返回:
    best_line (numpy.ndarray): 拟合的直线模型参数,形状为 (2, 3)。包含拟合直线的两个端点。
    best_inliers (list): 内点索引列表。包含符合拟合直线的点的索引。
    best_direction (numpy.ndarray): 拟合直线的方向向量。
    """
    best_inliers = []  # 初始化最佳内点列表为空
    best_line = None  # 初始化最佳直线模型为空
    num_points = len(points)  # 获取点云中的点的数量

    for _ in range(num_iterations):  # RANSAC 算法迭代次数
        # 随机选择 ransac_n 个点
        sample_indices = random.sample(range(num_points), ransac_n)
        sample_points = points[sample_indices]

        # 拟合直线:计算两个采样点之间的方向向量
        v = sample_points[1] - sample_points[0]
        v /= np.linalg.norm(v)  # 将方向向量单位化
        line_point = sample_points[0]  # 选择第一个采样点作为直线上的一个点

        # 计算内点:判断哪些点与拟合的直线距离小于阈值
        inliers = calculate_inliers(points, line_point, v, distance_threshold)

        # 如果找到的内点数量比当前最佳内点数量多,则更新最佳内点和最佳直线模型
        if len(inliers) > len(best_inliers):
            best_inliers = inliers
            best_line = sample_points
            best_direction = v  # 更新最佳方向向量

    return best_line, best_inliers, best_direction  # 返回最佳直线模型、内点列表和方向向量

2.2完整代码

import open3d as o3d
import numpy as np
import random


def generate_noisy_line(num_points=1000, noise_level=0.1):
    """
    生成一条带有噪声的直线点云。

    参数:
    num_points (int): 点云中的点的数量。
    noise_level (float): 噪声水平,默认为 0.1。

    返回:
    point_cloud (numpy.ndarray): 生成的点云数据。
    """
    x = np.linspace(-5, 5, num_points)
    y = 2 * x + 1
    z = np.zeros_like(x)

    # 添加噪声
    noise = np.random.normal(0, noise_level, (num_points, 3))
    points = np.vstack((x, y, z)).T + noise

    return points


def calculate_inliers(points, line_point, v, distance_threshold):
    """
    计算点云中符合距离阈值的内点。

    参数:
    points (numpy.ndarray): 点云数据,形状为 (N, 3)。
    line_point (numpy.ndarray): 直线上一点。
    v (numpy.ndarray): 直线方向向量。
    distance_threshold (float): 距离阈值。

    返回:
    inliers (list): 内点索引列表。
    """
    inliers = []
    for i in range(points.shape[0]):
        point = points[i]
        distance = np.linalg.norm(np.cross(point - line_point, v))
        if distance < distance_threshold:
            inliers.append(i)
    return inliers


def ransac_fit_line(points, distance_threshold=0.1, ransac_n=2, num_iterations=1000):
    """
    使用 RANSAC 算法拟合空间直线。

    参数:
    points (numpy.ndarray): 点云数据,形状为 (N, 3)。
    distance_threshold (float): 内点距离阈值,默认为 0.1。
    ransac_n (int): 每次随机采样的点的数量,默认为 2。
    num_iterations (int): RANSAC 算法的迭代次数,默认为 1000。

    返回:
    best_line (numpy.ndarray): 拟合的直线模型参数,形状为 (2, 3)。
    best_inliers (list): 内点索引列表。
    """
    best_inliers = []
    best_line = None
    num_points = len(points)

    for _ in range(num_iterations):
        # 随机选择 ransac_n 个点
        sample_indices = random.sample(range(num_points), ransac_n)
        sample_points = points[sample_indices]

        # 拟合直线
        v = sample_points[1] - sample_points[0]
        v /= np.linalg.norm(v)
        line_point = sample_points[0]

        inliers = calculate_inliers(points, line_point, v, distance_threshold)

        if len(inliers) > len(best_inliers):
            best_inliers = inliers
            best_line = sample_points

    return best_line, best_inliers, v


def create_lineset_from_line_model(line_model, direction, length_multiplier=2.0):
    """
    从 RANSAC 拟合的线模型创建 LineSet 对象,并设置线段长度。

    参数:
    line_model (numpy.ndarray): 直线模型参数,形状为 (2, 3)。
    direction (numpy.ndarray): 直线方向向量。
    length_multiplier (float): 线段长度倍数,默认为 2.0。

    返回:
    lineset (open3d.geometry.LineSet): LineSet 对象。
    """
    mid_point = (line_model[0] + line_model[1]) / 2
    length = np.linalg.norm(line_model[1] - line_model[0]) * length_multiplier
    start_point = mid_point - direction * length / 2
    end_point = mid_point + direction * length / 2
    points = [start_point, end_point]
    lines = [[0, 1]]
    colors = [[1, 0, 0] for _ in range(len(lines))]

    lineset = o3d.geometry.LineSet(
        points=o3d.utility.Vector3dVector(points),
        lines=o3d.utility.Vector2iVector(lines),
    )
    lineset.colors = o3d.utility.Vector3dVector(colors)

    return lineset


# 生成带有噪声的直线点云
num_points = 100
noise_level = 0.1
points = generate_noisy_line(num_points, noise_level)

# 使用 RANSAC 算法拟合直线
distance_threshold = 0.1
ransac_n = 2
num_iterations = 500
line_model, inliers, direction = ransac_fit_line(points, distance_threshold, ransac_n, num_iterations)

# 创建 LineSet 对象,设置线段长度为点云范围的2倍
lineset = create_lineset_from_line_model(line_model, direction, length_multiplier=2.0)

# 可视化点云和拟合的直线
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)

inlier_cloud = pcd.select_by_index(inliers)
inlier_cloud.paint_uniform_color([0, 1, 0])

o3d.visualization.draw_geometries([pcd, lineset, inlier_cloud], window_name="RANSAC Line Fitting",
                                  width=800, height=600, left=50, top=50)

三、实现效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/803350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VScode终端和外部终端中文乱码问题

VScode终端和外部终端中文乱码问题 前言VScode终端VScode的第二大特点方法一方法二外部终端&#xff08;命令为ctrlf5&#xff09; 总结实现VScode终端和外部终端都能运行可执行文件 心得 前言 如果只想要看解决方案可直接跳转到总结部分&#xff0c;其余的章节只是用来说明原…

解决C#读取US7ASCII字符集oracle数据库的中文乱码

&#x1f468; 作者简介&#xff1a;大家好&#xff0c;我是Taro&#xff0c;全栈领域创作者 ✒️ 个人主页&#xff1a;唐璜Taro &#x1f680; 支持我&#xff1a;点赞&#x1f44d;&#x1f4dd; 评论 ⭐️收藏 文章目录 前言一、解决方法二、安装System.Data.OleDb连接库三…

第7章 模块(2)

目录 7.3 插入和删除模块 7.3.1 模块的表示 7.3.2 依赖关系和引用 7.3.3 模块的二进制结构 7.3.4 插入模块 7.3.5 移除模块 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 7.3 插入和删除模块 两个系统调用&#xff1a; init_module&#xff1…

考研数学二战,怎么准备才能提升大?

一战70多...二战提升空间那是相当的大 我身边很多一战甚至不到60&#xff0c;二战成绩飙到120的&#xff0c;真的很猛 所以你根本不用担心是自己学数学没天赋&#xff0c;其实知识方法没用对而已 本人属于基础很差相当于是零基础的23考研党&#xff0c;经过一年备考成功上岸…

k8s集群 安装配置 Prometheus+grafana+alertmanager

k8s集群 安装配置 Prometheusgrafanaalertmanager k8s环境如下&#xff1a;机器规划&#xff1a; node-exporter组件安装和配置安装node-exporter通过node-exporter采集数据显示192.168.40.180主机cpu的使用情况显示192.168.40.180主机负载使用情况 Prometheus server安装和配置…

JayChou周杰伦的歌曲网易云音乐怎么听

听Jay自由 网易云导入 专辑介绍 周杰伦&#xff08;Jay Chou&#xff09;是一位著名的台湾流行歌手、词曲创作人和演员。他以其独特的音乐风格和才华横溢的创作能力而闻名于世。以下是对周杰伦所有专辑的简要介绍&#xff1a; 《Jay》&#xff08;2000年&#xff09;&#xf…

独立开发者系列(26)——域名与解析

域名&#xff08;英语&#xff1a;Domain Name&#xff09;&#xff0c;又称网域&#xff0c;是由一串用点分隔的名字组成的互联网上某一台计算机或计算机组的名称&#xff0c;用于在数据传输时对计算机的定位标识&#xff08;有时也指地理位置&#xff09;。 由于IP地址不方便…

Leaflet集成wheelnav在WebGIS中的应用

目录 前言 一、两种错误的实现方式 1、组件不展示 2、意外中的空白 二、不同样式的集成 1、在leaflet中集成wheelnav 2、给marker绑定默认组件 2、面对象绑定组件 3、如何自定义样式 三、总结 前言 在之前的博客中&#xff0c;我们曾经介绍了使用wheelnav.js构建酷炫…

Flink底层原理解析:案例解析(第37天)

系列文章目录 一、flink架构 二、Flink底层原理解析 三、Flink应用场景解析 四、fink入门案例解析 文章目录 系列文章目录前言一、flink架构1. 作业管理器&#xff08;JobManager&#xff09;2. 资源管理器&#xff08;ResourceManager&#xff09;3. 任务管理器&#xff08;Ta…

【八股系列】CSS盒模型:掌握网页布局的核心

&#x1f389; 博客主页&#xff1a;【剑九 六千里-CSDN博客】 &#x1f3a8; 上一篇文章&#xff1a;【Vue中的&#xff1c;keep-alive&#xff1e;组件&#xff1a;深入解析与实践指南】 &#x1f3a0; 系列专栏&#xff1a;【面试题-八股系列】 &#x1f496; 感谢大家点赞&…

夏日狂欢水上漂流的爆笑奇遇记

【夏日狂欢&#xff0c;水上漂流的爆笑奇遇记 —— 月亮姐姐的“睫毛漂流记”】在这个炎炎夏日&#xff0c;当烈日炙烤着大地&#xff0c;每一寸空气弥漫着对清凉的渴望时&#xff0c;一场别开生面的“暑期嘉年华”正悄然掀起一场水上狂欢的浪潮。而在这场盛宴中&#xff0c;月…

FPGA实训报告DAY 1(Verilog HDL)

实习日志与总结 日期&#xff1a;2024 年 7 月 10 日 星期三 姓名&#xff1a;XXX 一、实习日志 上午 9:00 - 9:30 按时到达工位&#xff0c;参加部门早会&#xff0c;了解了今天的实习任务和目标&#xff0c;即初步学习 FPGA 简介和 Verilog 基础语法知识。 9:30 - 10:30…

springboot 集成minio,启动报错

springboot 集成 minio 8.5.10 报错 *************************** APPLICATION FAILED TO START *************************** Description: An attempt was made to call a method that does not exist. The attempt was made from the following location: io.minio.S3Base.…

在mybatis-plus中关于@insert注解自定义批处理sql导致其雪花算法失效而无法自动生成id的解决方法

受到这位作者的启发 > 原文在点这里 为了自己实现批量插入&#xff0c;我在mapper层使用insert注解写了一段自定义sql //自定义的批量插入方法 Insert("<script>" "insert into rpt_material_hour(id,sample_time,rounding_time,cur_month,machine_no…

启智畅想火车类集装箱号码识别技术,软硬件解决方案

集装箱号码识别需求&#xff1a; 实时检测车皮号、火车底盘号码、集装箱号码&#xff0c;根据火车类型分为以下三种情况&#xff1a; 1、纯车皮&#xff0c;只检测车皮号&#xff1b; 2、火车拉货箱&#xff08;半车皮&#xff09;&#xff0c;检测车皮号集装箱号码&#xff1b…

基于springboot和mybatis的RealWorld后端项目实战一之hello-springboot

新建Maven项目 注意archetype选择quickstart pom.xml 修改App.java App.java同级目录新增controller包 HelloController.java package org.example.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotatio…

拒绝废话:computed、watch和methods的区分和使用场景

computed、watch和methods是用于处理数据和响应数据变化的不同方式&#xff0c;三者之间有什么不同呢&#xff0c;贝格前端工场作为10年前端老司机&#xff0c;用浅显的语言给大家分享一下。 computed&#xff1a; computed属性是用来定义一个基于依赖的响应式属性。它会根据…

QT--控件篇四

一、对话框 在软件开发中&#xff0c;对话框&#xff08;Dialog&#xff09;是一种常见的用户界面元素&#xff0c;用于与用户进行交互和获取信息。它通常以模态或非模态的形式出现&#xff0c;模态对话框会阻止用户与应用程序的其他部分交互&#xff0c;直到对话框关闭为止&a…

Linux热键,shell含义及权限介绍

君子忧道不忧贫。 —— 孔丘 Linux操作系统的权限 1、几个常用的热键介绍1、1、[Tab]键1、2、[ctrl]-c1、3、[ctrl]-d1、4、[ctrl]-r 2、shell命令以及运行原理3、权限3、1、什么是权限3、2、权限的本质3、3、Linux中的用户3、4、Linux中文件的权限3、4、1、快速掌握修改权限的…

排序——归并排序及排序章节总结

前面的文章中 我们详细介绍了排序的概念&#xff0c;插入排序&#xff0c;交换排序与选择排序&#xff0c;大家可以通过下面的链接再去学习&#xff1a; ​​​​​​排序的概念及插入排序 交换排序 选择排序 这篇文章就详细介绍一下另一种排序算法&#xff1a;归并排序以及…