
文章插图
在本教程中,我们将学习如何在不使用 Open3D 库的情况下从深度图像计算点云 。我们还将展示如何优化代码以获得更好的性能 。
1. 深度图像
深度图像(也称为深度图)是一种图像,其中每个像素提供相对于传感器坐标系的距离值 。深度图像可以通过结构光或飞行时间传感器捕获 。为了计算深度数据,结构光传感器(例如 Microsoft Kinect V1)会比较投射光和接收光之间的变化 。至于像微软Kinect V2这样的飞行时间传感器,它们投射光线,然后计算从投射到随后接收光线的时间间隔 。
除了深度图像外,一些传感器还提供其对应的RGB图像以形成rgb- D图像 。这使得计算彩色点云成为可能 。本教程将以微软Kinect V1 RGB-D图像为例 。
让我们从导入Python/ target=_blank class=infotextkey>Python库开始:
import imageio.v3 as iioimport numpy as npimport Matplotlib.pyplot as pltimport open3d as o3d现在,我们可以导入深度图像并打印其分辨率和类型:
# Read depth image:depth_image = iio.imread('data/depth.png')# print properties:print(f"Image resolution: {depth_image.shape}")print(f"Data type: {depth_image.dtype}")print(f"Min value: {np.min(depth_image)}")print(f"Max value: {np.max(depth_image)}")#输出Image resolution: (480, 640)Data type: int32Min value: 0Max value: 2980深度图像是一个大小为640×480的矩阵,其中每个像素都是32(或16)位整数,表示以毫米为单位的距离,因此,当打开深度图像时,它看起来是黑色的(见下图) 。最小值0表示噪声(没有距离),最大值2980表示最远像素的距离 。
【Python:基于 RGB-D 图像的点云计算】

文章插图
Microsoft Kinect V1 生成的深度图像
为了更好的可视化,我们计算它的灰度图像:
depth_instensity = np.array(256 * depth_image / 0x0fff,dtype=np.uint8)iio.imwrite('output/grayscale.png', depth_instensity)计算灰度图像意味着将深度值缩放到[0, 255]. 现在图像更清晰了:

文章插图
计算得到的灰度图像,黑色像素代表噪声
请注意,在可视化深度图像时,Matplotlib 会做同样的事情:
# Display depth and grayscale image:fig, axs = plt.subplots(1, 2)axs[0].imshow(depth_image, cmap="gray")axs[0].set_title('Depth image')axs[1].imshow(depth_grayscale, cmap="gray")axs[1].set_title('Depth grayscale image')plt.show()
文章插图
Matplotlib 自动缩放深度图像的像素
2.点云
现在我们已经导入并显示了深度图像,我们如何根据它估计点云呢?首先对深度相机进行标定,估计相机矩阵,然后用它来计算点云 。得到的点云也被称为2.5D点云,因为它是从 2D 投影(深度图像)而不是 3D 传感器(如激光传感器)估计的 。
2.1 深度相机标定
标定相机意味着通过寻找畸变系数和相机矩阵来估计镜头和传感器参数 。一般来说,标定相机有三种方法:使用工厂提供的标准参数,使用标定研究中获得的结果或手动标定Kinect 。手动标定包括标定算法,如棋盘格标定法 。标定矩阵M是一个3×3矩阵:

文章插图
其中fx、fy和cx、cy分别为焦距和光心 。对于本教程,我们将使用NYU Depth V2数据集获得的结果:
# Depth camera parameters:FX_DEPTH = 5.8262448167737955e+02FY_DEPTH = 5.8269103270988637e+02CX_DEPTH = 3.1304475870804731e+02CY_DEPTH = 2.3844389626620386e+022.2 点云计算
这里计算点云意味着将深度像素从深度图像2D坐标系转换到深度相机3D坐标系(x, y和z) 。3D坐标使用以下公式计算,其中depth(i, j)为第i行和第j列处的深度值:

文章插图
该公式适用于每个像素:
# compute point cloud:pcd = []height, width = depth_image.shapefor i in range(height):for j in range(width):z = depth_image[i][j]x = (j - CX_DEPTH) * z / FX_DEPTHy = (i - CY_DEPTH) * z / FY_DEPTHpcd.Append([x, y, z])让我们使用 Open3D 库显示它:
pcd_o3d = o3d.geometry.PointCloud() # create point cloud objectpcd_o3d.points = o3d.utility.Vector3dVector(pcd) # set pcd_np as the point cloud points# Visualize:o3d.visualization.draw_geometries([pcd_o3d])
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- python小程序轻松实现九宫格高“逼格”圈照,快来试一试
- Python生成二维码之segno模块
- 现实世界模型、薛定谔的猫和神经网络之间的联系及Python示例
- python日志包从头到尾讲清楚
- 十年 Python 程序员,初次尝试 Rust:“非常优秀!”
- python代码提速有哪些方法
- Python 获取上市公司利润表数据
- 连信是什么?
- python读写json文件
- 使用python selenium模拟登陆163并发送邮件
