一、概述
3D LiDAR目标检测是一种在三维空间中识别和定位感兴趣目标的技术。在自动驾驶系统和先进的空间分析中,目标检测方法的不断演进至关重要。3D LiDAR目标检测作为一种变革性的技术,在环境感知方面提供了前所未有的准确性和深度信息.
在这里,我们将深入探讨使用关键点特征金字塔网络(K-FPN)结合KITTI 360 Vision数据集,融合RGB相机和3D LiDAR数据,实现自动驾驶的详细过程和训练方法。
二、3D 点云中的目标检测
3D目标检测的核心在于识别和定位三维空间中的物体。与仅考虑图像平面上的高度和宽度的2D检测不同,3D检测还融入了深度信息,从而提供了完整的空间理解。这对于自动驾驶、机器人技术和增强现实等应用至关重要,因为这些领域与环境的交互是三维的.
2.1 人类深度感知
3D目标检测背后的基本直觉源于人类感知深度的方式。人类视觉利用阴影、透视和视差等线索推断第三维。类似地,3D检测算法利用几何形状、阴影和点的相对运动来辨别深度。
2.2 数字深度感知
Shuiwang Ji等人在他们的研究论文《3D Convolutional Neural Networks for Human Action Recognition》中首次提出了3D - CNN的概念。他们的模型能够通过执行3D卷积从空间和时间维度提取特征,从而捕捉多个相邻帧中编码的运动信息。这个特定模型从输入帧生成多个信息通道,最终的特征表示结合了所有通道的信息。
3D环境的表示通常通过点云实现,点云是三维坐标系中的顶点集合。这些顶点通常来自结构光或激光雷达(LiDAR)传感器。3D检测的一个关键方面是将这些点云转换为可处理的格式,以便识别目标。这涉及到分割,即将点云划分为可能代表目标的簇,然后将这些簇分类为已知类别,如汽车、行人或其他感兴趣的目标。
这里的技术挑战很大,因为点云数据具有稀疏性和可变性。与2D图像中的像素不同,3D空间中的点分布不均匀,并且其密度会随与传感器的距离而变化。诸如PointNet及其后续版本(如PointNet++)等复杂算法可以直接处理点云,学习对排列不变且对遮挡和杂乱具有鲁棒性的特征。
2.3 3D点云环境中目标检测的特殊性
在3D点云环境中检测目标引入了传统2D目标检测中不存在的几个特殊特征:
- 深度估计:最显著的特征之一是深度估计,它允许确定目标与传感器的距离。在点云中直接测量深度,而在2D图像中则必须推断深度。
- 体积估计:算法可以利用数据的体积性质,考虑目标的实际形状和大小。这与2D边界框不同,2D边界框仅近似目标在图像平面中的占位面积。
- 6DoF(六个自由度)目标姿态:3D检测算法不仅定位目标,还确定其在空间中的方向,提供完整的6DoF姿态估计(三个用于位置,三个用于旋转)。
- 尺度不变性:检测过程可以对目标的尺度不变。这对于基于LiDAR的系统尤为重要,因为目标可能出现在不同距离,因此具有不同尺度。
- 动态环境中的时间连续性:先进的3D目标检测系统利用动态环境中的时间连续性。通过跟踪点云数据随时间的变化,它们可以预测移动目标的轨迹和速度。
三、 论文综述
3.1 VoxelNet
Yin Zhou和Oncel Tuzel提出了VoxelNet——一种基于点云的3D目标检测的端到端学习方法。VoxelNet创新地将点云划分为结构化的3D体素网格,并采用独特的体素特征编码层将每个体素内的点转换为全面的特征表示。该表示与区域建议网络(RPN)无缝集成,以生成目标检测结果。在KITTI汽车检测基准测试中,VoxelNet显著优于现有的基于LiDAR的检测方法,并展示了学习不同目标表示的卓越能力,其在检测行人和自行车方面也取得了有前景的结果。
3.2 BirdNet
Jorge Beltrán等人引入了BirdNet——一个基于LiDAR信息的3D目标检测框架。他们的方法首先对激光数据的鸟瞰图投影进行创新的单元编码,然后使用从图像处理技术改编的卷积神经网络估计目标位置和方向。最后阶段涉及后处理,以巩固3D定向检测。在KITTI数据集上进行验证时,他们的框架不仅在该领域设定了新标准,还在不同LiDAR系统中表现出通用性,证实了其在现实交通条件下的稳健性。
3.3 VirConvNet
Hai Wu等人提出了VirConvNet,这是一种新颖且高效的骨干网络,旨在提高检测性能同时管理计算负载。VirConvNet的核心是两个创新组件:StVD(随机体素丢弃),它有策略地减少冗余体素计算;NRConv(抗噪子流形卷积),它通过利用2D和3D数据稳健地编码体素特征。作者展示了他们管道的三个变体:VirConv - L用于效率,VirConv - T用于精度,VirConv - S用于半监督方法。令人印象深刻的是,他们的管道在KITTI汽车3D检测排行榜上取得了顶级排名,VirConv - S领先,VirConv - L具有快速推理时间。
Peixuan Li等人开发了一种新颖的单目3D检测框架,能够进行高效且准确的单次预测。他们的方法摆脱了对传统2D边界框约束的依赖,创新性地从单目图像预测3D边界框的九个关键点,利用几何关系准确推断3D空间中的尺寸、位置和方向。即使在有噪声的关键点估计情况下,这种方法也被证明是稳健的,其紧凑的架构有助于实现快速检测速度。值得注意的是,他们的训练方案不需要外部网络依赖或监督数据。该框架成为第一个用于单目图像3D检测的实时系统,在KITTI数据集上设定了新的性能基准。
四、 用于3D LiDAR目标检测的数据集可视化
4.1 KITTI 360 Vision数据集
在这里将使用KITTI 360 Vision数据集进行训练过程。这是一个相对较大的数据集,因此需要进行3D LiDAR可视化以进行探索性数据分析(EDA)过程。以下是该实验的一些可视化结果。
可视化突出了来自传感器的3D LiDAR数据的三维表示。然而,在RGB相机流上可视化3D边界框也很重要,这对于开发先进驾驶辅助系统(ADAS)至关重要。为此,您必须首先下载数据集并创建目录结构。以下是KITTI 360 Vision数据集特定文件的链接:
- Velodyne点云 - 激光信息(29GB)
- 对象数据集的训练标签(5MB)
- 对象数据集的相机校准矩阵(16MB)
- 对象数据集的左彩色图像(12GB) - 用于可视化
现在安排文件,使目录结构如下所示:
kitti
├── demo|
└── calib.txt
├── gt_database
├── gt_database_mm
├── ImageSets
├── train.txt|
├── test.txt|
└── valid.txt
├── training
├── image_2
├── label_2
├── calib
└── velodyne
├── testing
├── image_2
├── calib
└── velodyne
├── kitti_dbinfos_train.pkl
├── kitti_dbinfos_train_mm.pkl
├── kitti_infos_train.pkl
├── kitti_infos_trainval.pkl
├── kitti_infos_val.pkl
└── kitti_infos_test.pkl
花点时间探索代码库中kitti_dataset.py
文件里定义的KittiDataset
类中的方法。可以通过滚动到本研究文章的代码演练部分或点击此处下载代码。
这个KittiDataset
类是一个自定义数据集类,适用于加载和操作来自KITTI 360 Vision数据集的数据。这个数据集类针对不同的操作模式(如训练('train'
)、验证('val'
)和测试('test'
))进行了定制,并通过configs
参数进行配置,该参数包含目录路径、输入大小和类别数量等设置。这是在data_process
目录中的kitti_dataset.py
脚本中实现的。
以下是类方法及其功能的细分:
def __init__(self, configs, mode='train', lidar_aug=None, hflip_prob=None, num_samples=None):
self.dataset_dir = configs.dataset_dir
self.input_size = configs.input_size
self.hm_size = configs.hm_size
self.num_classes = configs.num_classes
self.max_objects = configs.max_objects
assert mode in ['train', 'val', 'test'], 'Invalid mode: {}'.format(mode)
self.mode = mode
self.is_test = (self.mode == 'test')
sub_folder = 'testing' if self.is_test else 'training'
self.lidar_aug = lidar_aug
self.hflip_prob = hflip_prob
self.image_dir = os.path.join(self.dataset_dir, sub_folder, "image_2")
self.lidar_dir = os.path.join(self.dataset_dir, sub_folder, "velodyne")
self.calib_dir = os.path.join(self.dataset_dir, sub_folder, "calib")
self.label_dir = os.path.join(self.dataset_dir, sub_folder, "label_2")
split_txt_path = os.path.join(self.dataset_dir, 'ImageSets', '{}.txt'.format(mode))
self.sample_id_list = [int(x.strip()) for x in open(split_txt_path).readlines()]
if num_samples is not None:
self.sample_id_list = self.sample_id_list[:num_samples]
self.num_samples = len(self.sample_id_list)
这个初始化方法通过初始化各种数据目录(图像、LiDAR、校准和标签)的路径来设置数据集,并根据操作模式创建要使用的样本ID列表。它可以可选地应用LiDAR数据增强(lidar_aug
)和水平翻转(hflip_prob
)进行数据增强。如果指定了num_samples
,数据集将相应地截断其长度。
def __len__(self):
return len(self.sample_id_list)
此方法返回数据集中的样本数量,允许PyTorch的DataLoader
正确迭代数据集。
def __getitem__(self, index):
if self.is_test:
return self.load_img_only(index)
else:
return self.load_img_with_targets(index)
此方法从数据集中检索单个数据点。如果模式为“test”,它调用load_img_only
,仅检索图像数据。对于“train”或“val”,它调用load_img_with_targets
以获取图像数据和相应的目标标签。
def load_img_only(self, index):
"""Load only image for the testing phase"""
sample_id = int(self.sample_id_list[index])
img_path, img_rgb = self.get_image(sample_id)
lidarData = self.get_lidar(sample_id)
lidarData = get_filtered_lidar(lidarData, cnf.boundary)
bev_map = makeBEVMap(lidarData, cnf.boundary)
bev_map = torch.from_numpy(bev_map)
metadatas = {
'img_path': img_path,
}
return metadatas, bev_map, img_rgb
此方法在测试阶段用于仅加载图像数据及其相关元数据,因为测试期间不使用标签。
def load_img_with_targets(self, index):
"""Load images and targets for the training and validation phase"""
sample_id = int(self.sample_id_list[index])
img_path = os.path.join(self.image_dir, '{:06d}.png'.format(sample_id))
lidarData = self.get_lidar(sample_id)
calib = self.get_calib(sample_id)
labels, has_labels = self.get_label(sample_id)
if has_labels:
labels[:, 1:] = transformation.camera_to_lidar_box(labels[:, 1:], calib.V2C, calib.R0, calib.P2)
if self.lidar_aug:
lidarData, labels[:, 1:] = self.lidar_aug(lidarData, labels[:, 1:])
lidarData, labels = get_filtered_lidar(lidarData, cnf.boundary, labels)
bev_map = makeBEVMap(lidarData, cnf.boundary)
bev_map = torch.from_numpy(bev_map)
hflipped = False
if np.random.random() < self.hflip_prob:
hflipped = True
# C, H, W
bev_map = torch.flip(bev_map, [-1])
targets = self.build_targets(labels, hflipped)
metadatas = {
'img_path': img_path,
'hflipped': hflipped
}
return metadatas, bev_map, targets
此方法加载用于训练或验证的图像和目标标签。它应用任何指定的LiDAR增强,并在需要时处理翻转鸟瞰图(BEV)映射。它还构建用于目标检测的目标,包括热图、中心偏移、尺寸和方向。
def get_image(self, idx):
img_path = os.path.join(self.image_dir, '{:06d}.png'.format(idx))
img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)
return img_path, img
此方法获取图像文件路径并使用OpenCV加载它,将其从BGR转换为RGB格式。
def get_calib(self, idx):
calib_file = os.path.join(self.calib_dir, '{:06d}.txt'.format(idx))
# assert os.path.isfile(calib_file)
return Calibration(calib_file)
此方法检索指定索引的校准数据,这对于在相机和LiDAR坐标系之间进行转换至关重要。
def get_lidar(self, idx):
lidar_file = os.path.join(self.lidar_dir,