4. 基于深度学习的三维点云目标检测(PointPillars)
任务目标
本案例使用PointPillars模型对KITTI格式的三维点云进行目标检测,输出目标的3D边界框(中心坐标、尺寸、朝向角)与类别标签。实现范围:加载预训练模型权重,对单帧点云执行前向推理,解析并输出检测结果。
环境与依赖
- Ubuntu 20.04 / 22.04,Python 3.8+
- PyTorch ≥ 1.10,CUDA ≥ 11.3(CPU亦可运行,速度较慢)
- OpenPCDet(PointPillars官方实现库)
- 依赖安装:
pip install openpcdet torch numpy open3d
实现代码
以下代码完成从加载模型到输出检测结果的完整闭环。模型权重需预先下载(见下文说明)。
import torch
import numpy as np
from openpcdet.models import build_network
from openpcdet.config import cfg, cfg_from_yaml_file
from openpcdet.datasets import DatasetTemplate
class PointCloudProcessor(DatasetTemplate):
def __init__(self, cfg):
super().__init__(dataset_cfg=cfg.DATA_CONFIG, class_names=cfg.CLASS_NAMES, training=False)
self.cfg = cfg
def prepare_input(self, points):
"""将原始点云转换为模型输入格式"""
input_dict = {
'points': torch.from_numpy(points).float().cuda(),
'frame_id': 'demo'
}
data_dict = self.prepare_data(data_dict=input_dict)
return data_dict
def load_model(config_path, ckpt_path, class_names):
"""加载PointPillars模型与预训练权重"""
cfg_from_yaml_file(config_path, cfg)
cfg.CLASS_NAMES = class_names
cfg.MODEL.POST_PROCESSING.RECALL_MODE = 'specified'
model = build_network(model_cfg=cfg.MODEL, num_class=len(class_names), dataset=cfg.DATA_CONFIG)
checkpoint = torch.load(ckpt_path, map_location='cuda:0')
model.load_state_dict(checkpoint['model_state_dict'])
model.cuda().eval()
return model, cfg
def detect_objects(model, processor, points, threshold=0.3):
"""执行推理并返回检测结果"""
with torch.no_grad():
data_dict = processor.prepare_input(points)
pred_dicts, _ = model.forward(data_dict)
# 解析预测结果
boxes_3d = pred_dicts[0]['pred_boxes'].cpu().numpy() # [N, 7] (x,y,z,dx,dy,dz,heading)
scores = pred_dicts[0]['pred_scores'].cpu().numpy() # [N]
labels = pred_dicts[0]['pred_labels'].cpu().numpy() # [N]
# 置信度过滤
mask = scores >= threshold
return boxes_3d[mask], scores[mask], labels[mask]
if __name__ == '__main__':
# 配置路径(按实际路径修改)
CONFIG_PATH = 'tools/cfgs/kitti_models/pointpillar.yaml'
CKPT_PATH = 'pointpillar_7728.pth' # 预训练权重
CLASS_NAMES = ['Car', 'Pedestrian', 'Cyclist']
# 生成示例点云(模拟KITTI点云,实际使用时替换为真实数据)
np.random.seed(42)
demo_points = np.random.rand(5000, 4).astype(np.float32)
demo_points[:, 0] *= 40 # x范围0-40m
demo_points[:, 1] -= 20 # y范围-20~20m
demo_points[:, 2] *= 2 # z范围0-2m
# 加载模型与数据处理器
model, cfg = load_model(CONFIG_PATH, CKPT_PATH, CLASS_NAMES)
processor = PointCloudProcessor(cfg)
# 执行检测
boxes, scores, labels = detect_objects(model, processor, demo_points)
# 输出结果(预期输出:空检测,因随机点云无真实目标)
print(f'检测到 {len(boxes)} 个目标')
for i in range(len(boxes)):
print(f'类别: {CLASS_NAMES[labels[i]-1]}, 置信度: {scores[i]:.3f}')
print(f'3D框: cx={boxes[i][0]:.2f}, cy={boxes[i][1]:.2f}, cz={boxes[i][2]:.2f}, '
f'l={boxes[i][3]:.2f}, w={boxes[i][4]:.2f}, h={boxes[i][5]:.2f}, '
f'yaw={boxes[i][6]:.3f} rad')
运行与验证
- 准备权重:从OpenPCDet官方模型库下载PointPillars KITTI预训练权重(文件名
pointpillar_7728.pth),放入当前目录。 - 运行:
python pointpillars_demo.py - 验证方法:使用真实KITTI点云数据(替换
demo_points为实际点云数组,shape为[N,4],列为x,y,z,intensity),观察输出3D框是否与点云中的车辆/行人位置吻合。判定通过条件:程序无报错运行完成,输出检测目标数量与真实场景目视相符(如KITTI样本通常检测到5~15个目标),且3D框中心坐标位于点云有效范围内。
预期输出说明:上述代码使用随机点云作为输入,因无真实目标,预期输出为检测到 0 个目标。若替换为KITTI真实数据(如编号000008.bin),将输出对应检测框信息。
关键说明
- PointPillars将点云划分为垂直柱体(Pillar),通过特征编码网络提取特征,再经2D卷积骨干网络与检测头输出3D框。本案例聚焦推理闭环,训练过程不在范围内。
- 若需可视化检测结果,可使用Open3D:
o3d.visualization.draw_geometries([pcd, boxes]),其中boxes由boxes_3d转换得到。 - 模型对输入点云范围敏感,KITTI默认检测范围x∈[0,69.12],y∈[-39.68,39.68],z∈[-3,1]。超出范围的点会被预处理过滤。