LiDAR
LiDAR
(Light Deteation and Ranging
),激光探测及测距系统的简称,用激光器作为发射光源,采用光电探测技术手段的主动遥感设备,我们也称其为激光雷达。从名字上可以看出LIDAR
是一种主动测量方式,主要有激光发射部分、接收部分组成、信号处理部分组成,其主要功能就是测距和探测。
激光雷达的优点是具有极高的分辨率,抗干扰能力强,获取的信息量丰富,可全天时工作;缺点是容易受到大气条件以及工作环境的烟尘的影响。
激光雷达的类型很多,如下所示。车载激光雷达常用的是多线机械旋转的激光雷达。
单线雷达就是只有一个激光发射器和接收器,经过电机的旋转,投射到前面障碍物是一条线,这样的好处是数据量处理起来比较少,效率高,稳定性好,技术成熟,但是只能检测同一个高度的障碍物,不能测量整体轮廓,多应用于扫地机器人、酒店服务机器人
多线雷达目前市场有4
线、8
线、16
线、32
线、64
线、128
线,就是在垂直方向上具有多个发射器和接收器,通过电机的旋转,获得多条线束,线数越多,物体表面轮廓越完善,当然处理的数据量越大,对硬件要求越高;多线雷达主要应用在无人驾驶上,可以计算物体的高度信息,并对周围坏境进行3D
建模。每相连激光发射器之间形成的角度就是其角分辨率,一般各角度是相同的,但也有不等的,比如禾赛的40
线激光雷达,角分辨率0.33°
(-6°
到+2°
),角分辨率1°
(-16°
到-2°
,+2°
到+7°
);这样做的目的是可以充分捕捉远处物体的特征,不至于因视场角过大,激光器的射线在远距离时超出障碍物外而失效。
原理
测距
LiDAR
的首要工作就是测距,探测是在测距的基础上进行的。
时间测距
LiDAR
是利用发射和接收激光脉冲信号的时间差来实现对被测目标的距离测量,测距公式为:
其中R
是测量距离,c
是光速,t
是激光信号往返的时间差。
时间获取的方法主要脉冲法和相位法。
脉冲法(time of flight, TOF
)就是利用被测目标对激光脉冲的漫反射作用,通过接收和发射端的计时,来获取时间差。这种方法容易受到脉冲宽度和计数器时间分辨率的影响,测距很短的情况下,一个微小的时间偏差对于测距精度影响都很大,所以这种测距方法精度不是很高,但是工作方式简单,效率高,适合于精度要求不高的场景。
相位法(phase difference
),通过测量连续的调制波在待测距离上往返传播一次所产生的相位差,间接测定激光信号所传播的时间。相位法测距是根据波的周期性进行测距的,所以这里很重要的一点就是如何获取光波的整周期数,一般来说相位法测距精度可达到毫米级,优于脉冲法。
三角测距
LiDAR
中另外一种常见的测距方式为三角测量法(triangulation principle
)。这种测距方法的LiDAR
和时间测距法LiDAR
在结构上有一些差别,这种LiDAR
内部包含CMOS
元件,根据上下两个三角形相似原理计算距离:
探测
探测即探测物体在特定坐标系的坐标值。根据LiDAR
测量的距离S
、激光脉冲的竖直扫描角φ
、 水平扫描角Φ
,使用极坐标法可以得到物体的坐标:
点云
点云是某个坐标系下的点的数据集。点包含了丰富的信息,包括三维坐标X
,Y
,Z
、颜色、分类值、强度值、时间等等。主要是通过三维激光扫描仪进行数据采集获取点云数据,其次通过二维影像进行三维重建,在重建过程中获取点云数据,另外还有一些,通过三维模型来计算获取点
LiDAR
点云数据的定向,要通过多个坐标系间的几何关系来确定,包括激光扫描仪的参考坐标系、瞬时激光束坐标系、空中平台坐标系、目标所在水平参考坐标系与垂直坐标系和惯性导航仪的参考坐标系与WGS-84
坐标系。
KITT激光雷达点云数据处理
数据描述
KITTI
提供了Velodyne
激光雷达的点云数据用来进行3D
目标检测,点云数据被保存为二进制bin
文件,每个点包含3
个坐标和反射率信息,即 (x,y,z,r)
,坐标点存储在笛卡尔坐标系。
数据可视化
KITTI
官方提供了C++ SDK
进行点云数据的处理和开发,python
环境下可以使用numpy
进行数据的读取。在python
下可以选择的点云可视化工具基本只有mayavi
、python-pcl
或者open3d-python
这三个选项。其中前两者的安装较为复杂,这里使用open3d-python进行可视化操作。
pip3 install open3d
# or
pip install --user open3d
# or
python3 -m pip install --user open3d
# or
conda install -c open3d-admin -c conda-forge open3d
可视化代码如下,可以使用默认、距离或者反射强度来标定颜色。默认情况下以线数为标准分配颜色。
import numpy as np
import open3d
from matplotlib import cm
def cmap2rgb(cmap, step):
return np.asarray(getattr(cm, cmap)(step, bytes=True)[:3]) / 255
def vis_open3d(pointcloud, c_type='dist'):
# create point
points = pointcloud[:, 0: 3] # x,y,z position of point
r = pointcloud[:, 3] # reflectance value of point
col = None
if c_type == 'dist':
x = pointcloud[:, 0]
y = pointcloud[:, 1]
col = np.sqrt(x ** 2 + y ** 2) # Map Distance from sensor
elif c_type == 'reflect':
col = r
point_cloud = open3d.open3d.geometry.PointCloud()
point_cloud.points = open3d.open3d.utility.Vector3dVector(points)
if c_type != 'default':
col = ((col - np.min(col)) / (np.max(col) - np.min(col)) * 255).astype(np.int)
color = [cmap2rgb('viridis', col[i]) for i in range(col.shape[0])]
point_cloud.colors = open3d.utility.Vector3dVector(color)
# create Visualizer
vis = open3d.open3d.visualization.Visualizer()
vis.create_window(window_name="kitti")
vis.get_render_option().point_size = 1
opt = vis.get_render_option()
opt.background_color = np.asarray([0, 0, 0])
# show
# open3d.open3d.visualization.draw_geometries([point_cloud])
vis.add_geometry(point_cloud)
while True:
vis.update_geometry(point_cloud)
vis.poll_events()
vis.update_renderer()
if __name__ == '__main__':
path = 'E:\\BaiduNetdiskDownload\\LiDAR\\data_object_velodyne\\training\\velodyne\\000000.bin'
pointcloud = np.fromfile(path, dtype=np.float32, count=-1).reshape([-1,4])
print(pointcloud.shape)
# vis(pointcloud)
vis_open3d(pointcloud, 'default')
颜色越深距离越近。
颜色越深反射越小。