从图像到点云 Python PCL安装教程

本文旨在记录自己入门PCL、实现从二维图像转换成三维点云的过程,有不足之处欢迎指出~

C++环境下的安装编程参考这两篇博文~

Python环境下的编程参考这篇博文~

一、基本配置

我的配置是Win10+OpenCV3.4.1+Python3.6.1+PCL1.8.1,注意PCL1.8.0以上的版本只支持Python3.5以上的版本

1. OpenCV安装

参考我的上一篇博文Win10+vs2015+opencv3.4.1+附加模块opencv_contrib+cmake3.11.0编译和配置~ 在此就不赘述了。

2. PCL安装

PCL的安装和环境配置可参考这篇博文中”工程配置”之前的部分。

3. Python-PCL的配置

(1)将这个github中的仓库以ZIP形式下载到本地并解压。

(2)下载Windows Gtk+并解压,将bin目录下的文件拷贝到上一个步骤解压的python-pcl-master文件夹下的pkg-config文件夹中

(3)设置环境变量

  • 在系统变量中添加变量PCL_ROOT,变量值是PCL路径。

  • 在PATH路径中设置以下三个变量,分别是 <你的PCL路径>\bin<你的OPEN_NI的路径>\Tools<你的VTK路径>\bin

(4)安装必需模块

如果电脑中同时有python2和python3的话,注意电脑中的pip对应哪个版本的python,若pip对应python2,以下命令用pip3

1
2
3
4
5
6
pip install --upgrade pip
pip install cython==0.25.2
pip install numpy

python setup.py build_ext -i
python setup.py install

到此整个编程环境就配置好啦!可以开始写代码了~

二、从2D到3D

1. 数学部分

参考高博博文,PS:这是一个很棒的SLAM博客~我简单列举一下写代码时需要用到的公式——从图像坐标到世界坐标的转换(即已知 $[u,v,d]$ 推导出 $[x,y,z]$ )

通常,把 $f_x,f_y,c_x,c_y$ 四个参数定义为相机的内参矩阵 $C$ ,也就是相机做好之后就不会变的参数。

2. 编程部分

先给出全部代码,之后再分开讲解各部分的作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import cv2
depth = cv2.imread("depth.png",-1)

import pcl
cloud = pcl.PointCloud() # 存储图像的点云
rows = len(depth)
cols = len(depth[0])
pointcloud = []

#camera_factor = 1
#camera_cx = 0
#camera_cy = 0
camera_fx = 588.03
camera_fy = 587.07

for m in range(0, rows):
for n in range(0, cols):
d = depth[m][n][0] + depth[m][n][1]*256
if d == 0:
pass
else:
z = float(d)
x = n * z / camera_fx
y = m * z / camera_fy
points = [x, y, z]
pointcloud.append(points)

#由于pcl库不会直接识别列表格式的点云数据,所以我们需要使用numpy库进行数据格式转换,并将点云保存pcd文件中。
import numpy as np
pointcloud = np.array(pointcloud, dtype = np.float32)
cloud.from_array(pointcloud)
pcl.save(cloud, "cloud.pcd", format = 'pcd')

接下来讲解一下各部分代码的作用。

1
2
import cv2
depth = cv2.imread("depth.png",-1)

在python中,cv2.imread()函数会将图片数据存储为一个多维列表(list),第二个参数设置为-1表示以原始图像读取。

1
2
for m in range(0, rows):
for n in range(0, cols):

接下来我们按照“先列后行”的顺序,遍历整张图。m指图像的行,n指图像的列。它们和空间点的坐标关系是这样的:

1
2
3
4
5
6
7
8
9
10
11
for m in range(0, rows):
for n in range(0, cols):
d = depth[m][n][0] + depth[m][n][1]*256
if d == 0: # d可能没有值,若如此,跳过此点
pass
else:
z = float(d)
x = n * z / camera_fx
y = m * z / camera_fy
points = [x, y, z]
pointcloud.append(points)

在for循环中,先获取图像深度(注意不同来源的图片,其图像深度获取方式不同,有的数据集中给出rgb图像和深度图像,这里的深度图像读取后不作变换就是深度,而我们的项目中深度的计算公式是:$b + g * 256$ ,而python中是以[b, g, r]的格式存储图像的),再进行从图像坐标到世界坐标的转换,将每个点存入一个列表中。

1
2
3
4
import numpy as np
pointcloud = np.array(pointcloud, dtype = np.float32)
cloud.from_array(pointcloud)
pcl.save(cloud, "cloud.pcd", format = 'pcd')

由于pcl库不会直接识别列表格式的点云数据,所以我们需要使用numpy库进行数据格式转换,并将点云保存pcd文件中。

最后,在当前目录下打开cmd或者powershell,运行pcl_viewer(在<PCL安装路径>\bin目录下),就可以看到我们生成的点云了。

结果如下~:

原始图片:

点云:

文章作者: Elody
文章链接: http://Elody-07.github.io/从图像到点云/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Elody的博客