YOLOv9 API封装教程:构建REST接口供外部调用
你有没有遇到过这样的情况:模型训练好了,效果也不错,但别人想用你的检测功能时,还得装环境、跑命令行,甚至要改代码?太麻烦了。如果能像调用天气接口一样,发个图片链接就返回识别结果,那该多好。
这就是我们今天要解决的问题——把 YOLOv9 封装成一个 RESTful API 接口,让任何人都能通过简单的 HTTP 请求来调用目标检测功能。本文将手把手带你从零开始,在官方镜像基础上,用 Python + Flask 搭建一个稳定可用的图像检测服务接口,无需深度学习部署经验也能上手。
1. 准备工作:了解基础环境
在开始封装之前,先确认你使用的镜像是文中提到的YOLOv9 官方版训练与推理镜像。这个镜像已经为你省去了大量配置时间:
- 基于
WongKinYiu/yolov9官方仓库构建 - 预装 PyTorch 1.10.0 + CUDA 12.1 + Python 3.8.5
- 包含 OpenCV、NumPy 等常用库
- 代码位于
/root/yolov9 - 已预下载
yolov9-s.pt权重文件
这意味着我们不需要再处理依赖问题,可以直接进入开发阶段。
1.1 激活环境并测试原始推理
首先确保你处于正确的 Conda 环境中:
conda activate yolov9 cd /root/yolov9运行一次默认推理命令,验证模型是否正常工作:
python detect_dual.py --source './data/images/horses.jpg' --img 640 --device 0 --weights './yolov9-s.pt' --name yolov9_s_640_detect如果成功执行,你会在runs/detect/yolov9_s_640_detect目录下看到带框标注的输出图片。这说明模型可以正常加载和推理,接下来就可以进行 API 封装了。
2. 设计API服务架构
我们要做的不是简单地把命令行包装一下,而是构建一个结构清晰、可扩展的服务。整个流程如下:
- 外部用户发送一张图片(或图片 URL)
- 服务接收请求,保存图片
- 调用 YOLOv9 模型进行目标检测
- 返回 JSON 格式的检测结果(类别、置信度、坐标等)
我们将使用Flask作为 Web 框架,因为它轻量、易上手,非常适合快速搭建原型服务。
2.1 安装必要组件
虽然镜像里已经有大部分依赖,但我们还需要安装 Flask:
pip install flask flask-cors requestsflask:核心 Web 框架flask-cors:解决跨域问题,方便前端调用requests:用于支持从 URL 加载图片
3. 编写核心检测逻辑
为了复用官方代码,我们不重新实现检测逻辑,而是封装detect_dual.py的功能为可调用函数。
3.1 提取检测函数
创建一个新的文件api_detector.py,放在/root/yolov9目录下:
import os import sys from pathlib import Path # 添加 YOLOv9 路径到系统路径 FILE = Path(__file__).resolve() ROOT = FILE.parents[0] # YOLOv9 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) import torch import cv2 import numpy as np from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords from utils.datasets import LoadImages from utils.torch_utils import select_device import json class YOLOv9Detector: def __init__(self, weights='yolov9-s.pt', device='0', img_size=640): self.weights = weights self.device = select_device(device) self.img_size = img_size self.model = None self.names = None self.load_model() def load_model(self): """加载模型权重""" self.model = attempt_load(self.weights, map_location=self.device) self.model.eval() self.names = self.model.module.names if hasattr(self.model, 'module') else self.model.names def detect(self, source_path): """执行检测,返回JSON格式结果""" dataset = LoadImages(source_path, img_size=self.img_size) results = [] for path, img, im0s, vid_cap in dataset: img = torch.from_numpy(img).to(self.device) img = img.float() # uint8 to fp32 img /= 255.0 # 归一化 if img.ndimension() == 3: img = img.unsqueeze(0) # 推理 with torch.no_grad(): pred = self.model(img)[0] pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45) # 解析结果 det = pred[0] if len(det): im0 = im0s.copy() h, w = im0.shape[:2] det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() for *xyxy, conf, cls in reversed(det): label = self.names[int(cls)] confidence = float(conf) box = [int(xyxy[0]), int(xyxy[1]), int(xyxy[2]), int(xyxy[3])] results.append({ "class": label, "confidence": confidence, "bbox": box }) return results这个类做了几件事:
- 封装了模型加载和推理过程
- 使用官方工具链处理图像输入和后处理
- 输出标准 JSON 结构,便于后续传输
4. 构建REST接口服务
现在我们来创建真正的 API 服务。新建app.py文件:
from flask import Flask, request, jsonify, send_from_directory from flask_cors import CORS import os import uuid import requests from urllib.parse import urlparse from api_detector import YOLOv9Detector app = Flask(__name__) CORS(app) # 允许跨域请求 # 配置上传目录 UPLOAD_FOLDER = '/tmp/images' os.makedirs(UPLOAD_FOLDER, exist_ok=True) # 初始化检测器 detector = YOLOv9Detector(weights='./yolov9-s.pt', device='0') def download_image_from_url(url, save_path): """从URL下载图片""" try: headers = {'User-Agent': 'Mozilla/5.0'} response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() with open(save_path, 'wb') as f: f.write(response.content) return True except Exception as e: print(f"下载失败: {e}") return False @app.route('/detect', methods=['POST']) def detect_objects(): # 清理旧文件(防止/tmp堆积) for f in os.listdir(UPLOAD_FOLDER): file_path = os.path.join(UPLOAD_FOLDER, f) try: if os.path.isfile(file_path): os.unlink(file_path) except Exception as e: print(f"删除临时文件失败: {e}") # 获取图片数据 image_file = request.files.get('image') image_url = request.form.get('url') if not image_file and not image_url: return jsonify({"error": "请提供图片文件或URL"}), 400 # 生成唯一文件名 filename = f"{uuid.uuid4().hex}.jpg" filepath = os.path.join(UPLOAD_FOLDER, filename) # 处理图片来源 if image_file: image_file.save(filepath) elif image_url: if not download_image_from_url(image_url, filepath): return jsonify({"error": "无法从指定URL下载图片"}), 400 # 执行检测 try: results = detector.detect(filepath) return jsonify({ "success": True, "results": results, "count": len(results) }) except Exception as e: return jsonify({"error": f"检测过程中出错: {str(e)}"}), 500 @app.route('/health', methods=['GET']) def health_check(): """健康检查接口""" return jsonify({"status": "running", "model": "yolov9-s"}) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=False)4.1 接口说明
| 路由 | 方法 | 功能 |
|---|---|---|
/detect | POST | 接收图片并返回检测结果 |
/health | GET | 健康检查,用于服务状态监控 |
请求示例(上传本地图片):
curl -X POST http://localhost:5000/detect \ -F "image=@./data/images/horses.jpg" \ | python -m json.tool请求示例(传入图片URL):
curl -X POST http://localhost:5000/detect \ -F "url=https://example.com/horses.jpg" \ | python -m json.tool返回示例:
{ "success": true, "results": [ { "class": "horse", "confidence": 0.92, "bbox": [120, 80, 450, 500] }, { "class": "person", "confidence": 0.87, "bbox": [300, 100, 380, 400] } ], "count": 2 }5. 启动与测试服务
5.1 运行API服务
在终端中执行:
cd /root/yolov9 python app.py你会看到类似输出:
* Running on http://0.0.0.0:5000/说明服务已启动,监听所有IP的5000端口。
5.2 测试健康接口
打开浏览器访问:
http://<你的服务器IP>:5000/health应返回:
{"status":"running","model":"yolov9-s"}5.3 发送检测请求
使用 curl 或 Postman 发送 POST 请求测试实际检测能力。
6. 实际应用建议
6.1 性能优化建议
- 批量处理:若需高并发,可考虑使用 Gunicorn + Nginx 部署
- GPU复用:保持模型常驻内存,避免重复加载
- 缓存机制:对相同图片哈希值的结果做短期缓存
6.2 安全性提醒
- 生产环境中不要暴露 Flask 默认服务器
- 建议加身份验证(如 API Key)
- 限制上传文件类型和大小
- 设置请求频率限制
6.3 扩展方向
- 支持更多模型版本(如
yolov9-m.pt,yolov9-c.pt) - 添加图片绘制功能,直接返回带框图
- 集成数据库记录调用日志
- 提供 Swagger 文档界面
7. 总结
7.1 回顾所学内容
本文带你完成了 YOLOv9 模型的完整 API 封装流程:
- 利用官方镜像快速搭建运行环境
- 抽象检测逻辑为可调用类
- 使用 Flask 构建 REST 接口
- 支持文件上传和 URL 两种输入方式
- 返回结构化 JSON 数据
你现在拥有了一个即插即用的目标检测服务,任何前端页面、移动 App 或其他后端系统都可以通过简单的 HTTP 请求调用它。
7.2 下一步建议
- 尝试将其打包为 Docker 镜像,便于迁移部署
- 结合前端页面做一个可视化检测平台
- 接入真实业务场景,比如商品识别、安防监控等
只要模型能跑通,封装成接口其实并不难。关键在于理解“如何把命令行工具变成服务”,这是每一个 AI 工程师都应该掌握的基本技能。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。