713 lines
23 KiB
Markdown
713 lines
23 KiB
Markdown
|
|
# 模型评测框架使用指南
|
|||
|
|
|
|||
|
|
> 入口脚本:`eval_tools/core/run_eval_with_config.sh`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
|
|||
|
|
1. [框架概览](#1-框架概览)
|
|||
|
|
2. [目录结构](#2-目录结构)
|
|||
|
|
3. [核心流程](#3-核心流程)
|
|||
|
|
4. [配置文件说明](#4-配置文件说明)
|
|||
|
|
5. [命令行参数说明](#5-命令行参数说明)
|
|||
|
|
6. [数据格式](#6-数据格式)
|
|||
|
|
7. [评测指标](#7-评测指标)
|
|||
|
|
8. [ROI GT 处理](#8-roi-gt-处理)
|
|||
|
|
9. [模型对比(共同匹配集)](#9-模型对比共同匹配集)
|
|||
|
|
10. [Heading 误差分析](#10-heading-误差分析)
|
|||
|
|
11. [输出结果](#11-输出结果)
|
|||
|
|
12. [使用示例](#12-使用示例)
|
|||
|
|
13. [常见问题](#13-常见问题)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 框架概览
|
|||
|
|
|
|||
|
|
本框架用于评测 YOLOv5-3D 模型的 2D 检测与 3D 定位性能,支持:
|
|||
|
|
|
|||
|
|
- **2D 检测评测**:全部 14 个类别的 Precision / Recall / AP / mAP
|
|||
|
|
- **3D 检测评测**:vehicle / pedestrian / bicycle / rider 的横向误差、纵向误差、heading 误差
|
|||
|
|
- **ROI GT 过滤**:评测坐标系与训练时保持一致
|
|||
|
|
- **距离区间分析**:按纵向距离(z轴)和横向距离(x轴)分段统计 3D 指标
|
|||
|
|
- **多模型对比**:基于共同匹配集(Common Matches)公平比较两个模型的 3D 性能
|
|||
|
|
- **Heading 误差分析**:提取、可视化、分析方向预测误差
|
|||
|
|
|
|||
|
|
### 架构图
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
eval_tools/core/run_eval_with_config.sh
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
eval_tools/core/eval.py ← 主入口 Python 脚本
|
|||
|
|
│
|
|||
|
|
├─── eval_tools/configs/*.yaml ← 配置文件
|
|||
|
|
│
|
|||
|
|
└─── eval_tools/evaluator/ ← 核心评测引擎
|
|||
|
|
├── evaluator.py ← 主控流程、并行调度
|
|||
|
|
├── parser.py ← GT / 检测结果解析
|
|||
|
|
├── matcher.py ← 2D IoU 匹配
|
|||
|
|
├── metrics_2d.py ← 2D 指标计算
|
|||
|
|
├── metrics_3d.py ← 3D 指标计算
|
|||
|
|
└── roi_processor.py ← ROI 坐标系对齐
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
eval_tools/
|
|||
|
|
├── core/
|
|||
|
|
│ ├── eval.py # 主评测脚本
|
|||
|
|
│ ├── run_eval_with_config.sh # 单模型评测入口(当前默认入口)
|
|||
|
|
│ ├── run_eval.sh # 早期版本入口(无配置文件)
|
|||
|
|
│ ├── run_eval_2d_only.sh # 仅 2D 评测
|
|||
|
|
│ ├── run_eval_3d_only.sh # 仅 3D 评测
|
|||
|
|
│ └── run_evaluation_example.sh # 示例脚本
|
|||
|
|
│
|
|||
|
|
├── configs/
|
|||
|
|
│ ├── eval_config_mono3d-roi0.yaml # mono3d 模型 ROI0 配置
|
|||
|
|
│ ├── eval_config_mono3d-roi1.yaml # mono3d 模型 ROI1 配置
|
|||
|
|
│ ├── eval_config_yolov5s-roi0.yaml # yolov5s 模型 ROI0 配置
|
|||
|
|
│ ├── eval_config_yolov5s-roi1.yaml # yolov5s 模型 ROI1 配置
|
|||
|
|
│ ├── eval_config_yolov5s_cncap-roi0.yaml # yolov5s CNCAP 测试集 ROI0(当前默认)
|
|||
|
|
│ └── eval_config_yolov5s_cncap-roi1.yaml # yolov5s CNCAP 测试集 ROI1
|
|||
|
|
│
|
|||
|
|
├── evaluator/
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── evaluator.py # 主评测器(数据加载、调度、报告生成)
|
|||
|
|
│ ├── parser.py # 真值 / 检测结果解析器
|
|||
|
|
│ ├── matcher.py # 2D IoU 匹配器
|
|||
|
|
│ ├── metrics_2d.py # 2D 指标计算(P/R/AP/mAP)
|
|||
|
|
│ ├── metrics_3d.py # 3D 指标计算(Lat/Long/Heading)
|
|||
|
|
│ └── roi_processor.py # ROI GT 处理器
|
|||
|
|
│
|
|||
|
|
├── model_comparison/
|
|||
|
|
│ ├── find_common_matches.py # 找出两模型共同匹配的 GT
|
|||
|
|
│ ├── compare_models.py # 生成双模型对比报告
|
|||
|
|
│ ├── compare_models_with_common_matches.sh # 一键双模型对比脚本
|
|||
|
|
│ ├── generate_eval_report.py # 从 JSON 生成 Markdown 评测报告
|
|||
|
|
│ ├── generate_comparison_report.py # 生成对比 Markdown 报告
|
|||
|
|
│ └── ...
|
|||
|
|
│
|
|||
|
|
├── heading_analysis/
|
|||
|
|
│ ├── extract_bad_heading_cases.py # 提取 heading 误差大的案例
|
|||
|
|
│ ├── visualize_heading_errors.py # 可视化 heading 误差(BEV/图像/极坐标)
|
|||
|
|
│ └── ...
|
|||
|
|
│
|
|||
|
|
├── visualization/
|
|||
|
|
│ └── test_val_visualize_from_paths.py # 从路径可视化检测结果
|
|||
|
|
│
|
|||
|
|
├── utilities/
|
|||
|
|
│ ├── check_img_exists.py # 检查图像文件是否存在
|
|||
|
|
│ └── extract_video_frames.py # 视频帧提取
|
|||
|
|
│
|
|||
|
|
└── docs/ # 详细设计文档(本文件所在目录)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 核心流程
|
|||
|
|
|
|||
|
|
### 单模型评测(`run_eval_with_config.sh`)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────┐
|
|||
|
|
│ run_eval_with_config.sh │
|
|||
|
|
│ │
|
|||
|
|
│ 1. 设置 PYTHONPATH │
|
|||
|
|
│ 2. 指定配置文件路径 (MODEL_CONFIG) │
|
|||
|
|
│ 3. 指定输出目录 (OUTPUT_BASE/MODEL_NAME/TIMESTAMP) │
|
|||
|
|
│ 4. 调用 eval_tools/core/eval.py │
|
|||
|
|
└─────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────┐
|
|||
|
|
│ eval.py │
|
|||
|
|
│ │
|
|||
|
|
│ 1. 解析 YAML 配置 + 命令行参数 │
|
|||
|
|
│ 2. 初始化 Evaluator(含 ROIProcessor) │
|
|||
|
|
│ 3. 加载检测结果 & 真值文件对 │
|
|||
|
|
│ 4. 并行处理每张图 (IoU 匹配 + 指标统计) │
|
|||
|
|
│ 5. 汇总指标并生成报告 │
|
|||
|
|
└─────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
┌────────────┴─────────────┐
|
|||
|
|
▼ ▼
|
|||
|
|
evaluation_report.json detailed_3d_matches.json
|
|||
|
|
evaluation_report.txt (--save-detailed-matches)
|
|||
|
|
per_case_reports/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 双模型对比(`compare_models_with_common_matches.sh`)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Model 1 评测 → detailed_3d_matches.json
|
|||
|
|
┐
|
|||
|
|
├─ find_common_matches.py → common_matches.json
|
|||
|
|
│
|
|||
|
|
Model 2 评测 → detailed_3d_matches.json ┘
|
|||
|
|
│
|
|||
|
|
└─ compare_models.py → 对比报告
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 配置文件说明
|
|||
|
|
|
|||
|
|
配置文件位于 `eval_tools/configs/`,YAML 格式,分以下几个部分:
|
|||
|
|
|
|||
|
|
### 4.1 数据集路径 (`dataset`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
dataset:
|
|||
|
|
det_path: "/data1/.../evalset_roi0" # 检测结果根目录(含 case 文件夹)
|
|||
|
|
gt_path: "/data1/xdzhu/Testdata" # 真值标签根目录(含 case 文件夹)
|
|||
|
|
path_depth: 1 # 目录层级:1 = det_path/case/txt_results
|
|||
|
|
# 2 = det_path/level1/case/txt_results
|
|||
|
|
det_format: "json" # 检测结果格式:auto / json / txt
|
|||
|
|
gt_format: "json" # 真值格式:auto / json / txt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**目录结构要求(`path_depth: 1`)**:
|
|||
|
|
```
|
|||
|
|
det_path/
|
|||
|
|
└── case_019b178d/
|
|||
|
|
└── json_results/ ← det_format="json"
|
|||
|
|
├── 000000.json
|
|||
|
|
└── 000001.json
|
|||
|
|
|
|||
|
|
gt_path/
|
|||
|
|
└── case_019b178d/
|
|||
|
|
└── labels_json/ ← gt_format="json"
|
|||
|
|
├── 000000.json
|
|||
|
|
└── 000001.json
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 图像尺寸 (`image`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
image:
|
|||
|
|
width: 1920
|
|||
|
|
height: 1080
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 模型配置与 GT 过滤 (`model`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
model:
|
|||
|
|
input_size: 704 # 模型输入宽度(像素)
|
|||
|
|
min_box_size_at_input_scale: 8 # 模型输入分辨率下的最小框尺寸
|
|||
|
|
# GT 过滤阈值自动计算:min_box_size = 8 * roi_width / 704
|
|||
|
|
# ROI0 (1920→704): ≈ 21.8 像素;ROI1 (704→704): 8 像素
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 并行性能 (`performance`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
performance:
|
|||
|
|
num_workers: 32 # 并行 worker 数(null = auto-detect CPU 核数)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.5 ROI GT 处理 (`roi_gt`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
roi_gt:
|
|||
|
|
enabled: true
|
|||
|
|
calib_root: "/data1/xdzhu/Testdata" # 标定文件根目录(含 camera4.json)
|
|||
|
|
roi_config: [1920, 960] # ROI 配置,与训练保持一致
|
|||
|
|
# ROI0: [1920, 960]
|
|||
|
|
# ROI1: [704, 352]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> **重要**:`roi_config` 必须与训练时的 ROI 配置完全一致,否则坐标系不对齐,IoU 计算将不准确。
|
|||
|
|
|
|||
|
|
### 4.6 类别定义 (`classes`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
classes:
|
|||
|
|
3d_classes: [0, 1, 2, 3] # 参与 3D 评测的类别
|
|||
|
|
2d_classes: [4, 5, ..., 13] # 仅参与 2D 评测的类别
|
|||
|
|
class_names:
|
|||
|
|
0: "vehicle"
|
|||
|
|
1: "pedestrian"
|
|||
|
|
...
|
|||
|
|
13: "tricycle"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.7 匹配参数 (`matching`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
matching:
|
|||
|
|
iou_threshold: 0.5 # 2D 匹配 IoU 阈值
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.8 2D 指标 (`metrics_2d`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
metrics_2d:
|
|||
|
|
enabled: true
|
|||
|
|
conf_threshold: 0.4 # Precision/Recall 置信度阈值
|
|||
|
|
ap_method: "voc2010" # AP 计算方法:voc2010(11点插值)/ coco(全点插值)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.9 3D 指标 (`metrics_3d`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
metrics_3d:
|
|||
|
|
enabled: true
|
|||
|
|
heading_tolerance: "both" # strict / relaxed / both
|
|||
|
|
distance_ranges: # 纵向距离区间(米)
|
|||
|
|
- [0, 10]
|
|||
|
|
- [10, 20]
|
|||
|
|
- ...
|
|||
|
|
- [100, 999]
|
|||
|
|
lateral_distance_ranges: # 横向距离区间(米,x 轴)
|
|||
|
|
- [-50, -40]
|
|||
|
|
- ...
|
|||
|
|
- [40, 50]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`heading_tolerance` 说明**:
|
|||
|
|
| 值 | 含义 |
|
|||
|
|
|---|---|
|
|||
|
|
| `strict` | 标准计算(默认)|
|
|||
|
|
| `relaxed` | 对称物体允许 180° 对称:`error = min(error, π - error)` |
|
|||
|
|
| `both` | 同时计算并输出 strict 和 relaxed 两套结果 |
|
|||
|
|
|
|||
|
|
### 4.10 输出配置 (`output`)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
output:
|
|||
|
|
save_path: "evaluation_results/my_model/{timestamp}"
|
|||
|
|
formats: ["json", "txt"]
|
|||
|
|
print_details: true
|
|||
|
|
per_case_reports: true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 命令行参数说明
|
|||
|
|
|
|||
|
|
`eval_tools/core/eval.py` 支持以下参数(命令行参数优先级高于配置文件):
|
|||
|
|
|
|||
|
|
| 参数 | 类型 | 默认值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| `--config` | str | — | YAML 配置文件路径 |
|
|||
|
|
| `--det-path` | str | — | 检测结果根目录 |
|
|||
|
|
| `--gt-path` | str | — | 真值标签根目录 |
|
|||
|
|
| `--path-depth` | int | 1 | 目录层级(1 或 2)|
|
|||
|
|
| `--det-format` | str | auto | 检测结果格式(auto/json/txt)|
|
|||
|
|
| `--gt-format` | str | auto | 真值格式(auto/json/txt)|
|
|||
|
|
| `--output-dir` | str | eval_results | 输出目录 |
|
|||
|
|
| `--img-width` | int | 1920 | 图像宽度(像素)|
|
|||
|
|
| `--img-height` | int | 1080 | 图像高度(像素)|
|
|||
|
|
| `--iou-threshold` | float | 0.5 | IoU 匹配阈值 |
|
|||
|
|
| `--conf-threshold` | float | 0.5 | 置信度阈值 |
|
|||
|
|
| `--ap-method` | str | voc2010 | AP 计算方法(voc2010/coco)|
|
|||
|
|
| `--heading-tolerance` | str | strict | heading 容忍模式(strict/relaxed/both)|
|
|||
|
|
| `--num-workers` | int | auto | 并行 worker 数 |
|
|||
|
|
| `--eval-2d-only` | flag | — | 仅评测 2D |
|
|||
|
|
| `--eval-3d-only` | flag | — | 仅评测 3D |
|
|||
|
|
| `--save-detailed-matches` | flag | — | 保存详细 3D 匹配信息(供模型对比使用)|
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 数据格式
|
|||
|
|
|
|||
|
|
### 6.1 真值(Ground Truth)格式
|
|||
|
|
|
|||
|
|
**车辆类别(50 个值)**:
|
|||
|
|
```
|
|||
|
|
[class, x, y, w, h, # 0-4: 类别 + 归一化 2D 框
|
|||
|
|
x3d, y3d, z3d, # 5-7: 3D 中心点(相机坐标系)
|
|||
|
|
l, h, w, # 8-10: 3D 尺寸(长高宽)
|
|||
|
|
rot_y, # 11: 绕 Y 轴旋转角
|
|||
|
|
xc, yc, # 12-13: 3D 中心点的图像投影
|
|||
|
|
xc_d, yc_d, # 14-15: 深度相关投影
|
|||
|
|
alpha, # 16: 观测角
|
|||
|
|
0, # 17: 占位符
|
|||
|
|
前面(x3d,y3d,z3d,alpha,xc,yc,score,occ), # 18-25
|
|||
|
|
后面(x3d,y3d,z3d,alpha,xc,yc,score,occ), # 26-33
|
|||
|
|
左面(x3d,y3d,z3d,alpha,xc,yc,score,occ), # 34-41
|
|||
|
|
右面(x3d,y3d,z3d,alpha,xc,yc,score,occ)] # 42-49
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**行人/自行车/骑手(18 个值)**:
|
|||
|
|
上述 0-17,无四面信息。
|
|||
|
|
|
|||
|
|
**仅 2D 标注(6 个值)**:
|
|||
|
|
```
|
|||
|
|
[class, x, y, w, h, -1]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 检测结果格式
|
|||
|
|
|
|||
|
|
**车辆(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 cs x3d y3d z3d l h w rot_y face_type
|
|||
|
|
```
|
|||
|
|
`face_type` 取值:`front` / `back`(或 `rear`/`tail`)/ `left` / `right`
|
|||
|
|
|
|||
|
|
**行人/骑手等(15 个字段)**:同上,`face_type` 固定为 `whole`。
|
|||
|
|
|
|||
|
|
**纯 2D 类别(6 个字段)**:
|
|||
|
|
```
|
|||
|
|
plate 0.94246 532.12 203.26 558.73 214.86
|
|||
|
|
label conf x1 y1 x2 y2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 评测指标
|
|||
|
|
|
|||
|
|
### 7.1 2D 检测指标
|
|||
|
|
|
|||
|
|
- **Precision**:TP / (TP + FP),按 `conf_threshold` 过滤
|
|||
|
|
- **Recall**:TP / (TP + FN)
|
|||
|
|
- **F1-Score**:2 × P × R / (P + R)
|
|||
|
|
- **AP**:PR 曲线下面积(IoU 阈值 0.5)
|
|||
|
|
- **mAP**:所有类别 AP 的算术平均
|
|||
|
|
|
|||
|
|
**匹配规则**:
|
|||
|
|
1. 按置信度从高到低排序预测框
|
|||
|
|
2. 与真值框 IoU ≥ 0.5 且类别相同 → TP(每个真值框只匹配一次)
|
|||
|
|
3. 未匹配预测框 → FP;未被匹配真值框 → FN
|
|||
|
|
|
|||
|
|
**类别划分(14 类)**:
|
|||
|
|
|
|||
|
|
| ID | 类别 | 3D 评测 |
|
|||
|
|
|----|------|---------|
|
|||
|
|
| 0 | vehicle | ✓ |
|
|||
|
|
| 1 | pedestrian | ✓ |
|
|||
|
|
| 2 | bicycle | ✓ |
|
|||
|
|
| 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 | — |
|
|||
|
|
|
|||
|
|
### 7.2 3D 检测指标
|
|||
|
|
|
|||
|
|
> 前提:2D IoU 匹配成功(≥ 0.5)且真值包含完整 3D 标注。
|
|||
|
|
|
|||
|
|
**车辆类别**(基于最近面中心点对比):
|
|||
|
|
|
|||
|
|
根据检测结果的 `face_type` 字段,在真值中选取对应面的中心点进行比较:
|
|||
|
|
```
|
|||
|
|
face_type → 真值面中心点索引
|
|||
|
|
front → [18, 19, 20] (x3d, y3d, z3d)
|
|||
|
|
back → [26, 27, 28]
|
|||
|
|
left → [34, 35, 36]
|
|||
|
|
right → [42, 43, 44]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**行人/骑手/自行车**:使用整体中心点 `[5, 6, 7]` 进行比较。
|
|||
|
|
|
|||
|
|
**误差指标**:
|
|||
|
|
- **横向误差(Lateral Error)**:`|x3d_pred - x3d_gt|`(米)
|
|||
|
|
- **纵向误差(Longitudinal Error)**:`|z3d_pred - z3d_gt|`(米)
|
|||
|
|
- **Heading 误差**:`|rot_y_pred - rot_y_gt|`(弧度)
|
|||
|
|
|
|||
|
|
每个指标输出:均值(Mean)、中位数(Median)、标准差(Std)、90 百分位数(P90)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. ROI GT 处理
|
|||
|
|
|
|||
|
|
### 动机
|
|||
|
|
|
|||
|
|
训练时图像经过 ROI 裁剪和缩放(坐标系改变),但历史评测代码中检测结果在 ROI 坐标系,GT 在原图坐标系,导致 IoU 计算不准确。
|
|||
|
|
|
|||
|
|
### 解决方案
|
|||
|
|
|
|||
|
|
`ROIProcessor`(`eval_tools/evaluator/roi_processor.py`)在评测时对 GT 标签执行与训练完全相同的 ROI 处理:
|
|||
|
|
|
|||
|
|
1. 读取标定文件(`case_root/camera4.json`)中的 `focal_u, focal_v, cu, cv, pitch`
|
|||
|
|
2. 计算裁剪中心:`cx = oriW // 2`,`cy = cv - focal_v × tan(pitch × π/180)`
|
|||
|
|
3. 以 `(cx, cy)` 为中心按 `roi_config` 裁剪 ROI
|
|||
|
|
4. 过滤完全在 ROI 外的目标;将部分在 ROI 内的框 clip 到边界
|
|||
|
|
5. 将坐标转换到 ROI 相对坐标系 → 再缩放到模型输入分辨率
|
|||
|
|
|
|||
|
|
**配置对应关系**:
|
|||
|
|
| 训练 ROI 配置 | `roi_config` 值 |
|
|||
|
|
|---|---|
|
|||
|
|
| ROI0(大 crop) | `[1920, 960]` |
|
|||
|
|
| ROI1(小 crop) | `[704, 352]` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 模型对比(共同匹配集)
|
|||
|
|
|
|||
|
|
### 问题背景
|
|||
|
|
|
|||
|
|
直接比较两个模型的 3D 指标时,若双方匹配到的 GT 对象数量不同(如相差 11.7%),差异可能来自**匹配集差异**而非模型质量。
|
|||
|
|
|
|||
|
|
### 解决方案
|
|||
|
|
|
|||
|
|
只统计两个模型**都成功匹配**的 GT 对象(Common Matches)的 3D 指标。
|
|||
|
|
|
|||
|
|
### 使用方式
|
|||
|
|
|
|||
|
|
#### 方式一:一键脚本(推荐)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
bash eval_tools/model_comparison/compare_models_with_common_matches.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
该脚本自动完成:
|
|||
|
|
1. 评测 Model 1,保存 `detailed_3d_matches.json`
|
|||
|
|
2. 评测 Model 2,保存 `detailed_3d_matches.json`
|
|||
|
|
3. 调用 `find_common_matches.py` 得到 `common_matches.json`
|
|||
|
|
4. 调用 `compare_models.py` 生成对比报告
|
|||
|
|
5. 调用 `generate_eval_report.py` 为各模型生成 Markdown 报告
|
|||
|
|
|
|||
|
|
#### 方式二:手动分步执行
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Step 1: 评测两个模型
|
|||
|
|
python eval_tools/core/eval.py \
|
|||
|
|
--config eval_tools/configs/eval_config_mono3d-roi1.yaml \
|
|||
|
|
--output-dir eval_results/model1 \
|
|||
|
|
--heading-tolerance both \
|
|||
|
|
--save-detailed-matches
|
|||
|
|
|
|||
|
|
python eval_tools/core/eval.py \
|
|||
|
|
--config eval_tools/configs/eval_config_yolov5s_cncap-roi1.yaml \
|
|||
|
|
--output-dir eval_results/model2 \
|
|||
|
|
--heading-tolerance both \
|
|||
|
|
--save-detailed-matches
|
|||
|
|
|
|||
|
|
# Step 2: 找出共同匹配
|
|||
|
|
python eval_tools/model_comparison/find_common_matches.py \
|
|||
|
|
--model1-matches eval_results/model1/detailed_3d_matches.json \
|
|||
|
|
--model2-matches eval_results/model2/detailed_3d_matches.json \
|
|||
|
|
--output eval_results/common_matches.json \
|
|||
|
|
--model1-name "mono3d" \
|
|||
|
|
--model2-name "yolov5s-300w"
|
|||
|
|
|
|||
|
|
# Step 3: 生成对比报告
|
|||
|
|
python eval_tools/model_comparison/compare_models.py \
|
|||
|
|
--model1 eval_results/model1/evaluation_report.json \
|
|||
|
|
--model2 eval_results/model2/evaluation_report.json \
|
|||
|
|
--common-matches eval_results/common_matches.json \
|
|||
|
|
--output-dir eval_results/comparison \
|
|||
|
|
--model1-name "mono3d" \
|
|||
|
|
--model2-name "yolov5s-300w"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 生成 Markdown 报告
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python eval_tools/model_comparison/generate_eval_report.py \
|
|||
|
|
eval_results/model1/evaluation_report.json \
|
|||
|
|
--model "yolov5s-300w-cncap" \
|
|||
|
|
--date 2026-03-03
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
输出:`eval_results/model1/EVALUATION_REPORT.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. Heading 误差分析
|
|||
|
|
|
|||
|
|
对于 heading 预测较差的案例,可使用以下工具进行深入分析:
|
|||
|
|
|
|||
|
|
### Step 1:提取 bad cases
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python eval_tools/heading_analysis/extract_bad_heading_cases.py \
|
|||
|
|
--input eval_results/model1/detailed_3d_matches.json \
|
|||
|
|
--threshold 1.5 \ # heading 误差阈值(弧度)
|
|||
|
|
--top-k 100 \
|
|||
|
|
--output bad_heading.json \
|
|||
|
|
--stats
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Step 2:可视化
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python eval_tools/heading_analysis/visualize_heading_errors.py \
|
|||
|
|
--input bad_heading.json \
|
|||
|
|
--image-root /path/to/images \
|
|||
|
|
--output runs/heading_viz \
|
|||
|
|
--viz-types bev image angle combined
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
可视化类型:
|
|||
|
|
- `bev`:鸟瞰图(GT / Pred 的 3D 框 + 方向箭头)
|
|||
|
|
- `image`:原图视图(2D 框 + 误差标注)
|
|||
|
|
- `angle`:角度分析(极坐标 + 柱状图)
|
|||
|
|
- `combined`:四宫格综合视图
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 输出结果
|
|||
|
|
|
|||
|
|
### 11.1 文件列表
|
|||
|
|
|
|||
|
|
| 文件 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| `evaluation_report.json` | 完整评测报告(JSON 格式,含所有类别和距离区间)|
|
|||
|
|
| `evaluation_report.txt` | 人类可读的文本报告 |
|
|||
|
|
| `detailed_3d_matches.json` | 每帧每目标的 3D 匹配详情(`--save-detailed-matches`)|
|
|||
|
|
| `per_case_reports/*.json` | 每个 case 的独立报告(`per_case_reports: true`)|
|
|||
|
|
| `EVALUATION_REPORT.md` | Markdown 格式摘要报告(由 `generate_eval_report.py` 生成)|
|
|||
|
|
|
|||
|
|
### 11.2 JSON 报告结构
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"evaluation_config": {...},
|
|||
|
|
"2d_evaluation": {
|
|||
|
|
"overall": {
|
|||
|
|
"precision": 0.85,
|
|||
|
|
"recall": 0.78,
|
|||
|
|
"f1_score": 0.81,
|
|||
|
|
"map": 0.72
|
|||
|
|
},
|
|||
|
|
"per_class": {
|
|||
|
|
"vehicle": {"precision": ..., "recall": ..., "ap": ...},
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"3d_evaluation": {
|
|||
|
|
"vehicle": {
|
|||
|
|
"overall": {
|
|||
|
|
"n_samples": 440408,
|
|||
|
|
"lateral_mean": 0.647,
|
|||
|
|
"longitudinal_mean": 1.680,
|
|||
|
|
"heading_mean_strict": 0.258
|
|||
|
|
},
|
|||
|
|
"by_distance": {
|
|||
|
|
"[0-10m]": {...},
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 11.3 控制台输出示例
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
3D Metrics:
|
|||
|
|
vehicle [overall]: Lat=0.647m, Long=1.680m, Head=0.258rad (n=440408)
|
|||
|
|
[0-10m]: Lat=0.423m, Long=0.891m, Head=0.153rad (n=98241)
|
|||
|
|
[10-20m]: Lat=0.501m, Long=1.203m, Head=0.177rad (n=142038)
|
|||
|
|
[30-60m]: Lat=1.149m, Long=5.074m, Head=0.607rad (n=18432)
|
|||
|
|
[100-999m]:Lat=2.341m, Long=9.221m, Head=1.036rad (n=871)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 使用示例
|
|||
|
|
|
|||
|
|
### 例 1:单模型评测(当前默认入口)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd /deeplearning_team/ydong/dongying/projects/yolov5-3d
|
|||
|
|
conda activate slot
|
|||
|
|
|
|||
|
|
bash eval_tools/core/run_eval_with_config.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
脚本使用 `eval_tools/configs/eval_config_yolov5s_cncap-roi0.yaml`,结果保存至:
|
|||
|
|
```
|
|||
|
|
evaluation_results/eval_results_common_match_comparison_cncap_yolov5s_20260303_roi0/
|
|||
|
|
└── yolov5s-300w-newdata-cncap-test/
|
|||
|
|
└── 20260303_HHMMSS/
|
|||
|
|
├── evaluation_report.json
|
|||
|
|
├── evaluation_report.txt
|
|||
|
|
└── detailed_3d_matches.json
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 例 2:命令行直接评测(不使用配置文件)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python eval_tools/core/eval.py \
|
|||
|
|
--det-path /data1/.../inference_results/model/evalset_roi0 \
|
|||
|
|
--gt-path /data1/xdzhu/Testdata \
|
|||
|
|
--output-dir evaluation_results/my_test \
|
|||
|
|
--heading-tolerance both \
|
|||
|
|
--conf-threshold 0.4 \
|
|||
|
|
--num-workers 16
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 例 3:仅 2D 评测
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python eval_tools/core/eval.py \
|
|||
|
|
--config eval_tools/configs/eval_config_yolov5s_cncap-roi0.yaml \
|
|||
|
|
--eval-2d-only \
|
|||
|
|
--output-dir evaluation_results/2d_only_test
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 例 4:双模型对比
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
bash eval_tools/model_comparison/compare_models_with_common_matches.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 例 5:修改配置直接运行
|
|||
|
|
|
|||
|
|
仅修改 `run_eval_with_config.sh` 中的以下三个变量即可适配新模型:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
MODEL_CONFIG="eval_tools/configs/eval_config_yolov5s_cncap-roi0.yaml"
|
|||
|
|
OUTPUT_BASE="evaluation_results/eval_results_my_model"
|
|||
|
|
MODEL_NAME="my-model-name"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 常见问题
|
|||
|
|
|
|||
|
|
### Q1:No image pairs found
|
|||
|
|
|
|||
|
|
**原因**:`det_path` 与 `gt_path` 下的 case 名称不匹配,或 `det_format` / `gt_format` 设置错误。
|
|||
|
|
|
|||
|
|
**排查**:
|
|||
|
|
```bash
|
|||
|
|
ls ${det_path}/ # 查看 case 目录名
|
|||
|
|
ls ${det_path}/case_xxx/ # 查看是 json_results/ 还是 txt_results/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Q2:IoU 始终为 0,评测指标异常
|
|||
|
|
|
|||
|
|
**原因**:`roi_gt` 配置未启用,或 `roi_config` 与训练时不匹配,导致坐标系不对齐。
|
|||
|
|
|
|||
|
|
**排查**:检查配置中 `roi_gt.enabled: true` 且 `roi_config` 与训练 YAML 中的 `roi:` 字段一致。
|
|||
|
|
|
|||
|
|
### Q3:3D 指标样本数 (n=0)
|
|||
|
|
|
|||
|
|
**原因**:真值中该类别无完整 3D 标注(仅有 6 维的 2D-only 标注),或 2D 匹配 IoU < 0.5。
|
|||
|
|
|
|||
|
|
### Q4:如何添加新模型配置
|
|||
|
|
|
|||
|
|
复制现有配置文件,仅修改 `dataset.det_path` 和 `dataset.gt_path` 即可:
|
|||
|
|
```bash
|
|||
|
|
cp eval_tools/configs/eval_config_yolov5s_cncap-roi0.yaml \
|
|||
|
|
eval_tools/configs/eval_config_my_model-roi0.yaml
|
|||
|
|
# 编辑新文件中的 det_path 和 output.save_path
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Q5:如何加速评测
|
|||
|
|
|
|||
|
|
调大 `performance.num_workers`(建议不超过 CPU 核数 × 2):
|
|||
|
|
```bash
|
|||
|
|
python eval_tools/core/eval.py --config ... --num-workers 64
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*文档生成日期:2026-03-03*
|