当前位置: 首页 > news >正文

【点云处理教程】03使用 Python 实现地面检测

一、说明

        这是我的“点云处理”教程的第3篇文章。“点云处理”教程对初学者友好,我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。

        在上一教程中,我们在不使用 Open3D 库的情况下从深度数据计算点云。在本教程中,我们将首先描述系统坐标。然后,我们将以地面检测为例,仔细分析点云。我们还将介绍有组织的点云,这是一种有趣的3D表示。

作者的相机视野

这是我的“点云处理”教程的第3篇文章。“点云处理”教程对初学者友好,我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。

  • 第1条:点云处理简介
  • 文章2:在Python中从深度图像估计点云
  • 文章3:了解点云:使用Python实现地面检测
  • 文章4:Python中的点云过滤
  • 文章 5 : Python 中的点云分割

二、计算机视觉坐标系

        在开始之前,了解计算机视觉中的传统坐标系非常重要。它们在Open3D [1]和Microsoft Kinect传感器[2]中紧随其后。在计算机视觉中,图像以独立的 2D 坐标系表示,其中 X 轴从左到右指向,Y 轴从上到下指向。对于相机,3D 坐标系原点位于相机的焦点,其中 X 轴指向右,Y 轴指向下方,Z 轴指向前方。

        计算机视觉坐标系

        我们首先导入所需的库:

import numpy as np
import open3d as o3d

        为了更好地理解,让我们从 PLY 文件导入点云,使用 Open3D 创建默认 3D 坐标系并显示它们:

# Read point cloud:
pcd = o3d.io.read_point_cloud("data/depth_2_pcd.ply")
# Create a 3D coordinate system:
origin = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5)
# geometries to draw:
geometries = [pcd, origin]
# Visualize:
o3d.visualization.draw_geometries(geometries)

        显示的具有坐标系原点的点云。蓝色箭头是 Z 轴,红色箭头是 X 轴,绿色箭头是 Y 轴。

        知道蓝色、红色和绿色箭头分别表示 Z 轴、X 轴和 Y 轴,您可以看到点云与 Open3D 坐标系表示在同一坐标系中。现在,让我们得到每个轴具有最小值和最大值的点: 

# Get max and min points of each axis x, y and z:
x_max = max(pcd.points, key=lambda x: x[0])
y_max = max(pcd.points, key=lambda x: x[1])
z_max = max(pcd.points, key=lambda x: x[2])
x_min = min(pcd.points, key=lambda x: x[0])
y_min = min(pcd.points, key=lambda x: x[1])
z_min = min(pcd.points, key=lambda x: x[2])
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

        我们可以打印它们,但为了获得更好的可视化效果,我们在每个点位置创建一个球体几何形状。默认情况下,Open3D 在原点位置创建 3D 几何体:

要将球体移动到给定位置,需要进行平移转换。在下面的示例中,球体由向量 [1,1,1] 平移:

让我们回到我们的示例,为每个球体分配一种颜色。对于每个位置,我们创建一个球体并将其转换为该位置。然后,我们分配正确的颜色,最后我们将其添加到最后显示。

# Colors:
RED = [1., 0., 0.]
GREEN = [0., 1., 0.]
BLUE = [0., 0., 1.]
YELLOW = [1., 1., 0.]
MAGENTA = [1., 0., 1.]
CYAN = [0., 1., 1.]positions = [x_max, y_max, z_max, x_min, y_min, z_min]
colors = [RED, GREEN, BLUE, MAGENTA, YELLOW, CYAN]
for i in range(len(positions)):# Create a sphere mesh:sphere = o3d.geometry.TriangleMesh.create_sphere(radius=0.05)# move to the point position:sphere.translate(np.asarray(positions[i]))# add color:sphere.paint_uniform_color(np.asarray(colors[i]))# compute normals for vertices or faces:sphere.compute_vertex_normals()# add to geometry list to display later:geometries.append(sphere)# Display:
o3d.visualization.draw_geometries(geometries)

        嗯,我们可以看到对应的黄色球体在墙上,对应的绿色球体在地面上。实际上,Y 轴表示点的高度:在现实世界中,最高的球体是黄色的,最低的球体是绿色的球体。但是,由于 Y 轴指向下方,因此黄色球体具有最小值,绿色球体具有最大值。y_min y_max

        另一个有趣的球体是原点上的青色球体。正如我们在上一教程中提到的,深度值为 0 的像素是噪声点,因此位于原点的点是从这些噪声像素计算的点(当和 )。z=0x=0y=0

