一文搞懂pcd文件数据结构+如何读取pcd.bin文件(原理版和open3d简易版)

这篇文章介绍了pcd文件的数据结构及原理,我介绍了读取pcd bin file的简易方法以及使用open3d直接读取的简易方法(真的非常简便),如果你不想看原理直接拉到最后就好 :)

目录

pcd文件数据结构

        如何读取pcd bin 文件(原理版)

        一步到位简易读取 pcd bin file


pcd文件数据结构

首先我们来搞懂使用pcl生成的pcd文件的数据结构,我参考了这篇文章,在这里介绍下重点:The PCD (Point Cloud Data) file format — Point Cloud Library 1.14.1-dev documentation

 Example of the header fields: seperateded using new lines /n

# .PCD v0.7 - Point Cloud Data file format\n

VERSION 0.7\n

FIELDS x y z intensity\n

SIZE 4 4 4 4\n

TYPE F F F F\n

COUNT 1 1 1 1\n

WIDTH 2048\n

HEIGHT 128\n

VIEWPOINT 0 0 0 1 0 0 0\n

POINTS 262144\n

DATA binary\n

\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\....

pcd文件包含headersbinary数据:

headers包含整个数据集的主要信息,本数据集一共有262144个点,宽度是2048是lidar旋转一圈,一行有2048个点,height是128,代表每列有128个点,这些点组成了点云矩阵。

每个点包含四个信息 x y z intensity, 每个信息的数据类型是float,也就是包含4个bytes,一共4×8=32个bits。所以每4×4个bytes是一个点的全部信息,全部的信息长度是262144×16=4194304再加上前面的headers的长度。


如何读取pcd bin 文件(原理版)

我拥有的原始数据是同事从pcl生成的bin file,首先读取headers信息,然后把按照bytes读取的点赋值到相应的list当中,参考了很多代码,source列在这里:

https://github.com/nutonomy/nuscenes-devkit/blob/master/python-sdk/nuscenes/utils/data_classes.py

Reading Point Cloud .bin file using C++ - Stack Overflow

Conversion of binary lidar data (.bin) to point cloud data (.pcd) format - Stack Overflow

#source: https://github.com/nutonomy/nuscenes-devkit/blob/master/python-sdk/nuscenes/utils/data_classes.py
#source: https://stackoverflow.com/questions/65570879/reading-point-cloud-bin-file-using-c
#source:  https://stackoverflow.com/questions/60506331/conversion-of-binary-lidar-data-bin-to-point-cloud-data-pcd-format
def read_pcd_bin(binFilePath):
    """
    source: https://pointclouds.org/documentation/tutorials/pcd_file_format.html
    PCD file have headers:
    VERSION
    FIELDS
    SIZE
    TYPE
    COUNT
    WIDTH
    HEIGHT
    VIEWPOINT
    POINTS
    DATA
    
    Example of the header fields: seperateded using new lines /n
    # .PCD v0.7 - Point Cloud Data file format\n
    VERSION 0.7\n
    FIELDS x y z intensity\n
    SIZE 4 4 4 4\n
    TYPE F F F F\n
    COUNT 1 1 1 1\n
    WIDTH 2048\n
    HEIGHT 128\n
    VIEWPOINT 0 0 0 1 0 0 0\n
    POINTS 262144\n
    DATA binary\n
    \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
    """
    headers = []
    with open(binFilePath, mode = 'rb') as f:
        for line in f:
            line = line.strip().decode('utf-8')
            headers.append(line)
            if line.startswith('DATA'):
                break
        data_binary = f.read()

    # Get the headers and check if they appeared as expected
    assert headers[0].startswith('#')
    assert headers[1].startswith('VERSION')
    sizes = headers[3].split(' ')[1:] # first element is the name of header
    types = headers[4].split(' ')[1:] 
    type = ''.join(types)
    counts = headers[5].split(' ')[1:] 
    width = int(headers[6].split(' ')[1])
    height = int(headers[7].split(' ')[1])
    points = int(headers[9].split(' ')[1])
    data_format = headers[10].split(' ')[1]
    feature_nb = len(types) #4
    assert width > 0
    assert height > 0
    assert data_format == 'binary'
    
    sizes_int = [int(size) for size in sizes]
    sizes_sum = sum(sizes_int)
    list_pcd = []
    list_intensity = []
    
    # Decode each point
    for i in range (points):
        start = i * sizes_sum
        end = start +sizes_sum
        point = data_binary[start:end]
        x,y,z,intensity = struct.unpack(type.lower(), point)
        list_pcd.append([x,y,z])
        list_intensity.append(intensity)

    pcd_np = np.asarray(list_pcd)
    intensity_np = np.asarray(list_intensity)
    # Create Open3D point cloud
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(pcd_np)
    
    # Create a color map based on intensity
    intensity_normalized = (intensity_np - np.min(intensity_np)) / (np.max(intensity_np) - np.min(intensity_np))
    colors = o3d.utility.Vector3dVector(np.stack([intensity_normalized, np.zeros_like(intensity_normalized), np.zeros_like(intensity_normalized)], axis=1))
    pcd.colors = colors

    return pcd
# Example usage
file_name = './0000000120.bin'
pcd = read_pcd_bin(file_name)
o3d.visualization.draw_geometries([pcd])

一步到位简易读取 pcd bin file

我花了一上午再加上昨天2h,还和我同事一起研究pcd的结构,好不容易搞明白,但是我突然找到了一个open3d关于如何读取pcd文件的帖子,原来只需要把bin file的文件后缀改成。pcd,然后使用open3d的集成方法read_point_cloud就解决了这个问题,一整个大无语

Can't read pcd.bin format · Issue #680 · isl-org/Open3D · GitHub

filename = './0000000120.pcd'

pcd = o3d.io.read_point_cloud(filename, format='auto', remove_nan_points=False, remove_infinite_points=False, print_progress=False)
o3d.visualization.draw_geometries([pcd])

 这个浪费的时间能生成一篇文章,顿时感觉碎得没有那么难过了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值