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

10 KiB
Raw Blame History

Bird Detect Cascade Service:YOLOv5 + ConvNeXt 鸟类级联识别服务

本项目用于将 YOLOv5 目标检测模型 和 ConvNeXt 鸟类细粒度分类模型 级联起来:

  1. 接收图片或视频;
  2. 使用 YOLOv5 检测鸟类目标位置;
  3. 对每个检测框进行目标裁剪;
  4. 将裁剪图送入 ConvNeXt 分类模型;
  5. 返回每个目标的位置、检测置信度、分类类别、分类置信度;
  6. 可选返回画框后的图片或视频。

项目默认使用 ONNX Runtime 推理,适合用 Docker 部署成 HTTP API 服务,方便网站后端调用。


1. 项目结构

bird_detect_cascade_service/
├── app/
│   ├── main.py                  # FastAPI 接口入口
│   ├── config.py                # 配置读取
│   ├── schemas.py               # 返回结构
│   ├── pipeline.py              # YOLO + 裁剪 + ConvNeXt 级联流程
│   ├── utils.py                 # 图像工具函数
│   └── inference/
│       ├── yolo_onnx.py         # YOLOv5 ONNX 推理与后处理
│       └── convnext_onnx.py     # ConvNeXt ONNX 推理
├── models/
│   ├── yolov5.onnx              # 你的 YOLOv5 ONNX 模型,需自行放入
│   ├── convnext.onnx            # 你的 ConvNeXt ONNX 模型,需自行放入
│   ├── det_classes.txt          # YOLO 类别名
│   └── cls_classes.txt          # ConvNeXt 类别名
├── test_client.py               # 本地接口测试脚本
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
└── README.md

2. 模型准备

2.1 YOLOv5 导出 ONNX

如果你的 YOLOv5 是 .pt 权重,一般可在 YOLOv5 项目目录下执行:

python export.py \
  --weights /path/to/best.pt \
  --img 960 960 \
  --batch 1 \
  --device cpu \
  --include onnx \
  --simplify

导出后把 ONNX 文件复制为:

models/yolov5.onnx

2.2 ConvNeXt 导出 ONNX

如果你已有 ConvNeXt 的 .onnx,直接复制为:

models/convnext.onnx

如果你只有 PyTorch 权重,需要用你训练时的模型定义导出,输入通常为:

1 × 3 × 224 × 224

如果你的 ConvNeXt 输入尺寸不是 224,需要修改 .env 或 docker-compose.yml 中的:

CLS_IMG_SIZE=224

3. 类别文件格式

3.1 YOLO 检测类别

models/det_classes.txt

如果 YOLO 只检测鸟,可以写:

bird

如果 YOLO 有多个检测类别,例如:

bird
person
cat
dog

每一行对应一个类别,行号从 0 开始。

3.2 ConvNeXt 分类类别

models/cls_classes.txt

每一行一个鸟类类别,顺序必须和训练时类别索引一致,例如:

Aix_galericulata
Anas_crecca
Anser_cygnoides
Cygnus_columbianus

4. 本地直接运行

安装依赖:

pip install -r requirements.txt

启动服务:

uvicorn app.main:app --host 0.0.0.0 --port 8000

访问接口文档:

http://127.0.0.1:8000/docs

5. Docker 构建与运行

5.1 构建镜像

docker build -t bird-detect-cascade-service:latest .

5.2 启动容器

docker run -d \
  --name bird-detect-cascade-service \
  -p 8000:8000 \
  -v $(pwd)/models:/app/models \
  bird-detect-cascade-service:latest

5.3 使用 docker compose

docker compose up -d --build

查看日志:

docker logs -f bird-detect-cascade-service

停止服务:

docker compose down

6. API 说明

6.1 健康检查

curl http://127.0.0.1:8000/health

返回示例:

{
  "status": "ok",
  "det_model_loaded": true,
  "cls_model_loaded": true
}

6.2 图片识别接口

接口:

POST /predict

参数:

参数 类型 默认值 说明
file file 必填 上传图片
return_image bool false 是否返回画框后的 base64 图片
det_conf float 配置文件默认值 YOLO 检测置信度阈值
iou_thres float 配置文件默认值 NMS 的 IoU 阈值

curl 示例:

curl -X POST "http://127.0.0.1:8000/predict?return_image=true" \
  -F "file=@/path/to/test.jpg"

返回示例:

{
  "success": true,
  "image_width": 1920,
  "image_height": 1080,
  "num_objects": 1,
  "results": [
    {
      "bbox_xyxy": [500.2, 130.7, 820.9, 600.4],
      "det_confidence": 0.91,
      "det_class_id": 0,
      "det_class_name": "bird",
      "cls_class_id": 12,
      "cls_class_name": "Aix_galericulata",
      "cls_confidence": 0.87
    }
  ],
  "annotated_image_base64": "..."
}

7. Python 测试调用

python test_client.py \
  --url http://127.0.0.1:8000/predict \
  --image /path/to/test.jpg \
  --save result.jpg

8. 关键环境变量

这些配置可以在 docker-compose.yml 中修改。

