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

news2024/11/16 2:50:30

一、说明

        这是我的“点云处理”教程的第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 green

pcd.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()

五、结论

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

H5打包封装小程序系统开发

H5打包封装小程序系统开发 H5打包封装小程序系统开发是指将H5页面打包封装成小程序的开发过程。下面是一个简单的步骤: 准备工作:首先,需要准备好H5页面的代码和资源文件。确保H5页面在浏览器中正常运行,并且没有依赖于浏览器特…

【LeetCode每日一题合集】2023.7.24-2023.7.30

文章目录 771. 宝石与石头代码1——暴力代码2——位运算集合⭐(英文字母的long集合表示) 2208. 将数组和减半的最少操作次数(贪心 优先队列)2569. 更新数组后处理求和查询⭐⭐⭐⭐⭐(线段树)TODO2500. 删除…

渗透测试技术知识技能全景图(超清晰哦~~!)

这张技术全景图是博主对信息安全专业的了解学习,以及通过多方资料学习整理出来的,也结合了个人的一些学习经验在里面,图里详细列举了渗透测试这门技术应该具备的知识技能以及一些相关的图书的推荐。里面东西均为通过个人经验对渗透测试的了解…

DRIFTINGBLUES-1靶机通关详解

信息收集 漏洞发现 进web看源码发现 解码得到 /noteforkingfish.txt 访问发现是ook 解得 先把这个名字记下来 说不定之后要ssh爆破有用 然后他说要用 host file 注意到域名可能是driftingblues.box 加到hosts里试试 没啥用 看别人wp知道还得爆破子域名 那kali也添加个hosts…

【腾讯云 Cloud Studio 实战训练营】全新的开发方式,让你实现一站式开发

一、前言 关于 Cloud Studio 全在线云端开发 用户只需要浏览器就可以访问和使用Cloud Studio,无需在本地配置开发环境。Cloud Studio将开发环境部署在云服务器上,用户可以随时随地进行开发。多语言支持 Cloud Studio支持常见的开发语言,如Node.js、Python、Java、PHP等。用户…

QtC++ 技术分析3 - IOStream

目录 iostreamscanf/printfiostream 整体架构流相关类流缓冲区 模板特化后整体结构文件流文件流对象创建常见文件流操作输出格式设定文件流状态 字符串流字符串流内部缓冲区字符串流使用 流缓冲区用户自定义 IO iostream scanf/printf 几种常见的输入输出流函数 scanf 从键盘…

哆啦A梦(Python代码实现)

目录 1 送她的多啦A梦 2 白驹过隙 3 Python代码实现 1 送她的多啦A梦 一个哆啦A梦让她开心开心好久好久。我也很开心,昨天送了一个实体模型,今天用Python代码再弄一个送给她。 哆啦A梦(日语:ドラえもん,英语&…

linux页框回收之shrink_node函数源码剖析

概述 《Linux内存回收入口_nginux的博客-CSDN博客》前文我们概略的描述了几种内存回收入口,我们知道几种回收入口最终都会调用进入shrink_node函数,本文将以Linux 5.9源码来描述shrink_node函数的源码实现。 函数调用流程图 scan_control数据结构 str…

如何关闭谷歌浏览器自动更新

适用范围: 写自动化脚本时,需要安装浏览器驱动,安装浏览器驱动时需要下载对应的浏览器驱动版本,如果浏览器版本一直在自动更新的话,自动化脚本会报错浏览器版本和浏览器驱动不匹配,所以建议关闭谷歌浏览器自动更新&am…

认识 springboot 之 它的配置文件 -2

前言 本篇了解springboot中配置的作用,介绍配置文件的种类,介绍简单使用配置文件,简单的小技巧如何设置注释,开启热部署等等,如有错误,请在评论区指正,让我们一起交流,共同进步&…

内存分区模型

C程序在执行时,将内存大方向划分为4个区域 代码区:存放函数体的二进制代码,由操作系统进行管理的全局区:存放全局变量和静态变量以及常量栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等堆区:由程…

ReentrantLock锁的实现

ReentrantLock基于AQS,在并发编程中可以实现公平锁和非公平锁来对同步资源进行控制,并且是可重入锁。 1.ReentrantLock中的类的继承结构: 2.构造方法: 3.非公平锁的实现 看是否能够通过CAS来设置state来获取到锁,如果…

【数据结构】这堆是什么

目录 1.二叉树的顺序结构 2.堆的概念及结构 3.堆的实现 3.1 向上调整算法与向下调整算法 3.2 堆的创建 3.3 建堆的空间复杂度 3.4 堆的插入 3.5 堆的删除 3.6 堆的代码的实现 4.堆的应用 4.1 堆排序 4.2 TOP-K问题 首先,堆是一种数据结构,一种特…

Selenium开发环境搭建

1.下载Python https://www.python.org/downloads/ 下载下来选择自己创建的路径进行安装,然后配置环境变量 cmd命令框查看 2.安装selenium cmd命令框输入: pip install selenium3.下载pycharm https://www.jetbrains.com/pycharm/download/#sec…

VLOOKUP多条件查询

LOOKUP(1,0/((A3:A15A18)*(C3:C15C18)),F3:F15)

打印Winfrom控件实现简陋版的打印(C#)

本文在前面写的博文基础上进行修改:利用Graphics的CopyFromScreen实现简陋版的打印(C#)_zxy2847225301的博客-CSDN博客 通过截图的方式进行打印在前面的文章后面已经介绍过,有问题。 UI布局如下: 代码如下: using System; using…

无涯教程-jQuery - Dialog组件函数

小部件对话框函数可与JqueryUI中的小部件一起使用。对话框是在HTML页面上显示信息的一种不错的方法。对话框是一个带有标题和内容区域的浮动窗口。此窗口可以移动,调整大小,并且默认情况下可以使用" X"图标关闭。 Dialog - 语法 $( "#d…

CAN转ETHERCAT网关can协议和485协议区别

大家好,今天要跟大家分享一款自主研发的通讯网关,JM-ECT-CAN。这款产品能够将各种CAN总线和ETHERCAT网络连接起来,实现高效的数据传输和通信。那么,这款通讯网关具体有哪些功能和特点呢?接下来,我们就一起来…

苍穹外卖心得与总结【对比瑞吉】【如何获得铁粉】

对于苍穹外卖项目,从学习课程加复习已经13天了。 对于一名已经学习过SSMLinuxRedis数据库的Java练习生来说,这个项目相对于之前学习的《瑞吉外卖》新增了很多功能和技术,是很值得练手和提升的课程,下面给出自己的一些见解。&#…

大厂程序员的水平比非大厂高很多嘛?

最近一个月,筛选了一百多份简历,前前后后面试了二三十人,基本上都是有大厂经历的人。同时,也录用了几个有大厂经历的。但整体而言,打破了对大厂出来的都是优质人才的幻觉。看到的实际情况与想象中的落差还是比较大的。…