Python-PCL点云拼接(视觉SLAM第五讲案例)

最近在看高翔老师的《视觉SLAM十四讲》, 上面有C++的点云拼接, 看了之后也想用Python实现一下.

环境

于是去下了python-pcl, 安装这个库的过程还是比较折腾的. 最后还是按照这个issue里面讲得才安装成功.
这个库的文件写得比较简陋, 很多东西还是要查询PCL.
具体的C++, python代码还要案例使用的RGB图片和深度图都在GitHub, 大家可以参考.

Package: python3-pcl
Version: 0.3.0~rc1+dfsg-7~ubuntu18.04.2
Priority: optional
Section: python
Source: python-pcl
Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
Installed-Size: 2,193 kB
Provides: python3.6-pcl
Depends: cython3, python3 (<< 3.7), python3 (>= 3.6~), python3-filelock, python3-nose, python3-numpy, python3:any (>= 3.3.2-2~), libboost-system1.65.1, libc6 (>= 2.14), libflann1.9, libgcc1 (>= 1:3.0), libpcl-common1.8, libpcl-features1.8, libpcl-filters1.8, libpcl-io1.8, libpcl-kdtree1.8, libpcl-octree1.8, libpcl-sample-consensus1.8, libpcl-search1.8, libpcl-segmentation1.8, libpcl-surface1.8, libpcl-visualization1.8, libstdc++6 (>= 5.2)
Python-Version: 3.6
Download-Size: 463 kB
APT-Manual-Installed: yes
APT-Sources: http://ppa.launchpad.net/sweptlaser/python3-pcl/ubuntu bionic/main amd64 Packages
Description: Python 3 binding to the Pointcloud library (PCL)
 The following parts of the API are wrapped (all methods operate on PointXYZ)
 point types:
 - I/O and integration; saving and loading PCD files
 - segmentation
 - SAC
 - smoothing
 - filtering
 - registration (ICP, GICP, ICP_NL)
 .
 This package installs the library for Python 3.

再就是opencv-python (3.4.1.15)

四元数

使用Python写这个由于没找到现成的类似eigen3的库, 所以自己写了个四元数, 用来从四元数转换到旋转矩阵, 顺便把平移的translation也写在这里面了.
里面这个四元数转换的旋转矩阵一开始按照《视觉SLAM十四讲》上面的公式, 后来发现用起来有点问题, 因为我们numpy array都用列向量来表示, 所以那个矩阵要转置一下, 不然之后的点的方位会有错误.

import numpy as np

class Quaternion:
    def __init__(self, w, x, y, z):
        '''
        @param: w, x, y, z
        '''
        self.w = w
        self.x = x
        self.y = y
        self.z = z
        self.vector = np.array([w, x, y, z])

    def __str__(self):
        imaginary = [' ', 'i ', 'j ', 'k]']
        result = '['
        for i in range(4):
            result = result + str(self.vector[i]) + imaginary[i]
        return result

    def __add__(self, quater):
        q = self.vector + quater.vector
        return Quaternion(q[0], q[1], q[2], q[3])

    def transformToRotationMatrix(self):
        q = self.vector.copy()
        # w, x, y, z = q[0], q[1], q[2], q[3]
        # the rotation matrix below was transposed
        r = np.array([
            [1 - 2*q[2]*q[2] - 2*q[3]*q[3], 2*q[1]*q[2] + 2*q[0]*q[3], 2*q[1]*q[3]-2*q[0]*q[2],   0],
            [2*q[1]*q[2] - 2*q[0]*q[3], 1 - 2*q[1]*q[1] - 2*q[3]*q[3], 2*q[2]*q[3] + 2*q[0]*q[1], 0],
            [2*q[1]*q[3] + 2*q[0]*q[2], 2*q[2]*q[3] - 2*q[0]*q[1], 1 - 2*q[1]*q[1] - 2*q[2]*q[2], 0],
            [0,     0,      0,      1]
        ])
       
        return r.transpose()

def translation(position):
    '''
    @param: position: a 1x3 numpy array, indicates the location of a point (x,y,z)
    '''
    x, y, z = position[0], position[1], position[2]

    T = np.array([
        [1, 0, 0, x],
        [0, 1, 0, y],
        [0, 0, 1, z],
        [0, 0, 0, 1]
    ])
    return T