变量 默认值 说明
DET_MODEL_PATH /app/models/yolov5.onnx YOLOv5 ONNX 路径
CLS_MODEL_PATH /app/models/convnext.onnx ConvNeXt ONNX 路径
DET_CLASSES_PATH /app/models/det_classes.txt 检测类别文件
CLS_CLASSES_PATH /app/models/cls_classes.txt 分类类别文件
DET_IMG_SIZE 960 YOLO 输入尺寸
CLS_IMG_SIZE 224 ConvNeXt 输入尺寸
DET_CONF_THRES 0.25 YOLO 默认置信度阈值
DET_IOU_THRES 0.45 NMS 默认 IoU 阈值
CROP_PADDING_RATIO 0.08 裁剪框外扩比例
MAX_DETECTIONS 50 单张图片最多返回目标数
DEVICE cpu onnxruntime 设备,默认 cpu

9. 给网站同事的集成方式

网站后端只需要以 multipart/form-data 方式上传图片到:

POST http://服务器IP:8000/predict

前端或后端拿到 JSON 后,根据 results 字段展示识别结果即可。

如果网站只需要结果,不需要画框图:

return_image=false

如果网站需要展示画框图:

return_image=true

返回的 annotated_image_base64 是 JPEG 的 base64 字符串,前端可拼接为:

const imgSrc = "data:image/jpeg;base64," + annotated_image_base64;

10. 注意事项

  1. YOLO 的输入尺寸必须和导出 ONNX 时一致,例如导出时是 --img 960 960,配置里也建议用 DET_IMG_SIZE=960。
  2. ConvNeXt 的类别文件顺序必须和训练时完全一致。
  3. 如果 YOLO 输出不是标准 YOLOv5 ONNX 格式 [1, num_boxes, 5 + num_classes],需要根据实际输出改 app/inference/yolo_onnx.py。
  4. 如果 ConvNeXt 训练时使用了非 ImageNet 的 mean/std,需要修改 app/inference/convnext_onnx.py 中的归一化参数。
  5. 如果部署机器没有 GPU,默认 CPU 推理即可;如果需要 GPU 版本,需要替换 onnxruntime 为 onnxruntime-gpu,并使用支持 CUDA 的基础镜像。

11. 常见问题

11.1 为什么要用 HTTP API?

因为最终要集成到网站中,HTTP API 是最直接的对接方式。网站后端不需要关心模型细节,只需要上传图片并接收 JSON。

11.2 为什么先检测再分类?

YOLOv5 负责解决“鸟在哪里”,ConvNeXt 负责解决“这只鸟是什么种类”。先裁剪目标区域可以减少背景干扰,更适合细粒度分类。

11.3 多只鸟怎么处理?

YOLO 检测到几个目标,就裁剪几个目标,并分别送入 ConvNeXt 分类,最终返回一个结果列表。

11.4 没检测到鸟怎么办?

返回:

{
  "success": true,
  "num_objects": 0,
  "results": []
}

12. 视频识别接口

当前版本新增视频接口:

POST /predict_video

12.1 后台测试视频上传

启动服务后,在项目根目录执行:

bash backend_test_video.sh /path/to/test.mp4

等价于:

curl -X POST "http://127.0.0.1:8000/predict_video?sample_interval=25&save_annotated_video=true" \
  -F "file=@/path/to/test.mp4"

其中:

  • sample_interval=25 表示每 25 帧处理 1 帧;
  • save_annotated_video=true 表示保存画框后视频;
  • 如果视频很长,可以把 sample_interval 调大,例如 50、100,减少计算量。

12.2 视频运行结果保存位置

如果使用 docker compose up -d --build 启动,docker-compose.yml 已经挂载:

volumes:
  - ./models:/app/models
  - ./runs:/app/runs

所以结果会同时出现在:

容器内:

/app/runs/video_时间_随机ID/

宿主机项目目录下:

./runs/video_时间_随机ID/

每次处理一个视频,会生成一个新的任务目录,例如:

runs/
└── video_20260518_123000_a1b2c3d4/
    ├── source_video.mp4          # 上传的原始视频副本
    ├── annotated.mp4             # 画框后的结果视频
    ├── summary.json              # 本次视频任务摘要
    ├── frame_results.json        # 每个抽帧的详细识别结果
    └── frames/
        ├── frame_00000000.jpg    # 有识别结果的关键帧截图
        ├── frame_00000025.jpg
        └── ...

12.3 返回结果示例

{
  "success": true,
  "task_dir": "/app/runs/video_20260518_123000_a1b2c3d4",
  "source_video": "/app/runs/video_20260518_123000_a1b2c3d4/source_video.mp4",
  "annotated_video": "/app/runs/video_20260518_123000_a1b2c3d4/annotated.mp4",
  "frames_dir": "/app/runs/video_20260518_123000_a1b2c3d4/frames",
  "frame_results_json": "/app/runs/video_20260518_123000_a1b2c3d4/frame_results.json",
  "summary_json": "/app/runs/video_20260518_123000_a1b2c3d4/summary.json",
  "sample_interval": 25,
  "processed_frames": 120,
  "detected_frames": 87,
  "elapsed_sec": 35.6
}

12.4 网站集成建议

网站后端上传视频到:

POST http://服务器IP:8000/predict_video

如果网站需要展示结果,可以让网站后端读取返回的:

annotated_video
frame_results_json
summary_json

正式部署时更推荐把 runs/ 目录映射到网站后端可访问的静态文件目录,或者在本服务里再增加 /files/... 静态下载接口。