Skip to the content.

YOLO-Toys 教学文档

面向个人学习与实战演练的实时目标检测小项目说明


1. 项目简介

YOLO-Toys 是一个基于 FastAPI + Ultralytics YOLOv8 + HuggingFace Transformers + 原生前端 的多模型实时视觉识别 Demo:

本教学文档的目标:


2. 技术栈与关键依赖

建议在阅读本项目代码之前,先对以下概念有大致了解:


3. 快速开始

3.1 本地运行(推荐)

python -m venv .venv
# Linux/macOS
source .venv/bin/activate
# Windows
# .venv\Scripts\activate

pip install -U pip
pip install -r requirements.txt

# (可选)安装开发依赖(用于运行测试/代码规范检查)
pip install -r requirements-dev.txt

# 启动服务
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

浏览器访问:

http://localhost:8000/

3.2 使用 Docker 运行

# 构建镜像
docker build -t vision-det .

# 运行容器
docker run --rm -it -p 8000:8000 \
  -e MODEL_NAME=yolov8n.pt \
  -e CONF_THRESHOLD=0.3 \
  -e IOU_THRESHOLD=0.45 \
  -e DEVICE=cpu \
  vision-det

同样访问 http://localhost:8000/ 即可。

3.3 使用 Docker Compose

docker compose up --build -d
# 关闭
docker compose down --remove-orphans

4. 目录结构与文件说明

项目根目录主要结构如下(简化):

YOLO-Toys/
├─ app/
│  ├─ main.py             # FastAPI 入口 + lifespan 生命周期
│  ├─ config.py           # Pydantic Settings 统一配置
│  ├─ routes.py           # API 路由(REST + WebSocket)
│  ├─ model_manager.py    # 模型管理器(缓存 + Handler 委托)
│  ├─ schemas.py          # Pydantic 响应模型
│  └─ handlers/           # 策略模式处理器
│     ├─ base.py          # BaseHandler 抽象基类
│     ├─ registry.py      # 模型注册表 + 处理器工厂
│     ├─ yolo_handler.py  # YOLO 检测/分割/姿态
│     ├─ hf_handler.py    # DETR / OWL-ViT / Grounding DINO
│     └─ blip_handler.py  # BLIP Caption / VQA
├─ frontend/
│  ├─ index.html          # UI 界面
│  ├─ style.css           # 深色/浅色主题样式
│  ├─ app.js              # 前端入口(ES Module)
│  └─ js/                 # 前端模块 (api, camera, draw)
├─ tests/                 # API + WebSocket + 单元测试
├─ docs/
│  └─ README.md           # 本教学文档
├─ Dockerfile
├─ docker-compose.yml
├─ Makefile
├─ requirements.txt
├─ requirements-dev.txt
├─ pyproject.toml         # Ruff lint + format + pytest 配置
└─ README.md              # 项目简要说明与运行指南

你可以对照源码一起看本教学文档,效果会更好。


5. 后端架构与数据流

5.1 FastAPI 入口:app/main.py

app/main.py 是后端服务的入口,主要职责:

关键端点概览:

这些路由内部统一调用 app.model_manager.model_manager.infer 来执行对应模型的推理逻辑,并返回统一结构的结果。

5.2 推理逻辑:app/model_manager.py

model_manager.py 负责:

你可以在这里尝试:

5.3 后端配置与环境变量

常用环境变量(可通过 .env、docker-compose 或 shell 设置):

建议你自己动手:

  1. 修改 .env.example 中的值,复制为 .env
  2. 使用 make docker-run 读取 .env 并观察行为差异。

6. 前端架构与关键逻辑

前端入口文件为 frontend/index.htmlfrontend/style.cssfrontend/app.js

6.1 布局与控件:index.html

核心结构:

6.2 样式:style.css

可以尝试自行调整:

6.3 核心逻辑:app.js