点云拼接

python-pcl 的 PointCloud_PointXYZRGB有几个方法:

from_array(self, ndarray arr)
Fill this object from a 2D numpy array (float32)

from_file(self, char *f)
Fill this pointcloud from a file (a local path). Only pcd files supported currently.

from_list(self, _list)
Fill this pointcloud from a list of 3-tuples

这里我们使用了from_list, 或者转换成numpy array然后使用from_array也可以.
每个点的表示方式是float32格式的[X, Y, Z, RGB], RGB是一整个整数, 一开始我还以为是简单的三个255拼在一起, 后来发现不对劲. 于是看了PCL::PointXYZRGB的说明

A point structure representing Euclidean xyz coordinates, and the RGB color.
Due to historical reasons (PCL was first developed as a ROS package), the RGB information is packed into an integer and casted to a float. This is something we wish to remove in the near future, but in the meantime, the following code snippet should help you pack and unpack RGB colors in your PointXYZRGB structure:

// pack r/g/b into rgb
std::uint8_t r = 255, g = 0, b = 0;    // Example: Red color
std::uint32_t rgb = ((std::uint32_t)r << 16 | (std::uint32_t)g << 8 | (std::uint32_t)b);
p.rgb = *reinterpret_cast<float*>(&rgb);

可以看到RGB是rgb三个整数经过位运算后编码而成的一个整数

import cv2
import pcl
import pcl.pcl_visualization
import numpy as np
import quaternion

# camera intrinsics
cx = 325.5
cy = 253.5
fx = 518.0
fy = 519.0
depthScale = 1000.0

colorImgs, depthImgs = [], []

# read pose.txt
pose = []
with open('pose.txt', 'r') as f:
    for line in f.readlines():
        line = line.replace('\n', '')  # remove returns
        line = line.split(' ')  # split into 7 items
        vector = []
        for num in line:
            vector.append(float(num))
        vector = np.array(vector)
    # compute Rotation matrix based on quaternion
        quater = quaternion.Quaternion(vector[6], vector[3], vector[4], vector[5])
        R = quater.transformToRotationMatrix()
    # translation matrix
        position = np.array([vector[0], vector[1], vector[2]])  #x, y, z
        trans = quaternion.translation(position)
    # pose matrix
        # T =  trans * R  # wrong multiplication, should use dot
        
        T = np.dot(trans, R)
        pose.append(T)

# read color and depth images
view = []
for i in range(1,6):
    colorImg = cv2.imread(f"color/{i}.png")
    # cv2.imshow(f"Image{i}", colorImg)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()

    depthImg = cv2.imread(f"depth/{i}.pgm", cv2.IMREAD_UNCHANGED)

    height, width, channel  = colorImg.shape
    for v in range(height):
        for u in range(width):
        # get RBG value
            b = colorImg.item(v, u, 0)
            g = colorImg.item(v, u, 1)
            r = colorImg.item(v, u, 2)
            # pack RGB into PointXYZRGB structure, refer to PCL
            # http://pointclouds.org/documentation/structpcl_1_1_point_x_y_z_r_g_b.html#details
            # rgb = int(str(r)+str(g)+str(b))
            rgb = r << 16 | g << 8 | b

            depth = depthImg[v,u]
            if depth == 0:
                continue
            z = depth / depthScale
            x = (u - cx) * z/fx
            y = (v - cy) * z/fy
            # using homogeneous coordinate
            point = np.array([x, y, z, 1])
            point_world = np.dot(pose[i-1], point)
            # x,y,z,rgb
            # scene = np.insert(point_world, 3, rgb)
            scene = np.array([point_world[0], point_world[1], point_world[2], rgb], dtype=np.float32)
            view.append(scene)

colorCloud = pcl.PointCloud_PointXYZRGB()
colorCloud.from_list(view)
visual = pcl.pcl_visualization.CloudViewing()
visual.ShowColorCloud(colorCloud, b"cloud")
v = True
while v:
    v = not(visual.WasStopped())

最终结果是这样的, 跟C++的结果一样.
点云拼接结果

