379 lines
10 KiB
Markdown
379 lines
10 KiB
Markdown
|
|
# 真值可视化脚本说明
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
本目录包含用于单帧图像真值可视化的脚本,可以实现2D和3D边界框的可视化。
|
|||
|
|
|
|||
|
|
## 真值读取到可视化的完整流程
|
|||
|
|
|
|||
|
|
### 1. 数据加载流程(utils/dataloaders3d.py)
|
|||
|
|
|
|||
|
|
#### 1.1 标签读取 (`load_label()`)
|
|||
|
|
```python
|
|||
|
|
# 标签文件格式(47维数组):
|
|||
|
|
# - 列0: class (类别ID)
|
|||
|
|
# - 列1-4: x, y, w, h (归一化的2D边界框中心和宽高)
|
|||
|
|
# - 列5: score (置信度)
|
|||
|
|
# - 列6-8: x3d, y3d, z3d (3D中心点在相机坐标系下的坐标)
|
|||
|
|
# - 列9-11: length, height, width (3D框的尺寸)
|
|||
|
|
# - 列12: rot_y (偏航角旋转)
|
|||
|
|
# - 列13-14: xc, yc (3D框中心投影到2D的归一化坐标)
|
|||
|
|
# - 列15: alpha (观测角)
|
|||
|
|
# - 列16-23: 前面信息 [x3d, y3d, z3d, alpha, xc, yc, score, visible]
|
|||
|
|
# - 列24-31: 后面信息
|
|||
|
|
# - 列32-39: 左面信息
|
|||
|
|
# - 列40-47: 右面信息
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
支持三种标签格式:
|
|||
|
|
- **2D only (6列)**: 仅包含2D边界框
|
|||
|
|
- **2D+3D simple (18列)**: 针对行人、自行车、骑手,包含基本3D信息
|
|||
|
|
- **2D+3D+faces (50列)**: 针对车辆、三轮车,包含完整的4个面信息
|
|||
|
|
|
|||
|
|
#### 1.2 图像读取 (`load_image()`)
|
|||
|
|
```python
|
|||
|
|
# 使用cv2.imread读取BGR格式图像
|
|||
|
|
img = cv2.imread(image_path) # (H, W, 3) BGR
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 1.3 标定参数读取
|
|||
|
|
```python
|
|||
|
|
# 从 camera4.json 读取相机内参
|
|||
|
|
{
|
|||
|
|
"focal_u": fx, # x方向焦距
|
|||
|
|
"focal_v": fy, # y方向焦距
|
|||
|
|
"cu": cx, # x方向主点
|
|||
|
|
"cv": cy, # y方向主点
|
|||
|
|
"pitch": pitch, # 相机俯仰角
|
|||
|
|
"distort_coeffs": [] # 畸变系数
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 数据预处理流程
|
|||
|
|
|
|||
|
|
#### 2.1 ROI变换(可选)
|
|||
|
|
```python
|
|||
|
|
# 计算消失点和裁剪中心
|
|||
|
|
vanish_y = cy - fy * tan(pitch * π/180)
|
|||
|
|
crop_center = (oriW/2, vanish_y)
|
|||
|
|
|
|||
|
|
# 计算ROI边界
|
|||
|
|
roi_x1 = crop_center_x - roi_width/2
|
|||
|
|
roi_y1 = crop_center_y - roi_height/2
|
|||
|
|
roi_x2 = roi_x1 + roi_width
|
|||
|
|
roi_y2 = roi_y1 + roi_height
|
|||
|
|
|
|||
|
|
# 裁剪图像
|
|||
|
|
img_roi = img[roi_y1:roi_y2, roi_x1:roi_x2]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.2 标签坐标转换
|
|||
|
|
```python
|
|||
|
|
# 将2D边界框从原始图像坐标转换到ROI坐标
|
|||
|
|
# 1. 归一化xywh -> 绝对xyxy
|
|||
|
|
# 2. 平移到ROI相对坐标
|
|||
|
|
# 3. 裁剪到ROI边界内
|
|||
|
|
# 4. 重新归一化
|
|||
|
|
|
|||
|
|
# UV坐标(面中心投影)也需要相应转换
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.3 深度归一化(可选)
|
|||
|
|
```python
|
|||
|
|
# 当使用虚拟焦距时,需要缩放z3d深度值
|
|||
|
|
# 只缩放Z坐标,X和Y从UV和Z恢复
|
|||
|
|
scale = virtual_fx / fx_original
|
|||
|
|
z3d_normalized = z3d_original * scale
|
|||
|
|
|
|||
|
|
# 包括:
|
|||
|
|
# - 列7: 整体中心z3d
|
|||
|
|
# - 列17: 前面中心z3d
|
|||
|
|
# - 列25: 后面中心z3d
|
|||
|
|
# - 列33: 左面中心z3d
|
|||
|
|
# - 列41: 右面中心z3d
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 可视化流程(test_val_visualize.py)
|
|||
|
|
|
|||
|
|
#### 3.1 2D可视化
|
|||
|
|
```python
|
|||
|
|
# 使用 plot_2d_boxes_to_image() 或类似逻辑
|
|||
|
|
# 1. 放大图像(scale_factor=2)获得更清晰的可视化
|
|||
|
|
# 2. 将归一化坐标转换为像素坐标
|
|||
|
|
# 3. 使用Annotator绘制边界框和类别标签
|
|||
|
|
# 4. 添加标签文字(如"2D GT")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.2 3D可视化
|
|||
|
|
|
|||
|
|
**步骤1:解码3D框** (`decode_and_reconstruct_3d_box_from_target()`)
|
|||
|
|
```python
|
|||
|
|
# 针对不同类别采用不同策略:
|
|||
|
|
|
|||
|
|
# 车辆类(class 0, 13):基于最佳可见面重建
|
|||
|
|
# 1. 遍历4个面(前、后、左、右)
|
|||
|
|
# 2. 选择可见且得分最高的面
|
|||
|
|
# 3. 从面中心(u,v,z)反投影得到3D中心
|
|||
|
|
# 4. 使用dimensions和rot_y计算8个3D角点
|
|||
|
|
|
|||
|
|
# 行人类(class 1, 2, 3):基于完整3D框
|
|||
|
|
# 1. 直接使用(x3d, y3d, z3d)作为3D中心
|
|||
|
|
# 2. 使用dimensions和rot_y计算8个3D角点
|
|||
|
|
# 3. 注意:需要将归一化深度转换回原始尺度
|
|||
|
|
# z3d_original = z3d_normalized * depth_scale
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**步骤2:投影和绘制** (`plot_3d_boxes_from_decoded_targets()`)
|
|||
|
|
```python
|
|||
|
|
# 1. 将3D角点投影到2D图像平面
|
|||
|
|
# u = fx * X/Z + cx
|
|||
|
|
# v = fy * Y/Z + cy
|
|||
|
|
# 2. 绘制3D框的12条边
|
|||
|
|
# 3. 使用不同颜色区分前后面
|
|||
|
|
# 4. 对于车辆类,标记最佳可见面的中心点
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.3 BEV可视化
|
|||
|
|
```python
|
|||
|
|
# 1. 创建空白BEV图像 (draw_bev_blank)
|
|||
|
|
# 2. 对每个3D框调用 drawbev() 绘制俯视图
|
|||
|
|
# 3. 使用不同颜色区分真值(绿色)和预测(红色)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 关键坐标系统
|
|||
|
|
|
|||
|
|
#### 4.1 图像坐标系
|
|||
|
|
- 原点:图像左上角
|
|||
|
|
- x轴:向右
|
|||
|
|
- y轴:向下
|
|||
|
|
- 单位:像素或归一化[0,1]
|
|||
|
|
|
|||
|
|
#### 4.2 相机坐标系
|
|||
|
|
- 原点:相机光心
|
|||
|
|
- x轴:向右
|
|||
|
|
- y轴:向下
|
|||
|
|
- z轴:向前(深度方向)
|
|||
|
|
- 单位:米
|
|||
|
|
|
|||
|
|
#### 4.3 投影关系
|
|||
|
|
```
|
|||
|
|
u = fx * X/Z + cx
|
|||
|
|
v = fy * Y/Z + cy
|
|||
|
|
|
|||
|
|
# 反投影(已知u,v,Z求X,Y):
|
|||
|
|
X = (u - cx) * Z / fx
|
|||
|
|
Y = (v - cy) * Z / fy
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使用方法
|
|||
|
|
|
|||
|
|
### 基本用法(不应用ROI)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python scripts_for_gt/visualize_single_frame.py \
|
|||
|
|
--image /path/to/images/frame_001.jpg \
|
|||
|
|
--label /path/to/labels/frame_001.txt \
|
|||
|
|
--output ./gt_visualization
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 带ROI变换(与训练一致)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python scripts_for_gt/visualize_single_frame.py \
|
|||
|
|
--image /path/to/images/frame_001.jpg \
|
|||
|
|
--label /path/to/labels/frame_001.txt \
|
|||
|
|
--output ./gt_visualization \
|
|||
|
|
--roi 704 352 \
|
|||
|
|
--virtual-fx 500 \
|
|||
|
|
--ori-img-size 1920 1080
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 参数说明
|
|||
|
|
|
|||
|
|
- `--image`: 图像文件路径(必需)
|
|||
|
|
- `--label`: 标签文件路径(必需)
|
|||
|
|
- `--output`: 输出目录(默认:./gt_visualization)
|
|||
|
|
- `--calib`: 相机标定文件路径(camera4.json),如不提供会自动从图像路径推断
|
|||
|
|
- `--roi`: ROI尺寸(宽 高),如:`--roi 704 352`
|
|||
|
|
- `--virtual-fx`: 虚拟焦距,用于深度归一化
|
|||
|
|
- `--ori-img-size`: 原始图像尺寸(宽 高),如不提供则从图像自动获取
|
|||
|
|
|
|||
|
|
### 输出文件
|
|||
|
|
|
|||
|
|
脚本会在输出目录生成以下文件:
|
|||
|
|
- `{filename}_2d_gt.jpg`: 2D边界框可视化
|
|||
|
|
- `{filename}_3d_gt.jpg`: 3D边界框投影可视化
|
|||
|
|
- `{filename}_bev_gt.jpg`: 鸟瞰图(BEV)可视化
|
|||
|
|
- `{filename}_combined.jpg`: 组合可视化(2D + 3D + BEV)
|
|||
|
|
|
|||
|
|
## 示例
|
|||
|
|
|
|||
|
|
假设数据结构如下:
|
|||
|
|
```
|
|||
|
|
/data/
|
|||
|
|
├── images/
|
|||
|
|
│ └── frame_001.jpg
|
|||
|
|
├── labels/
|
|||
|
|
│ └── frame_001.txt
|
|||
|
|
└── calib/
|
|||
|
|
└── L2_calib/
|
|||
|
|
└── camera4.json
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
运行命令:
|
|||
|
|
```bash
|
|||
|
|
python scripts_for_gt/visualize_single_frame.py \
|
|||
|
|
--image /data/images/frame_001.jpg \
|
|||
|
|
--label /data/labels/frame_001.txt \
|
|||
|
|
--output ./output \
|
|||
|
|
--roi 704 352 \
|
|||
|
|
--virtual-fx 500
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
1. **标定文件自动推断**:如果不指定`--calib`,脚本会自动查找与图像路径对应的标定文件(`../calib/L2_calib/camera4.json`)
|
|||
|
|
|
|||
|
|
2. **深度归一化**:当使用`--virtual-fx`时,z3d坐标会被缩放以匹配虚拟焦距,这与训练时的处理一致
|
|||
|
|
|
|||
|
|
3. **坐标系统**:
|
|||
|
|
- 输入标签使用归一化坐标[0,1]
|
|||
|
|
- 3D坐标使用相机坐标系(米)
|
|||
|
|
- 深度归一化后需要在可视化时转换回原始尺度
|
|||
|
|
|
|||
|
|
4. **支持的类别**:
|
|||
|
|
- 0: vehicle(车辆)- 使用面策略
|
|||
|
|
- 1: pedestrian(行人)- 使用完整框
|
|||
|
|
- 2: bicycle(自行车)- 使用完整框
|
|||
|
|
- 3: rider(骑手)- 使用完整框
|
|||
|
|
- 13: tricycle(三轮车)- 使用面策略
|
|||
|
|
|
|||
|
|
## 快速测试
|
|||
|
|
|
|||
|
|
提供了一个自动测试脚本,可以自动从验证集中找到第一个有效样本并进行可视化:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 使用默认数据集配置
|
|||
|
|
python scripts_for_gt/test_visualization.py
|
|||
|
|
|
|||
|
|
# 指定数据集配置
|
|||
|
|
python scripts_for_gt/test_visualization.py --data data/mono3d.yaml --output ./test_output
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
测试脚本会:
|
|||
|
|
1. 从数据集配置中读取验证集路径
|
|||
|
|
2. 自动查找第一个有标签的样本
|
|||
|
|
3. 分别测试原始图像可视化和ROI变换可视化
|
|||
|
|
4. 生成所有可视化结果到指定目录
|
|||
|
|
|
|||
|
|
## 批量处理
|
|||
|
|
|
|||
|
|
如果需要批量处理多帧图像,可以使用批量脚本:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python scripts_for_gt/visualize_batch.py \
|
|||
|
|
--image-dir /path/to/images \
|
|||
|
|
--label-dir /path/to/labels \
|
|||
|
|
--output ./batch_output \
|
|||
|
|
--roi 704 352 \
|
|||
|
|
--virtual-fx 500 \
|
|||
|
|
--max-samples 10
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
参数说明:
|
|||
|
|
- `--image-dir`: 图像目录
|
|||
|
|
- `--label-dir`: 标签目录
|
|||
|
|
- `--output`: 输出目录
|
|||
|
|
- `--calib-dir`: 标定文件目录(可选)
|
|||
|
|
- `--roi`: ROI尺寸
|
|||
|
|
- `--virtual-fx`: 虚拟焦距
|
|||
|
|
- `--max-samples`: 最大处理样本数(可选)
|
|||
|
|
|
|||
|
|
## 条件过滤可视化
|
|||
|
|
|
|||
|
|
如果需要从训练集或验证集中筛选特定条件的样本进行可视化,可以使用过滤脚本:
|
|||
|
|
|
|||
|
|
### 示例1: 可视化包含两轮车的样本(空间范围过滤)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 只可视化两轮车在左右各10米、纵向50米范围内的样本
|
|||
|
|
python scripts_for_gt/visualize_filtered_train.py \
|
|||
|
|
--data data/mono3d.yaml \
|
|||
|
|
--target-class bicycle \
|
|||
|
|
--x-range -10 10 \
|
|||
|
|
--z-range 0 50 \
|
|||
|
|
--max-samples 20 \
|
|||
|
|
--output ./bicycle_samples
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 示例2: 可视化包含行人的样本
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 可视化前50个包含行人的训练样本
|
|||
|
|
python scripts_for_gt/visualize_filtered_train.py \
|
|||
|
|
--data data/mono3d.yaml \
|
|||
|
|
--target-class pedestrian \
|
|||
|
|
--max-samples 50 \
|
|||
|
|
--output ./pedestrian_samples
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 示例3: 可视化特定空间范围内的车辆
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 可视化车辆在左右5米、纵向10-30米范围内的样本
|
|||
|
|
python scripts_for_gt/visualize_filtered_train.py \
|
|||
|
|
--data data/mono3d.yaml \
|
|||
|
|
--target-class vehicle \
|
|||
|
|
--x-range -5 5 \
|
|||
|
|
--z-range 10 30 \
|
|||
|
|
--max-samples 30 \
|
|||
|
|
--output ./vehicle_samples
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 过滤参数说明
|
|||
|
|
|
|||
|
|
- `--target-class`: 目标类别(vehicle, pedestrian, bicycle, rider, motorcycle, tricycle)
|
|||
|
|
- `--x-range MIN MAX`: X坐标范围(左右方向),单位:米
|
|||
|
|
- `--y-range MIN MAX`: Y坐标范围(上下方向),单位:米
|
|||
|
|
- `--z-range MIN MAX`: Z坐标范围(前后方向/深度),单位:米
|
|||
|
|
- `--min-targets`: 最少目标数量(默认1)
|
|||
|
|
- `--max-samples`: 最大可视化样本数
|
|||
|
|
- `--split`: 数据集划分(train或val,默认train)
|
|||
|
|
- `--use-roi`: 使用ROI变换
|
|||
|
|
|
|||
|
|
### 坐标系说明
|
|||
|
|
|
|||
|
|
相机坐标系:
|
|||
|
|
- **X轴**: 向右为正(单位:米)
|
|||
|
|
- **Y轴**: 向下为正(单位:米)
|
|||
|
|
- **Z轴**: 向前为正(深度方向,单位:米)
|
|||
|
|
|
|||
|
|
示例:
|
|||
|
|
- `--x-range -10 10`: 左右各10米范围
|
|||
|
|
- `--z-range 0 50`: 前方0到50米范围
|
|||
|
|
- `--y-range -2 1`: 相机水平面上下2米到下方1米范围
|
|||
|
|
|
|||
|
|
## 脚本说明
|
|||
|
|
|
|||
|
|
本目录包含以下脚本:
|
|||
|
|
|
|||
|
|
1. **visualize_single_frame.py** - 单帧可视化脚本
|
|||
|
|
- 核心功能:读取单帧图像和标签,生成2D、3D和BEV可视化
|
|||
|
|
- 支持ROI变换和深度归一化
|
|||
|
|
|
|||
|
|
2. **visualize_batch.py** - 批量可视化脚本
|
|||
|
|
- 批量处理多帧图像
|
|||
|
|
- 自动匹配图像和标签文件
|
|||
|
|
|
|||
|
|
3. **test_visualization.py** - 快速测试脚本
|
|||
|
|
- 自动查找验证集样本
|
|||
|
|
- 测试不同配置的可视化效果
|
|||
|
|
|
|||
|
|
## 扩展功能
|
|||
|
|
|
|||
|
|
可以基于此脚本进行扩展:
|
|||
|
|
- 添加不同的可视化风格
|
|||
|
|
- 输出3D框参数到文件
|
|||
|
|
- 与预测结果对比
|
|||
|
|
- 统计分析(深度分布、尺寸分布等)
|