app.js 是前端的“控制中心”,可以 roughly 按模块理解:

  1. 状态与设置管理
    • 一系列 const xxx = document.getElementById(...) 获取 DOM 节点。
    • loadSettings / saveSettings:把用户在页面上的选择保存在 localStorage 中,实现简单的“记忆上次设置”。
    • applySettings:页面加载时应用上次保存的设置。
  2. 界面交互与主题
    • 设置面板:通过 settingsOverlay 的打开/关闭状态展示详细设置。
    • 侧边栏:支持折叠/展开,在小屏幕下以抽屉方式显示。
    • 主题切换:setTheme 切换 data-theme 并持久化到 localStorage
  3. 摄像头采集与绘制
    • setupCamera
      • 通过 navigator.mediaDevices.getUserMedia 打开摄像头;
      • 把媒体流绑定到隐藏的 <video> 元素;
      • 将 Canvas 的宽高设置为视频宽高。
    • draw
      • 使用 requestAnimationFrame 循环,把视频帧绘制到 Canvas;
      • 在其上叠加当前 detections 的可视化(调用 drawDetections)。
  4. 推理结果渲染drawDetections
    • 对每个检测对象:
      • 根据后端返回的坐标和当前 Canvas 尺寸计算缩放比例;
      • 根据标签哈希映射到固定调色板颜色;
      • 绘制:
        • 掩膜填充(可选)
        • 边框与标签背景矩形
        • 关键点与骨架(在姿态估计任务中)
  5. 通过 HTTP / WebSocket 调用后端
    • sendFrame
      • 按设定的发送宽度(如 320/480/640)把视频帧等比例缩放;
      • 转成 JPEG Blob;
      • 若勾选 WebSocket 且连接可用,则直接 ws.send(blob)
      • 否则使用 HTTP:
        • 构造 FormData 并调用 POST /infer
        • 解包 JSON 并调用 handleResult
    • handleResult
      • 更新 detections / lastInferSize / lastTask 等前端状态;
      • 计算后端耗时与往返时间;
      • 更新 #stats 文本状态栏;
      • 调用 updateSidebar 更新右侧概览。
    • initWS / closeWS
      • 负责建立 WebSocket 连接,将查询参数(conf、iou、max_det、device、model、imgsz、half、text_queries、question)一并附在 URL 上。
  6. 本地图片上传推理:runImageInference

这是在原项目基础上新增的一个扩展功能,方便你从静态图片入手理解整个数据流:

你可以把这个函数当作一个“最小闭环”:

  1. 从本地文件读取 → 2. 发给后端 → 3. YOLO 推理 → 4. 返回 JSON → 5. 在前端画出来。

  2. 检测概览与类别计数:updateSidebar

这是一个典型的“前端侧数据聚合 + 展示”例子,也非常适合你继续做更多可视化练习。


7. API 返回结构与数据模型

后端使用 Pydantic 模型 InferenceResponse 约束 /infer 等接口的返回结构:

在前端的 handleResult / runImageInference 中,你可以找到如何消费这些字段的示例。


8. 学习路线与扩展练习建议

如果你是以本项目作为“个人学习 + 功能扩展”的练习场,下面是一个推荐路线:

8.1 已完成的两个基础 Step

  1. 本地图片上传推理(Step 1)
    • 目标:从单张图片贯通前后端推理流程。
    • 对应代码:前端 runImageInference 及相关控件。
  2. 检测侧边栏 + 各类别计数(Step 2)
    • 目标:在前端基于返回 JSON 做数据聚合与结构化展示。
    • 对应代码:updateSidebar 与侧边栏 DOM 结构/CSS。

8.2 推荐的后续扩展 Step

你可以继续按难度递增做下面几件事:

  1. 本地视频文件推理
    • <input type="file" accept="video/*"> 选择本地视频;
    • 使用 URL.createObjectURL 在新的 <video> 上播放;
    • 按设定 FPS 从视频中截帧,复用现有 sendFrame 流程推理与绘制。
  2. 折线图 / 柱状图可视化
    • 维护一个最近 N 帧的历史数组(检测数量、耗时等);
    • 使用 Canvas 或简单图表库画:
      • FPS/延迟随时间变化的曲线;
      • 各类别出现频次的柱状统计图。
  3. 目标轨迹与热力图
    • 用最近几帧的 bbox 中心做最近邻匹配,给目标一个“临时 ID”;
    • 在画面上绘制轨迹线;
    • 累积中心点位置,渲染成热力图效果。
  4. RTSP / 网络视频流支持(进阶)
    • 在后端使用 cv2.VideoCapture(rtsp_url) 打开远程摄像头;
    • 在后台任务中持续读取帧并推理;
    • 通过 WebSocket/MJPEG 把结果推给前端。

每个 Step 完成后,都建议你:


9. 如何配合本仓库的工程工具

项目已经内置了一些工程化工具,建议你在改动后经常跑:

在首次运行 make lint / make test 之前,建议先执行一次 make dev(安装 requirements-dev.txt,包含 pytest / pre-commit 等)。

如果你增加了新的 Python 模块或测试:


10. 总结

YOLO-Toys 适合作为你学习以下内容的练习项目:

建议你一边阅读源码,一边在 docs/ 下不断添加属于你自己的学习笔记与扩展说明,让这个项目真正成为你的“YOLO 玩具实验场”。