Files
Bird_detect_cascade_service_V2/README.md
T
2026-08-21 14:19:14 +08:00

301 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Bird Detect Cascade Batch
这是一个 **YOLOv5 + ConvNeXt + 贝叶斯密度估计** 级联鸟类识别批处理程序。它通过 bash 命令处理图片、视频或文件夹,并输出标注结果、JSON、XML。
## 1. 最常用运行方式
处理单张图片、单个视频或一个文件夹:
```bash
bash run_batch.sh --input /path/to/input
```
指定输出目录,并关闭密度估计:
```bash
bash run_batch.sh --input /path/to/input --output /path/to/runs --disable-density
```
输入路径可以是图片、视频,也可以是包含图片/视频的文件夹。默认会递归处理子文件夹。
三个模型都可以单独关闭,例如只运行密度估计:
```bash
bash run_batch.sh --input /path/to/input \
--disable-detection \
--disable-classification
```
## 2. 哪些参数可以直接写在 bash 指令里
下面这些参数都可以直接写在 `bash run_batch.sh ...` 后面,不需要改 Python 代码。
| bash 参数 | 默认值 | 含义 |
|---|---:|---|
| `--input PATH` | 无,必填 | 输入路径,可以是图片、视频或文件夹 |
| `--output PATH` | `./runs` | 输出根目录 |
| `--sample-interval INT` | `2` | 视频抽帧间隔,`2` 表示每 2 帧处理 1 帧 |
| `--recursive` | 开启 | 输入是文件夹时递归处理子目录 |
| `--no-recursive` | 关闭递归 | 只处理输入文件夹第一层文件 |
| `--enable-detection` | 开启 | 启用 YOLO 目标检测 |
| `--disable-detection` | 关闭目标检测 | 不加载、不运行 YOLO;检测结果为空 |
| `--enable-classification` | 开启 | 启用 ConvNeXt 细粒度识别 |
| `--disable-classification` | 关闭细粒度识别 | 不加载、不运行 ConvNeXt;保留 YOLO 检测框 |
| `--enable-density` | 开启 | 启用贝叶斯密度估计 |
| `--disable-density` | 关闭密度估计 | 不运行密度估计,只运行 YOLO + ConvNeXt |
| `--det-conf-thres FLOAT` | `0.25` | YOLO 第一层检测阈值,低于该值的框直接丢弃 |
| `--det-iou-thres FLOAT` | `0.45` | NMS IoU 阈值;越低,重叠框去得越狠 |
| `--det-second-conf-thres FLOAT` | `0.35` | YOLO 第二层过滤阈值,低于该值不会裁剪,也不会进入 ConvNeXt |
| `--min-box-area-ratio FLOAT` | `0.00002` | 过滤面积占比过小的噪声框 |
| `--max-box-area-ratio FLOAT` | `1.0` | 最大框面积占比;默认不按面积过滤大目标 |
| `--max-box-aspect-ratio FLOAT` | `6.0` | 过滤长宽比过大的细长框 |
| `--cls-show-conf-thres FLOAT` | `0.50` | 普通目标分类置信度低于该值时,不在结果图显示物种名 |
| `--large-box-area-ratio FLOAT` | `0.002` | 框面积占比超过该值时,认为是近景大目标 |
| `--large-box-cls-show-conf-thres FLOAT` | `0.25` | 大目标显示物种名的较低分类阈值 |
| `--show-large-box-name-always BOOL` | `true` | 大目标是否只要分类名非空就显示 |
| `--dense-scene-count-thres INT` | `20` | 密度估计数量达到该值时,认为是密集场景 |
| `--hide-cls-name-in-dense-scene BOOL` | `true` | 密集场景下是否隐藏所有物种名 |
| `--crop-padding-ratio FLOAT` | `0.08` | 送入 ConvNeXt 前,检测框向外扩的比例 |
| `--max-detections INT` | `50` | 单张图或单帧最多保留的检测框数量 |
| `--uniform-species-color BOOL` | `false` | `true` 时所有物种的检测框和标签统一使用同一种颜色 |
示例:降低检测阈值、提高进入分类前的二次过滤阈值:
```bash
bash run_batch.sh \
--input /path/to/input \
--det-conf-thres 0.15 \
--det-second-conf-thres 0.45
```
示例:密集场景仍然显示物种名:
```bash
bash run_batch.sh \
--input /path/to/input \
--hide-cls-name-in-dense-scene false
```
示例:让所有物种的检测框和标签统一使用绿色:
```bash
bash run_batch.sh \
--input /path/to/input \
--uniform-species-color true
```
## 3. 阈值怎么调
最关键的是这两个参数:
- `--det-conf-thres`: YOLO 第一层阈值。低于这个值的框会在 YOLO 后处理阶段直接丢弃。
- `--det-second-conf-thres`: YOLO 第二层阈值。低于这个值的框不会裁剪,也不会传给 ConvNeXt 分类。
常见调法:
- 漏检多:降低 `--det-conf-thres`,例如 `0.25 -> 0.15`。
- 误检多:提高 `--det-second-conf-thres`,例如 `0.35 -> 0.45`。
- 小噪声框多:提高 `--min-box-area-ratio`。
- 异常大框多:降低 `--max-box-area-ratio`;不要为了排除异常框把它设得过低,否则近景大鸟会被误删。
- 细长误检框多:降低 `--max-box-aspect-ratio`。
- 检测到了但不显示物种名:降低 `--cls-show-conf-thres`,或检查 `--hide-cls-name-in-dense-scene`。
- 密集场景过早隐藏物种名:提高 `--dense-scene-count-thres`,或设置 `--hide-cls-name-in-dense-scene false`。
这些阈值现在都可以写在 bash 指令里,不需要去代码里调。
## 4. 三个模型的开关
三个模型默认都开启:
```bash
bash run_batch.sh --input /path/to/input
```
关闭目标检测:
```bash
bash run_batch.sh --input /path/to/input --disable-detection
```
关闭细粒度识别,只输出 YOLO 检测框:
```bash
bash run_batch.sh --input /path/to/input --disable-classification
```
关闭密度估计:
```bash
bash run_batch.sh --input /path/to/input --disable-density
```
也可以任意组合,例如只运行目标检测:
```bash
bash run_batch.sh --input /path/to/input \
--disable-classification \
--disable-density
```
只运行密度估计:
```bash
bash run_batch.sh --input /path/to/input \
--disable-detection \
--disable-classification
```
注意:细粒度识别依赖目标检测提供裁剪框,因此关闭目标检测后,ConvNeXt 不会加载或运行,即使显式传入 `--enable-classification`。密度估计与另外两个模型相互独立。
关闭某个模型后:
- 对应 ONNX 模型不会加载,也不会执行推理;
- 关闭目标检测时,`results` 为空;
- 关闭细粒度识别时,每个检测结果的 `cls_class_id` 为 `-1`、`cls_class_name` 为空、`cls_confidence` 为 `0.0`;
- 关闭密度估计时,JSON 里的 `density` 为 `null`,结果图不显示密度热力图和密度估计数量。
颜色开关不影响模型推理和 JSON/XML,只影响结果图片或视频的可视化:
- `--uniform-species-color false`:默认行为,每个物种使用各自的稳定颜色;
- `--uniform-species-color true`:所有物种的检测框和标签统一使用绿色。
## 5. 哪些配置用环境变量,不直接写 bash 参数
模型路径、输入尺寸、设备这类参数通常不频繁改,所以保留为环境变量。它们可以写在 bash 命令前面,也不需要改代码。
| 环境变量 | 默认值 | 含义 |
|---|---:|---|
| `ENABLE_DETECTION` | `true` | 是否启用 YOLO 目标检测 |
| `ENABLE_CLASSIFICATION` | `true` | 是否启用 ConvNeXt 细粒度识别 |
| `ENABLE_DENSITY` | `true` | 是否启用密度估计 |
| `DET_MODEL_PATH` | `models/YNDC_20251010_yolov5_optimize.onnx` | YOLOv5 检测模型 |
| `DET_CLASSES_PATH` | `models/YNDC_20251010_yolov5_optimize.txt` | YOLO 类别文件 |
| `CLS_MODEL_PATH` | `models/HHK_20260525_mmcls_optimize.onnx` | ConvNeXt 分类模型 |
| `CLS_CLASSES_PATH` | `models/HHK_20260525_mmcls_optimize.txt` | ConvNeXt 类别文件 |
| `DENSITY_MODEL_PATH` | `models/bird_density.onnx` | 密度估计模型 |
| `DET_IMG_SIZE` | `640` | YOLO 输入尺寸 |
| `CLS_IMG_SIZE` | `224` | ConvNeXt 输入尺寸 |
| `DENSITY_IMG_SIZE` | `0` | 密度模型输入尺寸;`0` 表示自动读取模型输入 |
| `TARGET_DET_CLASS_IDS` | `0` | 只保留哪些 YOLO 检测类别 |
| `DEVICE` | `cpu` | ONNX Runtime 运行设备,支持 `cpu` 或 `cuda`;CUDA 不可用时直接报错,不会静默回退 CPU |
| `UNIFORM_SPECIES_COLOR` | `false` | 是否让所有物种的检测框和标签使用同一种颜色 |
示例:
```bash
DEVICE=cpu TARGET_DET_CLASS_IDS=0 bash run_batch.sh --input /path/to/input
```
指定 GPU 0 运行:
```bash
CUDA_VISIBLE_DEVICES=0 DEVICE=cuda bash run_batch.sh --input /path/to/input
```
使用 CUDA 前必须安装与服务器 CUDA/cuDNN 匹配的 `onnxruntime-gpu`。启动时程序会分别打印 YOLO、ConvNeXt、密度模型的实际 Provider;使用 GPU 时应看到 `CUDAExecutionProvider`。
## 6. 哪些情况才需要改代码
一般调阈值、开关三个模型、切换统一颜色、改模型路径都不需要改代码。
只有下面这些情况通常需要改代码:
- YOLO ONNX 输出格式不是 `[1, num_boxes, 5 + num_classes]` 或 `[num_boxes, 6]`,需要改 `app/inference/yolo_onnx.py`。
- ConvNeXt 训练时没有使用 ImageNet mean/std,需要改 `app/inference/convnext_onnx.py` 的归一化参数。
- 密度估计模型的前处理或输出含义和当前实现不一致,需要改 `app/inference/density_onnx.py`。
- 想改变结果 JSON/XML 字段结构,需要改 `app/batch_runner.py` 或 `app/utils.py`。
## 7. 输出结果
每次运行会生成一个任务目录:
```text
runs/<时间戳>_<输入名>/
├── result/ # 标注后的图片或视频
├── json/ # 结构化结果
├── xml/ # XML 标注结果
└── index.json # 本次批处理汇总
```
图片输出:
- `result/<原文件名>.jpg`
- `json/<原文件名>.json`
- `xml/<原文件名>.xml`
视频输出:
- `result/<原文件名>.mp4`
- `json/<原文件名>.json`
- `xml/<原文件名>.xml`
JSON 中每个目标包含:
```json
{
"bbox_xyxy": [100.0, 120.0, 240.0, 310.0],
"det_confidence": 0.91,
"det_class_id": 0,
"det_class_name": "bird",
"cls_class_id": 12,
"cls_class_name": "绿头鸭",
"cls_confidence": 0.87,
"box_area_ratio": 0.0032,
"is_large_box": true,
"is_dense_scene": false,
"show_cls_name": true
}
```
## 8. Docker 备选运行方式
如果不想在宿主机安装 Python 依赖,可以用 Docker。Docker 只是备选,默认仍然执行同一个 `run_batch.sh`。
构建镜像:
```bash
docker build -t bird-cascade-batch:latest .
```
使用 Compose 处理项目根目录的 `input/`:
```bash
docker compose run --rm bird-cascade-batch
```
临时覆盖参数:
```bash
docker compose run --rm bird-cascade-batch \
--input /app/input \
--output /app/runs \
--sample-interval 5 \
--disable-density
```
`docker-compose.yml` 默认挂载:
```yaml
volumes:
- ./models:/app/models:ro
- ./input:/app/input:ro
- ./runs:/app/runs
```
## 9. 程序结构
```text
app/
├── batch_runner.py # 批处理入口
├── config.py # 环境变量配置
├── pipeline.py # 主级联流程
├── utils.py # 图像、JSON、XML 工具
├── video_pipeline.py # 视频平滑工具
└── inference/
├── yolo_onnx.py # YOLOv5 ONNX 推理和后处理
├── convnext_onnx.py # ConvNeXt ONNX 推理
└── density_onnx.py # 密度估计 ONNX 推理
```
历史文件 `pipeline_raw.py`、`pipeline_add_density.py`、`config_raw.py`、`batch_runner_raw.py` 不参与默认 bash 批处理主流程。