### 回答1: Python-PCL是一个Python绑定库,它提供了对PointCloud库的访问。点云网格化算法是将点云数据进行处理后生成一张网格表面的算法。网格化可以使点云数据更容易可视化、分析和处理。Python-PCL点云网格化算法可以将点云数据分割成均匀分布的三角形网格,并构建一个平滑的网格表面。 Python-PCL点云网格化算法的主要步骤包括: 1.加载点云数据并将其转换为PointNormal格式,以便于法线估计和网格化操作。 2.对点云数据进行法线估计。该过程使用一种求点云曲率的技术,将每个点的法线计算出来,并保存在其对应的点中。 3.将法线信息与点云数据结合,构建一个SurfaceReconstruction3D对象来执行网格化操作。在这个过程中,算法使用一个梯度下降优化算法,将点云数据映射到一个均匀分布的三角形网格上。优化约束条件限制每个三角形的边长,使网格表面更加平滑。 4.最后根据三角形间的相交情况对网格进行修复,并输出网格数据。在这个过程中,算法检查每个三角形是否与其他三角形相交,并尝试通过联通、压缩网格等修复操作,使网格曲面更加平滑。 Python-PCL点云网格化算法是一种实现点云数据可视化、处理和分析的有效工具。在3D打印、机器人视觉和虚拟现实等领域都有广泛的应用。 ### 回答2: Python-PCL是一个PythonPCL(点云库)封装库,允许用户在Python中使用PCL中的众多算法。点云网格化算法就是Python-PCL之中的一个非常重要的算法。 点云网格化算法是将点云数据转化为网格表示的过程,在这个过程中,将点云数据转换为一个等间距的二元矩阵表示。由于点云数据是一个由众多点组成的体,因此,这个矩阵是被空缺的网格填充而成的。在这个过程中,点云数据通过多次计算,不断地从自由形状变为一种规则形状,从而提高点云数据的处理效率。 点云网格化算法是通过点云曲面重构的算法实现的。曲面重构算法能够将点云数据转化为一个规则的几何模型,从而为相关应用提供了非常大的便捷,因此,点云网格化算法的应用非常广泛,例如:机器视觉,三维打印等方面。在Python-PCL的应用中,点云网格化算法的实现基于VTK(Visualization ToolKit)工具包,通过VTK包中的vtkPolyDataMapper类实现点云网格化。 点云网格化算法的实现需要通过多次迭代计算,使点云数据沿着均匀分布的空间方向发生变化,从而最终能够得到一种规则的几何形状。在实际应用中,点云数据可能会受到很多干扰,例如:噪音、数据不完整等因素,这对点云网格化算法的计算效率提出了非常高的要求,因此,Python-PCL提供了一系列优化的算法来满足实际应用的需求。 ### 回答3: Python-PCL是Point Cloud Library的Python封装库,提供了一组Python模块,可以在Python中使用PCL的功能。PCL是一个C++库,是开发点云处理算法和应用的一流工具,具有许多点云处理功能,如配准、滤波、分割、聚类、特征提取和识别等。 点云网格化是一种将点云转化为网格模型的技术。在点云数据中,所有的点都是离散的,而在网格模型中,点是有序的,因此点云网格化是将离散的点云数据转换为有序的网格数据的过程。 Python-PCL库提供了函数pcl.surface包来执行点云到三角网格转换,使用点云同步方法定义的半径搜索方式构建三角网格。 下面是一个简单的例程,它将点云转换为三角网格: ```python import pcl cloud = pcl.PointCloud.PointXYZRGB() mesh = cloud.make_mesh_cuboid() print('PointCloud before meshing') print(cloud) print('PointCloud after meshing') print(mesh.cloud) print(mesh.polygons) ``` 该例程首先定义了一个PointCloud对象,然后使用make_mesh_cuboid()函数将其转换为三角网格。最后,程序将输出PointCloud以及转换后的mesh。由于make_mesh_cuboid()函数是在一个立方体形状上生成网格对象,因此输出结果可能会有所不同。 总体而言,Python-PCL是一个非常强大的工具,它为Python程序员提供了使用点云数据处理的功能。尤其是对于点云网格化算法,Python-PCL提供了一个方便的方式来将点云数据转换为有序的网格数据。这个库是在点云领域做开发非常有帮助的,它为点云的开发和应用提供了大量的可靠和高效的处理工具。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值