# 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 批处理主流程。