三、 地面检测

        现在我们展示了一些要点,如何检测地面?在前面的示例中,绿色球体位于地面上。确切地说,它与沿 Y 轴的最高点相对应的中心是一个接地点。假设为了检测地面,我们将所有必须的点的颜色更改为绿色。y_max

        如果显示点云,您会注意到并非所有地面点都为绿色。事实上,只有一个与前一个绿色球体的中心相对应的点是绿色的。这是由于深度相机的准确性和噪点水平。

        为了克服此限制,我们需要添加一个阈值,以便将具有 y 坐标的点都视为地面点。为此,在得到之后,我们检查每个点的 y 坐标是否在该区间内,然后将其颜色设置为绿色。最后,我们更新点云的颜色属性并显示结果。[y_max-threshold, y_max]y_max

# Define a threshold:
THRESHOLD = 0.075# Get the max value along the y-axis:
y_max = max(pcd.points, key=lambda x: x[1])[1]# Get the original points color to be updated:
pcd_colors = np.asarray(pcd.colors)# Number of points:
n_points = pcd_colors.shape[0]# update color:
for i in range(n_points):# if the current point is aground point:if pcd.points[i][1] >= y_max - THRESHOLD:pcd_colors[i] = GREEN  # color it greenpcd.colors = o3d.utility.Vector3dVector(pcd_colors)# Display:
o3d.visualization.draw_geometries([pcd, origin])

        在此示例中,我们仅将表示地面的点着色为绿色。在实际应用中,提取地面以定义可步行区域,如机器人或视障系统,或将物体放在其上,如室内设计系统。它也可以被移除,因此剩余的点可以像在场景理解和对象检测系统中一样进行分割或分类。

四、有组织的点云

        在我们的第一个教程中,我们将点云定义为一组 3D 点。集合是一种无序结构,因此由集合表示的点云称为无组织点云。与 RGB 矩阵类似,有组织的点云是一个 2D 矩阵,具有 3 个通道,表示点的 xy 和 z 坐标。矩阵结构提供了相邻点之间的关系,从而降低了某些算法(如最近邻)的时间复杂性。

        例如,假设我们正在撰写一篇研究论文,我们希望将地面检测算法的结果显示为图表。不幸的是,无法选择动画人物。因此,我们可以截取点云的屏幕截图,也可以在深度图像上显示结果,如下图所示。在我看来,第二种选择是最好的。在这种情况下,需要一个有组织的点云来保留深度像素的位置。

左:3D 可视化的屏幕截图。右:深度图像的结果。

        让我们从上一个深度图像创建一个有组织的点云。我们首先,像上一篇文章中那样导入相机参数。我们还导入深度图像并将其转换为 3 通道灰度图像,以便我们可以将地面像素设置为绿色:

import imageio.v3 as iio
import numpy as np
import matplotlib.pyplot as plt# Camera parameters:
FX_DEPTH = 5.8262448167737955e+02
FY_DEPTH = 5.8269103270988637e+02
CX_DEPTH = 3.1304475870804731e+02
CY_DEPTH = 2.3844389626620386e+02# Read depth image:
depth_image = iio.imread('../data/depth_2.png')
# Compute the grayscale image:
depth_grayscale = np.array(256 * depth_image / 0x0fff, dtype=np.uint8)
# Convert a grayscale image to a 3-channel image:
depth_grayscale = np.stack((depth_grayscale,) * 3, axis=-1)

        为了计算有组织的点云,我们按照与上一个教程中相同的方式进行。我们没有展平深度图像,而是重塑并具有与深度图像相同的形状,如下所示:jjii

# get depth image resolution:
height, width = depth_image.shape
# compute indices and reshape it to have the same shape as the depth image:
jj = np.tile(range(width), height).reshape((height, width))
ii = np.repeat(range(height), width).reshape((height, width))
# Compute constants:
xx = (jj - CX_DEPTH) / FX_DEPTH
yy = (ii - CY_DEPTH) / FY_DEPTH
# compute organised point cloud:
organized_pcd = np.dstack((xx * depth_image, yy * depth_image, depth_image))

        如果打印创建的点云的形状,您可以看到它是具有3个通道的矩阵。如果您发现此代码难以理解,请返回上一个教程,如果仍然不清楚,请随时给我留下您的问题,我将很乐意为您提供帮助。(480, 640, 3)

        同样,我们像上面一样检测地面,但不是更新点的颜色并显示点云,而是更新灰度图像的像素并显示它:

# Ground_detection:
THRESHOLD = 0.075 * 1000  # Define a threshold
y_max = max(organized_pcd.reshape((height * width, 3)), key=lambda x: x[1])[1]  # Get the max value along the y-axis# Set the ground pixels to green:
for i in range(height):for j in range(width):if organized_pcd[i][j][1] >= y_max - THRESHOLD:depth_grayscale[i][j] = [0, 255, 0]  # Update the depth image# Display depth_grayscale:
plt.imshow(depth_grayscale)
plt.show()

五、结论

        在本教程中,为了习惯点云,我们引入了默认坐标系,并实现了一个简单的地面检测算法。事实上,地面探测在某些应用中(如导航)是一项重要任务,文献中已经提出了几种算法。实现的算法很简单;它将最低点视为地面。然而,它的局限性在于深度相机必须与地面平行,而大多数实际应用并非如此。

相关文章:

【点云处理教程】03使用 Python 实现地面检测

一、说明 这是我的“点云处理”教程的第3篇文章。“点云处理”教程对初学者友好,我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。 在上一教程中,我们在不使用 Open3D 库的情况下从深度数据计算点云。在本教程中,我们将首先…...

Python 日志记录:6大日志记录库的比较

Python 日志记录:6大日志记录库的比较 文章目录 Python 日志记录:6大日志记录库的比较前言一些日志框架建议1. logging - 内置的标准日志模块默认日志记录器自定义日志记录器生成结构化日志 2. Loguru - 最流行的Python第三方日志框架默认日志记录器自定…...

最近遇到一些问题的解决方案

最近遇到一些问题的解决方案 SpringBoot前后端分离参数传递方式总结Java8版本特性讲解idea使用git更新代码 : update project removeAll引发得java.lang.UnsupportedOperationException异常Java的split()函数用多个不同符号分割 Aspect注解切面demo 抽取公共组件,使…...

封装hutool工具生成JWT token

