tracking资料存放在/kitti_folder/tracking中
jupyter工程存放在/test3_autodrive_ws/src/jupyter_prj下的3D_tracking.ipynb
数据文件存放在/home/qinsir/kitti_folder/tracking/data_tracking_label_2/training/label_02
下,可以看到是txt文件,选择0000
标定程序的代码在test3_autodrive_ws/src/demo1_kitti_pub_photo/scripts/calibration.py文件夹下
对于已有数据在点云中绘制3D框已经有很多优秀的案例,这里选择在浏览器中键入visualize kitti lidar
选择"Alex Staravoitau’bolg"如下进行参考,进入点击查看plot3D的绘制的github源码
如下:
阅读资料后发现,我们只需要取绘制点云地图和绘制3D框的函数即可.
点云地图以velodyne为坐标中心,而计算出来的tracking框以camera为原点,必然存在旋转和平移的关系.
这里只介绍本节需要用到的,新的包:
...
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import sys
import os
sys.path.append('../demo1_kitti_pub_photo/scripts')
from data_utils import *
已经更改过的draw_point_cloud
函数
axes_limits = [
[-20, 80], # X axis range
[-20, 20], # Y axis range
[-3, 10] # Z axis range
axes_str = ['X', 'Y', 'Z']
ax.grid(False) #不要画出栅格
从本地TXT文件读取点云数据比较简单
DATA_PATH = '/home/qinsir/kitti_folder/2011_09_26/2011_09_26_drive_0005_sync'
points = read_point_cloud(os.path.join(DATA_PATH, 'velodyne_points/data/%010d.bin'%0)) #点云data的 path
这里调用之前的函数查看的是3D的点云:
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
draw_point_cloud(ax, points[::5]) #每5个点画一个
函数还为我们提供了2D显示接口:
fig, ax = plt.subplots(figsize=(20, 10))
draw_point_cloud(ax, points[::5], axes=[0, 1]) #只在xoy平面上,俯视图
本函数无需改动,可直接使用:
def draw_box(pyplot_axis, vertices, axes=[0, 1, 2], color='black'):
"""
Draws a bounding 3D box in a pyplot axis.
Parameters
----------
pyplot_axis : Pyplot axis to draw in.
vertices : Array 8 box vertices containing x, y, z coordinates.
axes : Axes to use. Defaults to `[0, 1, 2]`, e.g. x, y and z axes.
color : Drawing color. Defaults to `black`.
"""
vertices = vertices[axes, :]
connections = [
[0, 1], [1, 2], [2, 3], [3, 0], # Lower plane parallel to Z=0 plane
[4, 5], [5, 6], [6, 7], [7, 4], # Upper plane parallel to Z=0 plane
[0, 4], [1, 5], [2, 6], [3, 7] # Connections between upper and lower planes
]
for connection in connections:
pyplot_axis.plot(*vertices[:, connection], c=color, lw=0.5)
输入tracking中的数据点,得到一个8个点,分别是点长方体的8个点,并绘制:
corners_3d_cam2 = compute_3d_box_cam2(*df_tracking.loc[2, ['height', 'width', 'length', 'pos_x', 'pos_y', 'pos_z', 'rot_y']])
#3是x,y,z,8是一共长方体的8个定点定位
#绘制
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
#得到corners_3d_cam2是在照相机坐标系下得到的,所以会出现如下所示的略微奇怪的长方体
#为了可视化,应该再转为velodyne坐标系下
draw_box(ax, corners_3d_cam2)
从2.2.1我们可以看到,坐标系需要经过从cam->velodyne的过程才可以正常显示:
calib = Calibration('/home/qinsir/kitti_folder/2011_09_26', from_video=True)
corners_3d_velo = calib.project_ref_to_velo(corners_3d_cam2.T).T
corners_3d_velo
#绘制
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
#同一坐标系下绘制出即可
draw_point_cloud(ax, points[::5])
draw_box(ax, corners_3d_velo, color='r')
效果展示:
这里以俯视图为例:
fig, ax = plt.subplots(figsize=(20, 10))
draw_point_cloud(ax, points[::5], axes=[0, 1])
draw_box(ax, corners_3d_velo, axes=[0, 1], color='r')
源码已上传至我的博客,3D_tracking.ipynb
不先麻烦,源码如下:
import pandas as pd #读取csv等
import matplotlib.pyplot as plt #画出图形资料包
from mpl_toolkits.mplot3d import Axes3D #画3D的轴的资料包
import numpy as np
import sys
import os
sys.path.append('../demo1_kitti_pub_photo/scripts')
from data_utils import *
def draw_point_cloud(ax, title, axes=[0, 1, 2], point_size=0.1,xlim3d=None, ylim3d=None, zlim3d=None):
"""
Convenient method for drawing various point cloud projections as a part of frame statistics.
"""
#范围限制
axes_limits = [
[-20, 80], # X axis range
[-20, 20], # Y axis range
[-3, 10] # Z axis range
]
axes_str = ['X', 'Y', 'Z']
ax.grid(False) #不要画出栅格
ax.scatter(*np.transpose(points[:, axes]), s=point_size, c=points[:, 3], cmap='gray')
ax.set_title(title)
ax.set_xlabel('{} axis'.format(axes_str[axes[0]]))
ax.set_ylabel('{} axis'.format(axes_str[axes[1]]))
if len(axes) > 2:
ax.set_xlim3d(*axes_limits[axes[0]])
ax.set_ylim3d(*axes_limits[axes[1]])
ax.set_zlim3d(*axes_limits[axes[2]])
ax.set_zlabel('{} axis'.format(axes_str[axes[2]]))
else:
ax.set_xlim(*axes_limits[axes[0]])
ax.set_ylim(*axes_limits[axes[1]])
# User specified limits
if xlim3d!=None:
ax.set_xlim3d(xlim3d)
if ylim3d!=None:
ax.set_ylim3d(ylim3d)
if zlim3d!=None:
ax.set_zlim3d(zlim3d)
DATA_PATH = '/home/qinsir/kitti_folder/2011_09_26/2011_09_26_drive_0005_sync'
points = read_point_cloud(os.path.join(DATA_PATH, 'velodyne_points/data/%010d.bin'%0)) #点云data的 path
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
draw_point_cloud(ax, points[::5]) #每5个点画一个
fig, ax = plt.subplots(figsize=(20, 10))
draw_point_cloud(ax, points[::5], axes=[0, 1]) #只在xoy平面上,俯视图
df_tracking = read_tracking('/home/qinsir/kitti_folder/tracking/data_tracking_label_2/training/label_02/0000.txt')
df_tracking.head()
# 3D侦测框需要后边height, width, len, pos_x, y, z(相机坐标系里的坐标), rot_y(从上往下看旋转的角度)
# 根据长宽高XYZ和旋转角坐标定位并画出3D框
def compute_3d_box_cam2(h, w, l, x, y, z, yaw):
'''
return : 3xn in cam2 coordinate
'''
R = np.array([[np.cos(yaw), 0, np.sin(yaw)], [0, 1, 0], [-np.sin(yaw), 0, np.cos(yaw)]])
x_corners = [l/2, l/2, -l/2, -l/2, l/2, l/2, -l/2, -l/2]
y_corners = [0, 0, 0, 0, -h, -h, -h, -h]
z_corners = [w/2, -w/2, -w/2, w/2, w/2, -w/2, -w/2, w/2]
corners_3d_cam2 = np.dot(R, np.vstack([x_corners, y_corners, z_corners]))
corners_3d_cam2 += np.vstack([x, y, z])
return corners_3d_cam2
def draw_box(pyplot_axis, vertices, axes=[0, 1, 2], color='black'):
"""
Draws a bounding 3D box in a pyplot axis.
Parameters
----------
pyplot_axis : Pyplot axis to draw in.
vertices : Array 8 box vertices containing x, y, z coordinates.
axes : Axes to use. Defaults to `[0, 1, 2]`, e.g. x, y and z axes.
color : Drawing color. Defaults to `black`.
"""
vertices = vertices[axes, :]
connections = [
[0, 1], [1, 2], [2, 3], [3, 0], # Lower plane parallel to Z=0 plane
[4, 5], [5, 6], [6, 7], [7, 4], # Upper plane parallel to Z=0 plane
[0, 4], [1, 5], [2, 6], [3, 7] # Connections between upper and lower planes
]
for connection in connections:
pyplot_axis.plot(*vertices[:, connection], c=color, lw=0.5)
#先预览一个框, 得到一个3D侦测框
corners_3d_cam2 = compute_3d_box_cam2(*df_tracking.loc[2, ['height', 'width', 'length', 'pos_x', 'pos_y', 'pos_z', 'rot_y']])
#3是x,y,z,8是一共长方体的8个定点定位
corners_3d_cam2.shape
#绘制
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
#得到corners_3d_cam2是在照相机坐标系下得到的,所以会出现如下所示的略微奇怪的长方体
#为了可视化,应该再转为velodyne坐标系下
draw_box(ax, corners_3d_cam2)
from calibration import *
calib = Calibration('/home/qinsir/kitti_folder/2011_09_26', from_video=True)
#经过矫正到velodyne的函数,入口参数为从cam到velodyne
#需要8X3,转置一下
corners_3d_velo = calib.project_ref_to_velo(corners_3d_cam2.T).T
corners_3d_velo
#转换完之后,每一列就是它的一个的点的坐标
#绘制
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
#已经转为velodyne坐标系下,可以正常显示
draw_box(ax, corners_3d_velo)
#绘制
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111,projection='3d')
ax.view_init(40, 150) #观看角度
#同一坐标系下绘制出即可
draw_point_cloud(ax, points[::5])
draw_box(ax, corners_3d_velo, color='r')
fig, ax = plt.subplots(figsize=(20, 10))
draw_point_cloud(ax, points[::5], axes=[0, 1])
draw_box(ax, corners_3d_velo, axes=[0, 1], color='r')