第二章 python-pcl、open3d读取、显示pcd、bin等格式点云数据
第二章 python-pcl、open3d读取、显示pcd、bin格式点云数据
文章目录
- 第二章 python-pcl、open3d读取、显示pcd、bin格式点云数据
- 前言
- 环境
- 一、点云数据类型
- 1.基于python-pcl 读取显示pcd、bin格式文件
- 2.基于open3d 读取显示pcd格式文件
- 3.解析pcap格式点云文件并通过python-pcl显示
- 总结
前言
点云数据实际上就是许多组点的集合,每个点由{x,y,z}组成。当然理论上的只包含有3D坐标。
实际激光雷达获取的点云数据还会包含强度、反射率等等。但我们一般只用提取{x,y,z}来处理即可。
点云数据相比于其他传感器数据的核心优势就是在于 精准的深度信息。可惜获取具体的坐标信息。
环境
因为涉及到深度学习的应用,所以运用的整体环境是基于 python 使用pycharm编辑。
主要涉及库 python-pcl open3D mayavi numpy 等等用来处理点云数据并显示。
实际上点云的核心处理库应该是PCL 类似于图像处理中的Opencv 。后面也会有扩展。
一、点云数据类型
基于激光雷达录制的点云文件具有多种格式,如pcd、npy、ply、bin、pcap、lvx等等。
而读取点云数据也有多个库,python-pcl open3D mayavi numpy。
这里主要使用 python-pcl 和 open3D 两个核心库。
1.基于python-pcl 读取显示pcd、bin格式文件
代码如下(示例):
import numpy as np
import pcl.pcl_visualization
pt = pcl.load("D://code-python//Data//lidar//2094.799809520.pcd")#转为数组 形如 24000 x 3
points = pt.to_array()#但是pcl显示是要 N*4 所以要扩展一列 取一列插入数组使 N*3 变为 N*4
x = points[:,0]
points = np.insert(points,3,x,axis=1)# 这里对第四列进行赋值,它代表颜色值,根据你自己的需要赋值即可;
points[:, 3] = 255# PointCloud_PointXYZRGB 需要点云数据是N*4,分别表示x,y,z,RGB ,其中RGB 用一个整数表示颜色;
color_cloud = pcl.PointCloud_PointXYZRGB(points)
visual = pcl.pcl_visualization.CloudViewing()#窗口名
visual.ShowColorCloud(color_cloud, b'sta')flag = True
while flag:flag != visual.WasStopped()
这里就可以成功显示 颜色是根据自己设置
下面基于 numpy 读取bin格式点云文件
import pcl.pcl_visualization
import numpy as np# lidar_path 指定一个kitti 数据的点云bin文件就行了
#bin文件为2进制文件
lidar_path = r'D:/code-python/Data/lidar/000000.bin'# reshape成 N*4
points = np.fromfile(lidar_path, dtype=np.float32).reshape(-1, 4) # 在这里对第四列进行赋值,它代表颜色值,根据你自己的需要赋值即可;
points[:,3] = 255# PointCloud_PointXYZRGB 需要点云数据是N*4,分别表示x,y,z,RGB ,其中RGB 用一个整数表示颜色;
color_cloud = pcl.PointCloud_PointXYZRGB(points)
visual = pcl.pcl_visualization.CloudViewing()
visual.ShowColorCloud(color_cloud, b'cloud')
flag = True
while flag:flag != visual.WasStopped()
2.基于open3d 读取显示pcd格式文件
代码如下(示例):
import open3d as o3d
import numpy as nppoint = o3d.io.read_point_cloud("D:/code-python/Data/lidar/000000.pcd")o3d.visualization.draw_geometries([point])#open3d显示的时候有个bug 要把python pycharm设置为高性能 系统显示里 图形设置
效果相对于 python-pcl的显示还是差一点,不过也挺不错。同时是可以调的,它也是一个成熟的3D处理库。有许多内置的处理函数。
3.解析pcap格式点云文件并通过python-pcl显示
这里参考一位大佬的代码:
作者:lonlon ago
https://zhuanlan.zhihu.com/p/158621756
代码如下:
# -*- coding: UTF-8 -*-
import dpkt
import collections # 有序字典需要的模块
import time
import numpy as np
import struct# 安装了pcl , 可以使用它来进行可视化
import pcl.pcl_visualization
viewer = pcl.pcl_visualization.PCLVisualizering()#初始化一个对象
viewer.SetBackgroundColor(0, 0, 0) #颜色
viewer.AddCoordinateSystem()
viewer.InitCameraParameters()# vlp 16 的参数
'''
https://blog.csdn.net/qq_34911636/article/details/89946329#commentBox
激光雷达每一帧的数据长度固定为1248字节,其中分别为前42字节的前数据包标识、12组数据包、4字节时间戳和最后两字节雷达型号参数。
12组数据包中前两字节为数据包的开始标识(0xFFEE)、接下去两字节为的旋转角度(当前角度)值和连续32*(2字节的距离值+1字节的激光反射强度值)字节的距离信息,
其中32*3字节分别为雷达两次获取探测信息,每个数据包开头所携带的旋转角度是指当前数据包前16*3字节对应的角度,而后16*3字节对应的旋转角度激光雷达没有直接给出,
需要通过计算前后两次旋转角度然后求取平均值获得。
1248 = 42 + 12*(2 + 2 + 32*(2+1)) + 4 + 2 =1248雷达扫描频率为10Hz,每秒数据包在480帧左右,即每次扫描会产生48个左右的数据包,需要将分散的数据包数据合并称为一次扫描的点云数据
75个udp包产生一圈数据 vlp格式解析那篇文章 下面评论没理解 为什么是75 75*384*10 = 288000
若按照这样理解 角分辨率按照0.1度 360/0.1 = 3600 一圈转3600次 一次16个点 = 57600 10hz 1s 10圈 即 57600*10 = 576000 反正
有点乱
'''
DISTANCE_RESOLUTION = 0.002 # 距离数值分辨率 2mm转换为单位米
udp_package_num = 1
line_per_udp = 12 # 每个UDP 有多少列
point_per_udp_line = 32 # 每个UDP 的每列包含有多少个点
point_num_per_udp = point_per_udp_line * line_per_udp # 32*12=384thetas_lines = [-15, 1, -13, 3, -11, 5, -9, 7, -7, 9, -5, 11, -3, 13, -1, 15] #垂直角度w代表值
thetas_point = thetas_lines * 2 * line_per_udp * udp_package_num #感觉是嵌套列表 列表乘以一个数字 [[x],[x],[x]...]
thetas_point = np.radians(thetas_point) #角度从度转为弧度 thetas_point为输入的角度 它返回一个数组, 其中包含输入数组中给定度数的等效弧度角。
thetas_point_cos = np.cos(thetas_point) #cos弧度
thetas_point_sin = np.sin(thetas_point) #sin弧度data_fmt = '<' + (('H' + 'H' + 'HB' * point_per_udp_line) * line_per_udp + 'IH') * udp_package_num
base_range = np.array(range(2, point_per_udp_line*2+1, 2)) # 32, 距离值的基础索引
#range (start,stop,step) range(2,65,2) 32个数
angle_base_range = np.array([1])
d_range = []
r_range = []
angle_range = []
k = 0
data_gap = 2 + 2*point_per_udp_line # 每一列的长度 其实是2字节标识 2字节旋转角度 32*(2字节距离,1字节反射强度)点 这里貌似只计算旋转角度+距离66for i in range(udp_package_num):for j in range(line_per_udp):d_range.append(base_range + k * data_gap + i * 2) # 66 是 HH + HB*32 d.range 列表增加,多个列表嵌套r_range.append(base_range + k * data_gap + i * 2 + 1)angle_range.append(angle_base_range + k * data_gap + i * 2)k += 1
d_range = np.hstack(d_range) # 多个array组成的列表
r_range = np.hstack(r_range)
angle_range = np.hstack(angle_range)# 水平角度插值,如果有角度跳变会怎么样? 针对从360跳变到20的这部分拟合的并不是很好,误差很大;已经改正
x_index = np.arange(point_num_per_udp)
xp_index = np.arange(0, point_num_per_udp, point_per_udp_line) # array([ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352])def unpack_udp(data):data_tuple = struct.unpack(data_fmt, data) # 原始格式是元祖,要转array,元祖不能索引data_unpack = np.array(data_tuple, dtype=np.int64) # np.array会多耗时15毫秒 todo 这里为什么会报错?? 可能是时间戳的数值太大了distances = data_unpack[d_range] # 115200refs = data_unpack[r_range] / 255angles = data_unpack[angle_range]angles = np.radians(angles / 100).astype(np.float32) # 除以100再弧度值# 第一种处理角度的方式# angles = np.tile(angles, (32, 1)).flatten('F') # 因为angle只有1个,数据有32个,需要复制32次# 第二种方式angles_interp = np.interp(x_index, xp_index, angles).astype(np.float32)if angles[0] > angles[-1]: # 出现了角度的转折点# replace_angle = np.linspace(0,20,32) # 针对从360跳变到20 的角度替换change_index = np.argmax(angles)replace_index = change_index * 32 + 1interp_num_2 = int(angles[change_index+1]*32/40) # 每个UDP数据包之间的角度间隔为 40,每个包有32条线;interp_num_1 = 32 - interp_num_2replace_angle_1 = np.linspace(angles[change_index], 35999, interp_num_1) # 针对从360跳变到 20 的角度替换replace_angle_2 = np.linspace(0, angles[change_index+1], interp_num_2) # 针对从360跳变到 20 的角度替换angles_interp[replace_index:(replace_index+interp_num_1)] = replace_angle_1angles_interp[(replace_index+interp_num_1):(replace_index+32)] = replace_angle_2distances = distances * DISTANCE_RESOLUTIONx = distances * thetas_point_cos * np.sin(angles_interp)y = distances * thetas_point_cos * np.cos(angles_interp)z = distances * thetas_point_sinraw_points = np.stack((x, y, z), axis=1).astype(np.float32)# raw_points = np.stack((distances, angles_interp, refs, ), axis=1) # 也可以只要原始数据print(type(x))print(len(x)) #384一组 每个udp384一组#print(x)return raw_pointsdef main(file_path):# f = open(file_path) # 此写法为python2之下,f = open(file_path, mode='rb') #python3try:pcap = dpkt.pcap.Reader(f) # 先按.pcap格式解析,若解析不了,则按pcapng格式解析except:print("it is not pcap ... format, pcapng format...")pcap = dpkt.pcapng.Reader(f)# 接下来就可以对pcap做进一步解析了,记住在使用结束后最好使用f.close()关掉打开的文件,虽然程序运行结束后,# 系统会自己关掉,但是养成好习惯是必不可少的。当前变量pcap中是按照“间戳:单包”的格式存储着各个单包# 将时间戳和包数据分开,一层一层解析,其中ts是时间戳,buf存放对应的包all_pcap_data = collections.OrderedDict() # 有序字典# all_pcap_data_hex = collections.OrderedDict() # 有序字典,存十六进制形式cir_point = []i = 1for (ts, buf) in pcap:try:eth = dpkt.ethernet.Ethernet(buf) # 解包,物理层if not isinstance(eth.data, dpkt.ip.IP): # 解包,网络层,判断网络层是否存在,continueip = eth.data# if not isinstance(ip.data, dpkt.tcp.TCP): # 解包,判断传输层协议是否是TCP,即当你只需要TCP时,可用来过滤# continueif not isinstance(ip.data, dpkt.udp.UDP):#解包,判断传输层协议是否是UDPcontinuetransf_data = ip.data # 传输层负载数据,基本上分析流量的人都是分析这部分数据,即应用层负载流量if not len(transf_data.data): # 如果应用层负载长度为0,即该包为单纯的tcp包,没有负载,则丢弃continueif len( transf_data.data) != 1206: # 长度过滤 todo 为什么会有512字节的数据continueall_pcap_data[ts] = transf_data.data # 将时间戳与应用层负载按字典形式有序放入字典中,方便后续分析.points = unpack_udp(transf_data.data)if i % 76 != 0: # vlp16 每75个UDP数据包形成一圈数据cir_point.append(points)else:cir_udp = np.vstack(cir_point)print(cir_udp.shape) # 最后需要的一圈完整的点云数据 只包含了28000余个xyz坐标cloud_all = pcl.PointCloud(cir_udp[:, 0:3].astype(np.float32)) # 可视化viewer.AddPointCloud(cloud_all)viewer.SpinOnce(100)viewer.RemoveAllPointClouds(0)cir_point = []i += 1except Exception as err:print( "[error] %s" % err)f.close()if __name__ == '__main__':#file_path="D:xxxxxx.pcap"file_path = "2020-10-21-10-13-57_Velodyne-VLP-16-Data.pcap"main(file_path)
这里其实都是数据格式解析,要知道怎么样的数据格式,用什么方式能够更好的解析。
当然好的工具使用起来也是很舒服,感谢开发这些库的大佬们。
总结
本文仅仅简单介绍了基于python的不同类型点云数据读取、显示方法,这些都比较简单。
ubuntu下一般都是录制bag 文件,并通过rviz显示,后续可以扩展一下。
第二章 python-pcl、open3d读取、显示pcd、bin等格式点云数据相关推荐
- 【python第一章 基础捋顺,第二章 python基础语法】
第一章 基础捋顺,第二章 python基础语法 第一章 基础捋顺 第二章 python基础语法 2.1输入输出 2.2代码注释 2.3代码缩进 2.4命名规范 2.5变量 2.6基本数据类型 2.7数 ...
- 第二章 python系统监控
第二章 python系统监控 用Python来编写脚本简化日常的运维工作是Python的一个重要用途.在Linux下,有许多系统命令可以让我们时刻监控系统运行的状态,如ps,top,free等等.要获 ...
- Python面试宝典(第二章 Python基础)
Python面试宝典(第二章 Python基础) Python面试宝典(第二章 Python基础) 基础语法 输入输出 问题:代码中要修改不可变数据会出现什么问题? 抛出什么异常? 问题:a=1,b= ...
- 数字图像处理:第二章 图象获取、显示、表示与处理
第二章 图象获取.显示.表示与处理 图象获取是图象的数字化过程,显示则是将数字图象转化为适合人们使用的形式,而处理是通过软件对图象进行变换操作的过程. 目录 图象获取 图象显示 图象表示 图象处理 参 ...
- 2的10次方-1的python表达式_第二章PythonⅠ的基本语法,python,I
第二章 python基本语法 I 整数 交换两个变量的值 num1 = 10 num2 = 15 ##常规蛇形变换 tmp = num1 num1 = num2 num2 = tmp ##python ...
- python语言中、用来表示赋值的符号是_第二章Python语言基础知识
第二章Python语言基础知识 2.1 Python语言基础知识 2.1.1标识符与关键字 在Python语言中,对程序中各个元素命名加以区分,这种用来标识变量.函数.类等元素的符号称为标识符. Py ...
- python pandas库读取excel/csv中指定行或列数据详解
通过阅读表格,可以发现Pandas中提供了非常丰富的数据读写方法,下面这篇文章主要给大家介绍了关于python利用pandas库读取excel/csv中指定行或列数据的相关资料,需要的朋友可以参考下 ...
- python程序格式框架的描述_python 程序语言设计(嵩天)-学习笔记(第二章python 程序实例解析)...
第 2 章 python 程序实例解析 学习目标: 掌握解决计算问题的一般方法. 掌握python语言的基本语法,包括缩进.变量.命名等. 掌握python语言绘制图形的一般方法. 了解python标 ...
- 第二章 Python语言基本语法元素
文章目录 1.基本的语法元素 缩进 注释 续行符 2.变量 变量 常量 赋值语句 标识符 保留字 3.print()输出函数 1.基本的语法元素 缩进 1)Python语言采用严格的"缩进& ...
最新文章
- js 读取flask后台变量
- 初始python(二)
- php5(isapi).mysql5.zendforiis.rar_WIN2003系统IIS下PHP5+MySQL5+ZendOptimizer配置图解教程第1/3页...
- 报告解读丨细数万亿企服市场发展史,揭秘行业发展新趋势
- sqlite mysql pgsql_SQLite 、MySQL 与PostgreSQL三个关系型数据库的比较
- python拟合曲线的方式,Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】...
- 修改itunes备份路径的方法(奇奇怪怪的文件堆积C盘,别让文件成为最后的稻草哦)
- conn.execute
- python编写makefile_Python项目中的Makefiles
- 再谈CentOS 7程序自启动
- LINUX编译OPENJDK:--with-target-bits can only 32 or 64, you specified 64
- 颜色列表(中英文名称,RGB HSV CMYK值)
- stellarium-0.19.3.1-win64.exe下载
- spark编程ERROR01——java.lang.NullPointerException
- 百度、快手、商汤、旷视等重磅嘉宾确认出席AI ProCon 2019,你还剩1天早鸟票特权!...
- python 最速曲线
- 服务器系统和操作系统的区别
- CloudComparePCL 点云点匹配(基于点到面的距离)
- Nomad 服务编排
- 工具 网络游戏封包基础