556 lines
13 KiB
Markdown
556 lines
13 KiB
Markdown
|
|
# `analyze_val_two_roi_badcases.py` 评测设计说明
|
|||
|
|
|
|||
|
|
本文描述当前脚本 `tools/pdcl_inference/analyze_val_two_roi_badcases.py` 的真实输出内容、评测口径和统计方式。相关实现还涉及:
|
|||
|
|
|
|||
|
|
- `tools/pdcl_inference/two_roi_inference.py`
|
|||
|
|
- `ultralytics/utils/plotting_3d.py`
|
|||
|
|
- `ultralytics/utils/metrics.py`
|
|||
|
|
- `ultralytics/utils/metrics_3d.py`
|
|||
|
|
|
|||
|
|
## 1. 脚本定位
|
|||
|
|
|
|||
|
|
这个脚本不是训练期 validator 的简单包装,而是一个离线分析工具。它的目标是:
|
|||
|
|
|
|||
|
|
- 对 `val/train/test` split 做逐样本推理
|
|||
|
|
- 生成 per-ROI 的 2D/3D 指标汇总
|
|||
|
|
- 输出按类别、距离、框尺寸、可见面 bucket 分解后的统计
|
|||
|
|
- 导出坏例 CSV
|
|||
|
|
- 生成坏例可视化与 HTML 报告
|
|||
|
|
- 可选生成数据画像 `portrait`
|
|||
|
|
|
|||
|
|
默认会分析两个 ROI:
|
|||
|
|
|
|||
|
|
- `roi0`
|
|||
|
|
- `roi1`
|
|||
|
|
|
|||
|
|
## 2. 主流程
|
|||
|
|
|
|||
|
|
每个 ROI 的主流程如下:
|
|||
|
|
|
|||
|
|
1. 读取 split 列表,得到每个样本的 `label_path`。
|
|||
|
|
2. 根据 label 推导 image/calib 路径。
|
|||
|
|
3. 构造 ROI 图像和 ROI 标定。
|
|||
|
|
4. 跑模型,拿到:
|
|||
|
|
- 2D 检测结果
|
|||
|
|
- `preds_3d`
|
|||
|
|
- `preds_edge`
|
|||
|
|
- `anchors`
|
|||
|
|
- `strides`
|
|||
|
|
5. 同一张图会走两套预测用途:
|
|||
|
|
- 一套低阈值预测,用于 2D AP/PR/F1 曲线搜索
|
|||
|
|
- 一套正式阈值预测,用于 3D 匹配、坏例导出和报告
|
|||
|
|
6. 对 GT 与 Pred 做贪心匹配。
|
|||
|
|
7. 基于匹配结果生成 object-level record。
|
|||
|
|
8. 把 record 聚合进 overall / class / breakdown / interval 等 bucket。
|
|||
|
|
9. 结束后统一写出 CSV、JSON、Markdown、HTML 和可视化。
|
|||
|
|
|
|||
|
|
## 3. 匹配规则
|
|||
|
|
|
|||
|
|
## 3.1 主匹配规则
|
|||
|
|
|
|||
|
|
用于 3D 指标、坏例和 2D thresholded 指标的主匹配规则是:
|
|||
|
|
|
|||
|
|
- 条件:`IoU >= 0.5`
|
|||
|
|
- 要求:类别一致
|
|||
|
|
- 策略:按 IoU 从高到低贪心匹配,保证一对一
|
|||
|
|
|
|||
|
|
对应函数:
|
|||
|
|
|
|||
|
|
- `greedy_match_indices(...)`
|
|||
|
|
|
|||
|
|
## 3.2 2D AP 的 TP 计算
|
|||
|
|
|
|||
|
|
用于 `mAP50` 和 `mAP50-95` 的 TP 计算是标准 COCO 风格:
|
|||
|
|
|
|||
|
|
- IoU 阈值:`0.50:0.95`,步长 `0.05`
|
|||
|
|
- 每个阈值单独做一次贪心匹配
|
|||
|
|
- 然后调用 `ap_per_class(...)`
|
|||
|
|
|
|||
|
|
对应函数:
|
|||
|
|
|
|||
|
|
- `compute_2d_tp_matrix(...)`
|
|||
|
|
- `summarize_2d_ap_store(...)`
|
|||
|
|
|
|||
|
|
## 3.3 focused confusion 的匹配
|
|||
|
|
|
|||
|
|
focused confusion matrix 用的是“任意类别 IoU 匹配”:
|
|||
|
|
|
|||
|
|
- 先只按 `IoU >= 0.5` 做 greedy match
|
|||
|
|
- 再把“预测类别 vs GT 类别”记到 confusion matrix
|
|||
|
|
|
|||
|
|
这么做的目的不是算检测 AP,而是专门看“已经局部对上目标之后的分类混淆”。
|
|||
|
|
|
|||
|
|
对应函数:
|
|||
|
|
|
|||
|
|
- `update_subset_confusion_matrix(...)`
|
|||
|
|
|
|||
|
|
## 4. 2D 指标设计
|
|||
|
|
|
|||
|
|
## 4.1 AP / mAP
|
|||
|
|
|
|||
|
|
脚本会先以很低阈值收集候选框:
|
|||
|
|
|
|||
|
|
- `threshold_search_conf = min(bundle.spec.conf, 0.001)`
|
|||
|
|
|
|||
|
|
然后计算:
|
|||
|
|
|
|||
|
|
- `map50_2d`
|
|||
|
|
- `map50_95_2d`
|
|||
|
|
- 每类的 `map50/map50_95`
|
|||
|
|
- PR/F1 曲线
|
|||
|
|
|
|||
|
|
同时还会从 mean F1 curve 里挑一个推荐阈值:
|
|||
|
|
|
|||
|
|
- `recommended_confidence_2d`
|
|||
|
|
|
|||
|
|
其定义是:
|
|||
|
|
|
|||
|
|
- 对所有类别的 F1 曲线取均值
|
|||
|
|
- 先做 `smooth(..., 0.1)`
|
|||
|
|
- 取最大值对应的 confidence
|
|||
|
|
|
|||
|
|
## 4.2 thresholded 2D 指标
|
|||
|
|
|
|||
|
|
在 `recommended_confidence_2d` 下,脚本会再算一套 thresholded 2D 指标:
|
|||
|
|
|
|||
|
|
- `gt_total`
|
|||
|
|
- `pred_total`
|
|||
|
|
- `matched_2d`
|
|||
|
|
- `precision_2d = matched_2d / pred_total`
|
|||
|
|
- `recall_2d = matched_2d / gt_total`
|
|||
|
|
- `f1_2d`
|
|||
|
|
- `false_negatives_2d = gt_total - matched_2d`
|
|||
|
|
- `false_positives_2d = pred_total - matched_2d`
|
|||
|
|
|
|||
|
|
这些会出现在:
|
|||
|
|
|
|||
|
|
- overall summary
|
|||
|
|
- `class_metrics.csv`
|
|||
|
|
- `summary.json`
|
|||
|
|
|
|||
|
|
## 4.3 2D 分类准确率
|
|||
|
|
|
|||
|
|
脚本还会统计“已经匹配上的检测对里,类别判对了多少”:
|
|||
|
|
|
|||
|
|
- `classification_summary_2d`
|
|||
|
|
- `focused_classification_summary_2d`
|
|||
|
|
|
|||
|
|
核心口径是 confusion matrix 的主对角占比:
|
|||
|
|
|
|||
|
|
- `overall_accuracy = trace(matched_matrix) / sum(matched_matrix)`
|
|||
|
|
|
|||
|
|
每类还会有:
|
|||
|
|
|
|||
|
|
- `cls_eval_pairs_2d`
|
|||
|
|
- `cls_correct_2d`
|
|||
|
|
- `cls_acc_2d`
|
|||
|
|
|
|||
|
|
## 4.4 focused confusion 子集
|
|||
|
|
|
|||
|
|
脚本还会单独做一个“近距离、无遮挡、低难度”的 focused confusion:
|
|||
|
|
|
|||
|
|
- GT 条件:
|
|||
|
|
- `difficulty == 0`
|
|||
|
|
- `|lateral| < 5m`
|
|||
|
|
- `|longitudinal| < 30m` 对 `roi0`
|
|||
|
|
- `|longitudinal| < 80m` 对 `roi1`
|
|||
|
|
- Pred 条件:
|
|||
|
|
- 用预测 3D 中心估计空间位置
|
|||
|
|
- 满足相同的空间范围约束
|
|||
|
|
|
|||
|
|
这一部分主要用于看容易样本的分类混淆情况。
|
|||
|
|
|
|||
|
|
## 5. 3D object-level record 设计
|
|||
|
|
|
|||
|
|
每个 GT-Pred 匹配对,脚本都会尝试构造一个 record。record 是后续所有 3D 聚合统计的基础。
|
|||
|
|
|
|||
|
|
### 5.1 基本字段
|
|||
|
|
|
|||
|
|
包含但不限于:
|
|||
|
|
|
|||
|
|
- 样本标识:`sample_index`, `roi`, `frame_name`
|
|||
|
|
- GT/Pred 索引:`gt_index`, `pred_index`
|
|||
|
|
- 类别:`cls_id`, `cls_name`
|
|||
|
|
- 2D 匹配:`confidence`, `match_iou`
|
|||
|
|
- 3D 属性:
|
|||
|
|
- `gt_x_m / pred_x_m`
|
|||
|
|
- `gt_y_m / pred_y_m`
|
|||
|
|
- `gt_z_m / pred_z_m`
|
|||
|
|
- `gt_depth_m / pred_depth_m`
|
|||
|
|
- `gt_yaw_deg / pred_yaw_deg`
|
|||
|
|
- `x_abs_m / y_abs_m / z_abs_m`
|
|||
|
|
- `center_error_m`
|
|||
|
|
- `yaw_abs_deg`
|
|||
|
|
|
|||
|
|
### 5.2 yaw 误差定义
|
|||
|
|
|
|||
|
|
当前脚本的 yaw 误差不是普通 `|pred - gt|`,而是 **pi 周期误差**:
|
|||
|
|
|
|||
|
|
- 先做 `[-pi, pi)` wrap
|
|||
|
|
- 再取 `min(diff, |pi - diff|)`
|
|||
|
|
|
|||
|
|
含义是:
|
|||
|
|
|
|||
|
|
- 180 度前后翻转不被当成大错
|
|||
|
|
- 更接近“朝向轴”误差,而不是“严格方向”误差
|
|||
|
|
|
|||
|
|
对应函数:
|
|||
|
|
|
|||
|
|
- `angle_abs_deg(...)`
|
|||
|
|
|
|||
|
|
这点非常重要,读报告时必须按这个口径理解所有 yaw 指标。
|
|||
|
|
|
|||
|
|
### 5.3 position_eligible
|
|||
|
|
|
|||
|
|
不是所有 matched_3d 都会进入位置误差统计。当前实现里:
|
|||
|
|
|
|||
|
|
- `position_eligible = (cls in complete_3d_classes) or (not cut_object)`
|
|||
|
|
|
|||
|
|
也就是说:
|
|||
|
|
|
|||
|
|
- 完整 3D 类,总是参与位置误差
|
|||
|
|
- face-3D 类如果是 cut object,则不参与位置误差
|
|||
|
|
|
|||
|
|
因此:
|
|||
|
|
|
|||
|
|
- `matched_3d` 是形状/yaw层面的 3D 成功样本数
|
|||
|
|
- `matched_pos` 才是位置误差真正参与统计的样本数
|
|||
|
|
|
|||
|
|
### 5.4 position_error_basis
|
|||
|
|
|
|||
|
|
位置误差并不总是用 box center 计算。
|
|||
|
|
|
|||
|
|
当前实现优先级是:
|
|||
|
|
|
|||
|
|
1. 对 face_3d 类,如果 GT 和 Pred 都能解析到同一个可见 face,则使用该 `face_center`
|
|||
|
|
2. 否则退回 `box_center`
|
|||
|
|
|
|||
|
|
因此 record 中会有:
|
|||
|
|
|
|||
|
|
- `position_error_basis = face_center` 或 `box_center`
|
|||
|
|
|
|||
|
|
这会影响:
|
|||
|
|
|
|||
|
|
- `x_abs_m`
|
|||
|
|
- `y_abs_m`
|
|||
|
|
- `z_abs_m`
|
|||
|
|
- `center_error_m`
|
|||
|
|
|
|||
|
|
### 5.5 yaw compare 相关字段
|
|||
|
|
|
|||
|
|
脚本会同时保存三类 yaw:
|
|||
|
|
|
|||
|
|
1. `pred_yaw`
|
|||
|
|
- 来自 41 维 whole 头的直接 yaw 回归
|
|||
|
|
2. `pred_edge_visible_yaw`
|
|||
|
|
- 来自 edge 几何重建
|
|||
|
|
- 只有 `edge_confident=True` 时才记为有效
|
|||
|
|
3. `pred_edge_bucket_visible_yaw`
|
|||
|
|
- 记录当前 edge 选择器给出的 yaw
|
|||
|
|
- 即使它不满足“正式 edge 有效条件”,也会保留,用于 bucket 诊断
|
|||
|
|
|
|||
|
|
同时会记录:
|
|||
|
|
|
|||
|
|
- `direct_visible_yaw_abs_deg`
|
|||
|
|
- `edge_visible_yaw_abs_deg`
|
|||
|
|
- `direct_minus_edge_visible_yaw_abs_deg`
|
|||
|
|
|
|||
|
|
### 5.6 yaw_compare_eligible
|
|||
|
|
|
|||
|
|
只有满足下列条件,样本才被认为“允许进入 yaw compare 范围”:
|
|||
|
|
|
|||
|
|
- `|gt_x_m| < yaw_compare_max_lateral_dist_m`
|
|||
|
|
|
|||
|
|
默认 lateral limit 很大,来自:
|
|||
|
|
|
|||
|
|
- `DEFAULT_YAW_COMPARE_MAX_LATERAL_DIST_M = 30m`
|
|||
|
|
|
|||
|
|
但真正进入 `yaw_compare_count` 的条件更严格,还需要:
|
|||
|
|
|
|||
|
|
- direct yaw 有效
|
|||
|
|
- edge yaw 有效
|
|||
|
|
|
|||
|
|
也就是:
|
|||
|
|
|
|||
|
|
- `yaw_compare_eligible` 只是“允许参与”
|
|||
|
|
- `yaw_compare_count` 才是“真的成对比较了 direct vs edge”
|
|||
|
|
|
|||
|
|
## 6. bucket 聚合指标
|
|||
|
|
|
|||
|
|
所有 overall/class/breakdown/lateral-bin 等汇总,最终都通过 `summarize_metric_bucket(...)` 生成。
|
|||
|
|
|
|||
|
|
## 6.1 计数项
|
|||
|
|
|
|||
|
|
- `gt_total`
|
|||
|
|
- `pred_total`
|
|||
|
|
- `matched_2d`
|
|||
|
|
- `matched_3d`
|
|||
|
|
- `matched_pos`
|
|||
|
|
- `yaw_compare_eligible_count`
|
|||
|
|
- `yaw_compare_count`
|
|||
|
|
- `length_compare_count`
|
|||
|
|
|
|||
|
|
## 6.2 2D 派生项
|
|||
|
|
|
|||
|
|
- `precision_2d = matched_2d / pred_total`
|
|||
|
|
- `recall_2d = matched_2d / gt_total`
|
|||
|
|
- `f1_2d`
|
|||
|
|
|
|||
|
|
## 6.3 3D 主指标
|
|||
|
|
|
|||
|
|
- `mean_confidence`
|
|||
|
|
- `mean_match_iou`
|
|||
|
|
- `yaw_mae_deg`
|
|||
|
|
- `yaw_p90_deg`
|
|||
|
|
- `x_abs_mae_m`
|
|||
|
|
- `y_abs_mae_m`
|
|||
|
|
- `z_abs_mae_m`
|
|||
|
|
- `center_error_mae_m`
|
|||
|
|
|
|||
|
|
## 6.4 direct vs edge 对比指标
|
|||
|
|
|
|||
|
|
- `direct_regression_yaw_mae_deg`
|
|||
|
|
- `direct_regression_yaw_p90_deg`
|
|||
|
|
- `edge_based_yaw_mae_deg`
|
|||
|
|
- `edge_based_yaw_p90_deg`
|
|||
|
|
- `mean_direct_minus_edge_yaw_deg`
|
|||
|
|
- `median_direct_minus_edge_yaw_deg`
|
|||
|
|
- `yaw_compare_edge_better_count/rate`
|
|||
|
|
- `yaw_compare_direct_better_count/rate`
|
|||
|
|
- `yaw_compare_tie_count/rate`
|
|||
|
|
|
|||
|
|
脚本的判优规则是:
|
|||
|
|
|
|||
|
|
- `edge_err + eps < direct_err` 记为 edge better
|
|||
|
|
- `direct_err + eps < edge_err` 记为 direct better
|
|||
|
|
- 否则 tie
|
|||
|
|
|
|||
|
|
## 6.5 长度对比指标
|
|||
|
|
|
|||
|
|
当前还统计了 direct box 与 edge box 的车长误差对比:
|
|||
|
|
|
|||
|
|
- `direct_regression_length_mae_m`
|
|||
|
|
- `side_edge_length_mae_m`
|
|||
|
|
- `mean_direct_minus_side_edge_length_m`
|
|||
|
|
- `length_compare_edge_better_count/rate`
|
|||
|
|
- `length_compare_direct_better_count/rate`
|
|||
|
|
- `length_compare_tie_count/rate`
|
|||
|
|
|
|||
|
|
## 6.6 超阈值坏例占比
|
|||
|
|
|
|||
|
|
- `yaw_bad_rate = yaw_bad_count / matched_3d`
|
|||
|
|
- `horizontal_bad_rate = x_bad_count / matched_pos`
|
|||
|
|
- `vertical_bad_rate = z_bad_count / matched_pos`
|
|||
|
|
|
|||
|
|
默认阈值:
|
|||
|
|
|
|||
|
|
- yaw:`5 deg`
|
|||
|
|
- horizontal:`0.5 m`
|
|||
|
|
- vertical:`0.5 m`
|
|||
|
|
|
|||
|
|
## 6.7 当前实现的命名注意事项
|
|||
|
|
|
|||
|
|
这里有一个很容易误解的点:
|
|||
|
|
|
|||
|
|
- `vertical_*` 相关统计,当前实现实际上是基于 `z_abs_m` 做的,也就是纵向/深度误差
|
|||
|
|
- 不是基于 `y_abs_m`
|
|||
|
|
|
|||
|
|
具体来说:
|
|||
|
|
|
|||
|
|
- `bad_cases_vertical.csv` 的导出条件是 `z_abs_m > vertical_bad_threshold_m`
|
|||
|
|
- `vertical_abs_mae_m` 实际对应 `mean(z_abs_m)`
|
|||
|
|
- `class_vertical_depth_5m.csv` 也是按 `position_gt_z_m` 分桶
|
|||
|
|
|
|||
|
|
另外:
|
|||
|
|
|
|||
|
|
- `y_abs_m` 会被记录
|
|||
|
|
- 但 `y_bad_count` 当前实现没有真正累加,因此 `y_bad_rate` 基本恒为 `0` 或无实际含义
|
|||
|
|
|
|||
|
|
所以看报告时,建议把:
|
|||
|
|
|
|||
|
|
- `horizontal` 理解为 `x`
|
|||
|
|
- `vertical` 理解为 `z/depth`
|
|||
|
|
|
|||
|
|
## 7. breakdown 与分桶统计
|
|||
|
|
|
|||
|
|
## 7.1 breakdowns.json
|
|||
|
|
|
|||
|
|
脚本会输出 `breakdowns.json`,当前有 5 类 breakdown:
|
|||
|
|
|
|||
|
|
1. `cut_status`
|
|||
|
|
- `cut`
|
|||
|
|
- `non_cut`
|
|||
|
|
- `n/a`
|
|||
|
|
2. `face_visibility`
|
|||
|
|
- `front_rear_only`
|
|||
|
|
- `side only`
|
|||
|
|
- `two-face`
|
|||
|
|
3. `distance_bin`
|
|||
|
|
- `<20m`
|
|||
|
|
- `20-40m`
|
|||
|
|
- `40-60m`
|
|||
|
|
- `>=60m`
|
|||
|
|
4. `bbox_diag_bin`
|
|||
|
|
- `<32px`
|
|||
|
|
- `32-64px`
|
|||
|
|
- `64-128px`
|
|||
|
|
- `>=128px`
|
|||
|
|
5. `class_group`
|
|||
|
|
- `face_3d`
|
|||
|
|
- `complete_3d`
|
|||
|
|
- `2d_only`
|
|||
|
|
|
|||
|
|
## 7.2 interval CSV
|
|||
|
|
|
|||
|
|
脚本还会输出几类按区间统计的 CSV:
|
|||
|
|
|
|||
|
|
### `class_horizontal_lateral_5m.csv`
|
|||
|
|
|
|||
|
|
- 横轴:GT 的 `position_gt_x_m`
|
|||
|
|
- 分桶:`[-30m, 30m)` 内 5m 一桶
|
|||
|
|
- 指标:`x_abs_m`
|
|||
|
|
- 额外输出:
|
|||
|
|
- mean
|
|||
|
|
- median
|
|||
|
|
- p90
|
|||
|
|
- max
|
|||
|
|
- `rate_gt_0p5`
|
|||
|
|
|
|||
|
|
### `class_vertical_depth_5m.csv`
|
|||
|
|
|
|||
|
|
- 横轴:GT 的 `position_gt_z_m`
|
|||
|
|
- 分桶:5m 一桶
|
|||
|
|
- 指标:`z_abs_m`
|
|||
|
|
|
|||
|
|
### `class_yaw_depth_10m.csv`
|
|||
|
|
|
|||
|
|
- 横轴:GT 的 `gt_depth_m`
|
|||
|
|
- 分桶:10m 一桶
|
|||
|
|
- 指标:`yaw_abs_deg`
|
|||
|
|
|
|||
|
|
### `class_yaw_horizontal_5m.csv`
|
|||
|
|
|
|||
|
|
- 横轴:GT 的 `gt_x_m`
|
|||
|
|
- 分桶:`[-30m, 30m)` 内 5m 一桶
|
|||
|
|
- 指标:`yaw_abs_deg`
|
|||
|
|
|
|||
|
|
### `yaw_compare_signed_lateral_5m.csv`
|
|||
|
|
|
|||
|
|
这是专门给 direct vs edge yaw 对比用的:
|
|||
|
|
|
|||
|
|
- 横轴:GT 的 `gt_x_m`
|
|||
|
|
- 范围:`[-yaw_compare_max_lateral_dist_m, yaw_compare_max_lateral_dist_m)`
|
|||
|
|
- 分桶:5m
|
|||
|
|
- 额外还有一个纵向过滤条件:
|
|||
|
|
- `0 <= gt_z_m < 50m`
|
|||
|
|
|
|||
|
|
桶内不是简单均值列表,而是整套 `summarize_metric_bucket(...)` 输出。
|
|||
|
|
|
|||
|
|
### `yaw_compare_signed_lateral_5m_by_face_visibility.csv`
|
|||
|
|
|
|||
|
|
与上面类似,但再按 `face_visibility_bucket` 细分:
|
|||
|
|
|
|||
|
|
- `front_rear_only`
|
|||
|
|
- `side only`
|
|||
|
|
- `two-face`
|
|||
|
|
|
|||
|
|
## 7.3 large vehicle 专项统计
|
|||
|
|
|
|||
|
|
脚本对大车类单独做了一个 two-face yaw 对比视角:
|
|||
|
|
|
|||
|
|
- 类别集合:`5, 6, 7`
|
|||
|
|
- 即:
|
|||
|
|
- bus
|
|||
|
|
- truck/tanker/large_truck/construction_vehicle
|
|||
|
|
- special_vehicle
|
|||
|
|
|
|||
|
|
输出在:
|
|||
|
|
|
|||
|
|
- `summary.json` 的 `large_vehicle_compare`
|
|||
|
|
|
|||
|
|
## 8. 坏例导出规则
|
|||
|
|
|
|||
|
|
## 8.1 CSV 全量导出
|
|||
|
|
|
|||
|
|
脚本会把所有超阈值样本写入 CSV:
|
|||
|
|
|
|||
|
|
- `bad_cases_yaw.csv`
|
|||
|
|
- 条件:`yaw_abs_deg >= yaw_bad_threshold_deg`
|
|||
|
|
- `bad_cases_horizontal.csv`
|
|||
|
|
- 条件:`position_eligible and x_abs_m > horizontal_bad_threshold_m`
|
|||
|
|
- `bad_cases_vertical.csv`
|
|||
|
|
- 条件:`position_eligible and z_abs_m > vertical_bad_threshold_m`
|
|||
|
|
- `bad_cases_2d_false_negative.csv`
|
|||
|
|
- `bad_cases_2d_false_positive.csv`
|
|||
|
|
|
|||
|
|
## 8.2 可视化导出
|
|||
|
|
|
|||
|
|
可视化不是把所有坏例都画出来,而是做 reservoir sampling:
|
|||
|
|
|
|||
|
|
- overall top-k
|
|||
|
|
- per-class top-k
|
|||
|
|
- per-error-bin top-k
|
|||
|
|
|
|||
|
|
其中按误差区间导出时:
|
|||
|
|
|
|||
|
|
- yaw:`1 deg` 一桶
|
|||
|
|
- horizontal/vertical:`0.5 m` 一桶
|
|||
|
|
- 每桶先保留最多 `error_bin_badcases`
|
|||
|
|
- 再按 frame 聚合,最终每桶最多导出 `error_bin_samples_per_bin` 张图
|
|||
|
|
|
|||
|
|
## 9. 输出文件组织
|
|||
|
|
|
|||
|
|
## 9.1 每个 ROI 目录
|
|||
|
|
|
|||
|
|
每个 ROI 目录下会有:
|
|||
|
|
|
|||
|
|
- `summary.json`
|
|||
|
|
- `summary.md`
|
|||
|
|
- `summary_zh.md`
|
|||
|
|
- `class_metrics.csv`
|
|||
|
|
- `breakdowns.json`
|
|||
|
|
- `class_horizontal_lateral_5m.csv`
|
|||
|
|
- `class_vertical_depth_5m.csv`
|
|||
|
|
- `class_yaw_depth_10m.csv`
|
|||
|
|
- `class_yaw_horizontal_5m.csv`
|
|||
|
|
- `yaw_compare_signed_lateral_5m.csv`
|
|||
|
|
- `yaw_compare_signed_lateral_5m_by_face_visibility.csv`
|
|||
|
|
- `bad_cases_yaw.csv`
|
|||
|
|
- `bad_cases_horizontal.csv`
|
|||
|
|
- `bad_cases_vertical.csv`
|
|||
|
|
- `bad_cases_2d_false_negative.csv`
|
|||
|
|
- `bad_cases_2d_false_positive.csv`
|
|||
|
|
- `confusion_matrix_normalized.png`
|
|||
|
|
- `2d_confidence_curves/*.png`
|
|||
|
|
- `visuals/...`
|
|||
|
|
|
|||
|
|
## 9.2 总输出目录
|
|||
|
|
|
|||
|
|
总输出目录会汇总所有 ROI,写出:
|
|||
|
|
|
|||
|
|
- `summary.json`
|
|||
|
|
- `summary.md`
|
|||
|
|
- `summary_zh.md`
|
|||
|
|
- `report.html`
|
|||
|
|
|
|||
|
|
如果启用了 data portrait,还会额外有:
|
|||
|
|
|
|||
|
|
- `<split>_portrait/summary.json`
|
|||
|
|
- portrait 相关 CSV
|
|||
|
|
|
|||
|
|
## 10. 一句话总结
|
|||
|
|
|
|||
|
|
`analyze_val_two_roi_badcases.py` 当前实现的核心是:
|
|||
|
|
|
|||
|
|
- 用 `IoU>=0.5 + 类别一致` 的贪心匹配构造 object-level 记录
|
|||
|
|
- 以 record 为中心,统一聚合 2D、3D、direct-vs-edge、分桶和坏例统计
|
|||
|
|
- 2D AP 与 thresholded 2D 指标分开算
|
|||
|
|
- yaw 误差采用 pi 周期口径
|
|||
|
|
- 报告里名为 `vertical` 的主统计,当前实际上对应 `z/depth` 误差
|
|||
|
|
|
|||
|
|
如果后续要和训练期 validator 对齐,最值得先确认的就是:
|
|||
|
|
|
|||
|
|
- yaw 误差口径是否仍然保持 pi 周期
|
|||
|
|
- `vertical` 是否继续表示 `z`
|
|||
|
|
- `position_eligible` 是否继续排除 cut 的 face-3D 样本
|