private static final String KEY "abcdef";/*** 生成token** param payload 可以存放用户的一些信息&#xff0c;不要存放敏感字段* return*/public static String createToken(Map<String, Object> payload) {//十分重要&#xff0c;不禁用发布到生产环境无…...

【手机】三星手机刷机解决SecSetupWizard已停止

三星手机恢复出厂设置之后&#xff0c;出现SecSetupWizard已停止的解决方案 零、问题 我手上有一部同学给的三星 GT-S6812I&#xff0c;这几天搞了张新卡&#xff0c;多余出的卡就放到这个手机上玩去了。因为是获取了root权限的&#xff08;直接使用KingRoot就可以&#xff0…...

GDAL C++ API 学习之路 OGRGeometry 抽象曲线基类 OGRCurve

OGRCurve class "ogrsf_frmts.h" OGRCurve 是 OGR&#xff08;OpenGIS Simple Features Reference Implementation&#xff09;几何库中的一个基类&#xff0c;表示曲线几何对象。它是 OGRLineString 和 OGRCircularString 的抽象基类&#xff0c;用于表示曲…...

etcd底层支持的数据库有哪些

etcd底层的数据库可以更换。在当前版本的etcd中&#xff0c;它使用的是BoltDB作为默认的后端存储引擎。但是&#xff0c;etcd提供了接口允许您更换数据库后端&#xff0c;以便根据需要选择更合适的存储引擎。 以下是etcd支持的一些后端数据库选项&#xff1a; BoltDB&#xff…...

linux设备驱动的poll与fasync

什么是fasync 在 Linux 驱动程序中&#xff0c;fasync 是一种机制&#xff0c;用于在异步事件发生时通知进程。它允许进程在等待设备事件时&#xff0c;不必像传统的轮询方式那样持续地查询设备状态。 具体来说&#xff0c;当进程调用 fcntl(fd, F_SETFL, O_ASYNC) 函数时&am…...

TortoiseGit安装与配置

注&#xff1a;在安装TortoiseGit之前我已经安装了git工具。 二、Git的诞生及环境配置_tortoisegit安装包_朱嘉鼎的博客-CSDN博客 1、TortoiseGit简介 TortoiseGit是基于TortoiseSVN的Git版本的Windows Shell界面。它是开源的&#xff0c;可以完全免费使用。 TortoiseGit 支持…...

Java代码打印空心菱形(小练习)

回看基础 利用Java代码打印一个空心菱形 //5. 打印空心菱形 import java.util.Scanner; public class MulForExercise01 {//编写一个 main 方法public static void main(String[] args) {Scanner myScanner new Scanner(System.in);System.out.println("请输入正三角的行…...

【性能优化】MySQL百万数据深度分页优化思路分析

业务场景 一般在项目开发中会有很多的统计数据需要进行上报分析&#xff0c;一般在分析过后会在后台展示出来给运营和产品进行分页查看&#xff0c;最常见的一种就是根据日期进行筛选。这种统计数据随着时间的推移数据量会慢慢的变大&#xff0c;达到百万、千万条数据只是时间问…...

交叉编译工具链的安装、配置、使用

一、交叉编译的概念 交叉编译是在一个平台上生成另一个平台上的可执行代码。 编译&#xff1a;一个平台上生成在该平台上的可执行文件。 例如&#xff1a;我们的Windows上面编写的C51代码&#xff0c;并编译成可执行的代码&#xff0c;如xx.hex.在C51上面运行。 我们在Ubunt…...

【C++ 进阶】继承

一.继承的定义格式 基类又叫父类&#xff0c;派生类又叫子类&#xff1b; 二.继承方式 继承方式分为三种&#xff1a; 1.public继承 2.protected继承 3.private继承 基类成员与继承方式的关系共有9种&#xff0c;见下表&#xff1a; 虽然说是有9种&#xff0c;但其实最常用的还…...

Git使用详细教程

1. cmd面板的常用命令 clear&#xff1a;清屏cd 文件夹名称----进入文件夹cd … 进入上一级目录(两个点)dir 查看当前目录下的文件和文件夹(全拼:directory)Is 查看当前目录下的文件和文件夹touch 文件名----创建文件echo 内容 > 创建文件名----创建文件并写入内容rm 文件名…...

小程序 表单验证

使用 WxValidate.js 插件来校验表单数据 常用实例方法 名称返回类型描述checkForm(e)boolean验证所有字段的规则&#xff0c;返回验证是否通过。valid()boolean返回验证是否通过。size()number返回错误信息的个数。validationErrors()array返回所有错误信息。addMethod(name…...

本地仓库推送至远程仓库

1. 本地生成ssh密钥对 ssh-keygen -t rsa -C 邮箱2. 添加公钥到gitlab/github/gitee上 打开C:\Users\用户名\.ssh目录下生成的密钥文件id_rsa.pub&#xff0c;把内容复制到如下文本框中 删除Expiration date显示的日期&#xff0c;公钥有效期变成永久&#xff0c;之后点Add K…...

【Unity2D】角色动画的切换

动画状态转换 第一种方法是设置一个中间状态&#xff0c;从中间状态向其余各种状态切换&#xff0c;且各状态向其他状态需要设置参数 实现动作转移时右键点击Make Transition即可 实现动画转移需要设置条件 点击一种动画到另一种动画的线 &#xff0c;然后点击加号添加Condi…...

【MATLAB第62期】基于MATLAB的PSO-NN、BBO-NN、前馈神经网络NN回归预测对比

【MATLAB第62期】基于MATLAB的PSO-NN、BBO-NN、前馈神经网络NN回归预测对比 一、数据设置 1、7输入1输出 2、103行样本 3、80个训练样本&#xff0c;23个测试样本 二、效果展示 NN训练集数据的R2为&#xff1a;0.73013 NN测试集数据的R2为&#xff1a;0.23848 NN训练集数据的…...

深度剖析C++ 异常机制

传统排错 我们早在 C 程序里面传统的错误处理手段有&#xff1a; 终止程序&#xff0c;如 assert&#xff1b;缺陷是用户难以接受&#xff0c;说白了就是一种及其粗暴的手法&#xff0c;比如发生内存错误&#xff0c;除0错误时就会终止程序。 返回错误码。缺陷是需要我们自己…...

adb no permissions (user *** is not in the plugdev group)

首次配置ubuntu下的adb 环境&#xff0c;执行了adb device命令会出现以下问题 lvilvi-PC:~/develop/android/sdk/platform-tools$ adb devices List of devices attached 123699aac6536d65 no permissions (user lvi is not in the plugdev group); see [http://develo…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...