16 KiB
Executable File
16 KiB
Executable File
模型输出评测方案设计
1. 评测概述
1.1 评测目标
- 2D检测评测: 评估所有类别的2D边界框检测性能
- 3D检测评测: 评估3D类别的空间定位和朝向估计性能
1.2 评测类别划分
- 3D目标类别 (0-3): vehicle, pedestrian, bike, rider
- 纯2D目标类别 (4-13): roadblock, head, tsr, guideboard, plate, wheel, tl_border, tl_wick, tl_num, tricycle
2. 数据格式解析
2.1 真值数据格式
2.1.1 3D类别真值格式
完整3D标注(车辆类别)- 50个值:
[label, x, y, w, h, # 0-4: 类别和2D框(归一化)
x3d_ori, y3d_ori, z3d_ori, # 5-7: 原始3D中心点
l3d, h3d, w3d, # 8-10: 3D尺寸
rot_y, # 11: 旋转角
xc_ori, yc_ori, # 12-13: 原始中心点2D投影
xc_ori_d, yc_ori_d, # 14-15: 深度相关中心点
alpha_ori, # 16: 原始alpha角
0, # 17: 占位符
# 前面 (18-25)
x3d_front, y3d_front, z3d_front, alpha_front, xc_front, yc_front, score_front, is_occ_front,
# 后面 (26-33)
x3d_back, y3d_back, z3d_back, alpha_back, xc_back, yc_back, score_back, is_occ_back,
# 左面 (34-41)
x3d_left, y3d_left, z3d_left, alpha_left, xc_left, yc_left, score_left, is_occ_left,
# 右面 (42-49)
x3d_right, y3d_right, z3d_right, alpha_right, xc_right, yc_right, score_right, is_occ_right]
完整3D标注(非车辆类别)- 18个值:
[label, x, y, w, h, # 0-4: 类别和2D框(归一化)
x3d_ori, y3d_ori, z3d_ori, # 5-7: 3D中心点
l3d, h3d, w3d, # 8-10: 3D尺寸
rot_y, # 11: 旋转角
xc_ori, yc_ori, # 12-13: 中心点2D投影
xc_ori_d, yc_ori_d, # 14-15: 深度相关中心点
alpha_ori, # 16: alpha角
0] # 17: 占位符
仅2D标注 - 6个值:
[label, x, y, w, h, -1] # 最后一位为-1表示无3D标注
2.1.2 纯2D类别真值格式(6个值)
[label, x, y, w, h, -1] # label ∈ {4,5,6,7,8,9,10,11,12,13}
2.2 检测结果格式
2.2.1 3D类别检测格式(15个值)
车辆类别:
vehicle 0.95 368.08 574.17 437.89 617.20 cam -30.14 1.43 68.55 5.52 2.50 2.31 2.70 left
[label, conf, x1, y1, x2, y2, coord_sys, x3d, y3d, z3d, l3d, h3d, w3d, rot_y, face_type]
注:face_type可以是 front, back, left, right,也支持 rear 和 tail 作为 back 的别名
非车辆类别:
pedestrian 0.95 368.08 574.17 437.89 617.20 cam -30.14 1.43 68.55 5.52 2.50 2.31 2.70 whole
[label, conf, x1, y1, x2, y2, coord_sys, x3d, y3d, z3d, l3d, h3d, w3d, rot_y, whole]
2.2.2 纯2D类别检测格式(5个值)
plate 0.94246 532.12 203.26 558.73 214.86
[label, conf, x1, y1, x2, y2]
3. 评测指标设计
3.1 2D检测指标
3.1.1 基础指标
- Precision (精确率): TP / (TP + FP)
- Recall (召回率): TP / (TP + FN)
- AP (Average Precision): PR曲线下面积,IoU阈值=0.5
- mAP (mean Average Precision): 所有类别AP的平均值
3.1.2 匹配规则
- IoU阈值: 0.5
- 匹配策略:
- 计算预测框与真值框的IoU
- 按置信度从高到低排序预测框
- 每个真值框最多匹配一个预测框
- IoU >= 0.5 且类别相同视为匹配成功(TP)
- 未匹配的预测框为FP,未匹配的真值框为FN
3.1.3 分类别评测
- 对每个类别分别计算 Precision, Recall, AP
- 类别包括: vehicle, pedestrian, bike, rider, roadblock, head, tsr, guideboard, plate, wheel, tl_border, tl_wick, tl_num, tricycle
3.1.4 整体评测
- 总Precision: 所有类别的总TP / (总TP + 总FP)
- 总Recall: 所有类别的总TP / (总TP + 总FN)
- mAP: 所有类别AP的算术平均
3.2 3D检测指标
3.2.1 评测范围
仅评测3D类别:vehicle, pedestrian, bike, rider
3.2.2 前提条件
只有在2D检测匹配成功(IoU >= 0.5)且真值包含完整3D标注的情况下,才进行3D指标评测
3.2.3 3D评测指标
车辆类别的测距误差计算:
车辆类别需要根据预测结果中的最近面信息(front/back/left/right),选取真值中对应的最近面中心点进行比较:
- 根据预测结果中的
face_type字段(front/back/left/right),确定预测的最近面 - 从真值的4个面信息中,选取对应面的中心点坐标
- 计算预测最近面中心点与真值对应面中心点的误差
# 车辆类别
face_mapping = {
'front': [18, 19, 20], # x3d_front, y3d_front, z3d_front 在真值中的索引
'back': [26, 27, 28], # x3d_back, y3d_back, z3d_back
'left': [34, 35, 36], # x3d_left, y3d_left, z3d_left
'right': [42, 43, 44] # x3d_right, y3d_right, z3d_right
}
# 根据预测的face_type选择真值中对应的面中心点
face_type = det_result['face_type'] # 'front', 'back', 'left', 'right'
x3d_gt, y3d_gt, z3d_gt = gt_values[face_mapping[face_type]]
# 获取预测的最近面中心点
x3d_pred, y3d_pred, z3d_pred = det_result['3d_info']['center']
# 计算误差
lateral_error = |x3d_pred - x3d_gt|
longitudinal_error = |z3d_pred - z3d_gt|
非车辆类别的测距误差计算:
非车辆类别(pedestrian, bike, rider)直接使用3D框中心点计算误差:
# 非车辆类别
x3d_gt, y3d_gt, z3d_gt = gt_values[5:8] # x3d_ori, y3d_ori, z3d_ori
x3d_pred, y3d_pred, z3d_pred = det_result['3d_info']['center']
lateral_error = |x3d_pred - x3d_gt|
longitudinal_error = |z3d_pred - z3d_gt|
Heading偏差 (Heading Error):
所有3D类别使用相同的方式计算heading误差:
heading_error = |normalize_angle(rot_y_pred - rot_y_gt)|
其中 normalize_angle 将角度差归一化到 [-π, π]
3.2.4 统计指标
对每个3D类别分别统计:
- 横向误差: 平均值、中位数、标准差、90%分位数
- 纵向误差: 平均值、中位数、标准差、90%分位数
- Heading误差: 平均值、中位数、标准差、90%分位数
4. 评测流程设计
4.1 数据预处理
4.1.1 真值数据解析
def parse_ground_truth(gt_line, img_width, img_height):
"""
解析真值标注
返回: {
'label': int,
'bbox_2d': [x1, y1, x2, y2], # 像素坐标
'has_3d': bool,
'3d_info': {
'center': [x3d, y3d, z3d], # 原始中心点(用于非车辆类别)
'dimensions': [l3d, h3d, w3d],
'rotation': rot_y,
'faces': { # 仅车辆类别有此字段
'front': [x3d, y3d, z3d, alpha, xc, yc, score, is_occ],
'back': [x3d, y3d, z3d, alpha, xc, yc, score, is_occ],
'left': [x3d, y3d, z3d, alpha, xc, yc, score, is_occ],
'right': [x3d, y3d, z3d, alpha, xc, yc, score, is_occ]
} if label == 0 else None
} if has_3d else None
}
"""
4.1.2 检测结果解析
def parse_detection(det_line):
"""
解析检测结果
返回: {
'label': str -> int,
'confidence': float,
'bbox_2d': [x1, y1, x2, y2],
'3d_info': {
'center': [x3d, y3d, z3d],
'dimensions': [l3d, h3d, w3d],
'rotation': rot_y,
'face_type': str
} if is_3d_class else None
}
"""
4.2 2D评测流程
对每张图像:
1. 加载真值和检测结果
2. 对每个类别:
a. 筛选出该类别的GT和DET
b. 计算所有配对的IoU矩阵
c. 按置信度排序DET
d. 贪婪匹配(Hungarian or Greedy)
e. 统计TP, FP, FN
f. 记录置信度和匹配状态
对每个类别:
3. 根据所有图像的统计:
a. 按置信度排序所有预测
b. 计算不同阈值下的Precision-Recall
c. 计算AP (使用插值或积分)
整体统计:
4. 计算总Precision, Recall
5. 计算mAP
4.3 3D评测流程
对每张图像:
1. 基于2D匹配结果
2. 对每对匹配成功的(GT, DET):
a. 检查GT是否有完整3D标注
b. 检查DET是否为3D类别
c. 如果都满足:
- 如果是车辆类别(label=0):
* 根据DET的face_type选择GT中对应面的中心点
* 计算预测最近面与真值对应面的横向/纵向误差
- 如果是非车辆类别(label=1,2,3):
* 直接使用3D框中心点计算横向/纵向误差
- 计算Heading误差(所有类别相同)
- 按类别记录
对每个3D类别:
3. 统计所有图像的误差:
- 横向: mean, median, std, 90th percentile
- 纵向: mean, median, std, 90th percentile
- Heading: mean, median, std, 90th percentile
5. 实现架构
5.1 模块划分
eval_tools/
├── evaluator/
│ ├── __init__.py
│ ├── parser.py # 数据解析模块
│ ├── matcher.py # 2D匹配模块
│ ├── metrics_2d.py # 2D指标计算
│ ├── metrics_3d.py # 3D指标计算
│ ├── evaluator.py # 主评测器
│ └── visualizer.py # 结果可视化
├── configs/
│ └── eval_config.yaml # 评测配置
└── eval.py # 评测入口脚本
5.2 核心类设计
5.2.1 数据解析器
class GroundTruthParser:
def parse_line(self, line, img_shape)
def is_3d_annotated(self, values)
def get_class_name(self, label_id)
class DetectionParser:
def parse_line(self, line)
def map_class_name(self, name_str)
5.2.2 匹配器
class Matcher2D:
def __init__(self, iou_threshold=0.5)
def compute_iou(self, box1, box2)
def match(self, gts, dets) # 返回匹配对列表
5.2.3 指标计算器
class Metrics2D:
def __init__(self)
def add_image_results(self, matches, gts, dets, class_id)
def compute_ap(self, class_id)
def compute_map(self), face_type=None)
def compute_statistics(self, class_id)
def get_summary(self)
def _get_vehicle_face_center(self, gt_faces, face_type) # 根据face_type获取对应面中心
class Metrics3D:
def __init__(self)
def add_sample(self, gt_3d, det_3d, class_id)
def compute_statistics(self, class_id)
def get_summary(self)
5.2.4 主评测器
class Evaluator:
def __init__(self, config)
def load_ground_truth(self, gt_file)
def load_detections(self, det_file)
def evaluate_2d(self)
def evaluate_3d(self)
def generate_report(self, output_path)
5.3 配置文件示例
# eval_config.yaml
dataset:
gt_path: "path/to/ground_truth"
det_path: "path/to/detections"
image_list: "path/to/image_list.txt"
classes:
3d_classes: [0, 1, 2, 3] # vehicle, pedestrian, bike, rider
2d_classes: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
class_names:
0: "vehicle"
1: "pedestrian"
2: "bike"
3: "rider"
4: "roadblock"
5: "head"
6: "tsr"
7: "guideboard"
8: "plate"
9: "wheel"
10: "tl_border"
11: "tl_wick"
12: "tl_num"
13: "tricycle"
matching:
iou_threshold: 0.5
metrics_2d:
enabled: true
confidence_threshold: [0.1, 0.3, 0.5, 0.7, 0.9]
metrics_3d:
enabled: true
distance_ranges: # 可选:分距离段统计
- [0, 30]
- [30, 60]
- [60, 100]
- [100, 999]
output:
save_path: "eval_results"
format: ["json", "csv", "txt"]
visualize: true
6. 输出报告格式
6.1 2D评测报告
{
"2d_evaluation": {
"per_class": {
"vehicle": {
"precision": 0.92,
"recall": 0.88,
"ap": 0.90,
"num_gt": 1500,
"num_det": 1450,
"tp": 1320,
"fp": 130,
"fn": 180
},
"pedestrian": {...},
...
},
"overall": {
"precision": 0.87,
"recall": 0.84,
"map": 0.85,
"num_classes": 14
}
}
}
6.2 3D评测报告
{
"3d_evaluation": {
"vehicle": {
"lateral_error": {
"mean": 0.25,
"median": 0.18,
"std": 0.15,
"percentile_90": 0.45
},
"longitudinal_error": {
"mean": 1.2,
"median": 0.9,
"std": 0.8,
"percentile_90": 2.1
},
"heading_error": {
"mean": 0.08,
"median": 0.05,
"std": 0.06,
"percentile_90": 0.15
},
"num_samples": 1320
},
"pedestrian": {...},
...
}
}
7. 关键实现细节
7.1 IoU计算
def compute_iou(box1, box2):
"""
box: [x1, y1, x2, y2]
"""
x1 = max(box1[0], box2[0])
y1 = max(box1[1], box2[1])
x2 = min(box1[2], box2[2])
y2 = min(box1[3], box2[3])
if x2 < x1 or y2 < y1:
return 0.0
intersection = (x2 - x1) * (y2 - y1)
area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
union = area1 + area2 - intersection
return intersection / union if union > 0 else 0.0
7.2 AP计算(11点插值法)
def compute_ap(precisions, recalls):
"""
使用VOC 11点插值法计算AP
"""
ap = 0.0
for t in np.linspace(0, 1, 11):
if np.sum(recalls >= t) == 0:
p = 0
else:
p = np.max(precisions[recalls >= t])
ap += p / 11.0
return ap
7.3 角度归一化
def normalize_angle(angle):
"""
将角度归一化到[-π, π]
"""
while angle > np.pi:
angle -= 2 * np.pi
while angle < -np.pi:
angle += 2 * np.pi
return angle
7.4 坐标系转换
def normalized_to_pixel(bbox_norm, img_width, img_height):
"""
归一化坐标转像素坐标
bbox_norm: [x_center, y_center, w, h] (normalized)
返回: [x1, y1, x2, y2] (pixel)
"""
x_center = bbox_norm[0] * img_width
y_center = bbox_norm[1] * img_height
w = bbox_norm[2] * img_width
h = bbox_norm[3] * img_height
x1 = x_center - w / 2
y1 = y_center - h / 2
x2 = x_center + w / 2
y2 = y_center + h / 2
return [x1, y1, x2, y2]
8. 使用示例
8.1 命令行使用
# 基础评测
python eval_tools/eval.py \
--gt-path /path/to/labels \
--det-path /path/to/predictions \
--output-dir eval_results
# 指定配置文件
python eval_tools/eval.py \
--config eval_tools/configs/eval_config.yaml
# 只评测2D
python eval_tools/eval.py \
--config eval_config.yaml \
--eval-2d-only
# 只评测3D
python eval_tools/eval.py \
--config eval_config.yaml \
--eval-3d-only
8.2 Python API使用
from eval_tools.evaluator import Evaluator
# 创建评测器
evaluator = Evaluator(config_path='eval_config.yaml')
# 加载数据
evaluator.load_data(
gt_path='/path/to/labels',
det_path='/path/to/predictions'
)
# 执行评测
results_2d = evaluator.evaluate_2d()
results_3d = evaluator.evaluate_3d()
# 生成报告
evaluator.generate_report(
output_dir='eval_results',
formats=['json', 'csv', 'html']
)
9. 扩展性考虑
9.1 多IoU阈值评测
可扩展支持COCO风格的多IoU阈值(0.5:0.05:0.95)
9.2 距离分段评测
对3D指标按不同距离段分别统计(近距离、中距离、远距离)
9.3 场景分类评测
可按不同场景(白天/夜晚、晴天/雨天等)分别评测
9.4 时序一致性评测
对视频序列评测跟踪一致性和稳定性
10. 注意事项
- 坐标系统一: 确保GT和DET使用相同的坐标系和图像尺寸
- 类别映射: 注意字符串类别名和数字ID的映射关系
- 边界情况: 处理空检测、空真值、图像尺寸不一致等情况
- 性能优化: 对于大规模数据,考虑并行处理和内存优化
- 数值精度: 3D指标计算注意浮点数精度问题
- 可视化: 提供检测结果和误差分布的可视化,便于分析