项目地址:
yolo-object-detection-lab:基于 FastAPI 与 Ultralytics YOLO 的图像目标检测实验项目 - AtomGit
前面几篇文章里,我一直围绕 MNIST 做图像分类实验,从 CNN、Feature Map、CNN vs MLP,一直做到 ResNet + Grad-CAM。
但图像分类解决的问题始终是:
“这张图片是什么?”
这一次我想继续往前走一步,开始做目标检测。
目标检测不仅需要判断图片里有什么,还需要回答:
“目标在哪里?”
所以这次我继续使用码道 Agent,从零搭建了一个基于Ultralytics YOLO + FastAPI的目标检测 Web 实验平台。
最终效果可以直接上传图片,并得到:
- 检测类别
- 置信度
- Bounding Box
- 检测目标数量
- 检测结果图
- 每个目标的详细检测信息
一、从 Image Classification 到 Object Detection
前面的 CNN、ResNet 都属于图像分类任务。
比如输入一张手写数字:
Input Image ↓ CNN / ResNet ↓ Class = 8模型只需要告诉我们:
这张图是什么?
但 YOLO 做的是 Object Detection。
它的输出更像:
Input Image ↓ YOLO ↓ Dog 93.2% [x1, y1, x2, y2] Person 80.4% [x1, y1, x2, y2] Backpack 83.9% [x1, y1, x2, y2] ...不仅知道是什么,还能给出目标的位置。
因此这次我单独创建了一个新项目:
yolo-object-detection-lab而没有继续往之前的 MNIST 项目里塞功能。
二、项目整体结构
这次后端使用:
Python FastAPI Ultralytics YOLO OpenCV Pillow前端仍然保持比较轻量:
HTML CSS JavaScript检测流程大致是:
用户上传图片 ↓ FastAPI ↓ 图片解析与校验 ↓ YOLO11 ↓ 目标检测 ↓ 解析 Bounding Box ↓ 绘制检测框 ↓ 返回 Base64 图片 + Detection List ↓ 浏览器可视化前端本身不生成任何假框。
页面中看到的类别、置信度和 Bounding Box 全部来自后端真实 YOLO 推理结果。
三、使用 YOLO11n
这次使用的模型是:
yolo11n.pt其中n对应 Nano 版本。
对于一个目标检测实验平台来说,它体积比较小,推理速度也比较快,很适合先把完整流程跑通。
本地环境中使用:
PyTorch 2.14.0+cu130 Ultralytics 8.4.165 NVIDIA GeForce RTX 4090 CUDA Available = True一开始启动项目以后,我发现页面中的模型信息显示:
Device: cpu也就是说,虽然机器有 RTX 4090,但项目默认实际上还在使用 CPU。
于是启动服务时指定:
YOLO_DEVICE=0 python -m uvicorn app.main:app --reload再次查看模型状态:
{ "model_name": "yolo11n.pt", "device": "0", "model_loaded": true, "class_count": 80 }这时才真正切换到 GPU。
四、先做真实测试,而不是直接相信页面
Agent 完成项目以后,我首先运行了完整 pytest:
pytest -v最终结果:
34 passed, 1 warning in 0.91s34 个测试覆盖了:
- API 状态
- 模型信息
- 无文件上传
- 空文件
- 非图片
- 损坏图片
- 文件过大
- 权重缺失
- 推理异常
- Bounding Box 格式
- Confidence 范围
- Detection Schema
- 图片绘制
- Base64 编码
不过这里需要注意:
部分 YOLO 推理测试使用的是 Mock。
所以 pytest 全通过以后,我又单独进行了真实模型推理。
直接加载:
model = YOLO("yolo11n.pt")然后指定:
device=0真实推理中,模型本身的 inference 时间大约只有:
9.7 ms说明 CUDA 和 YOLO 模型都已经正常工作。
五、真实多目标检测效果
为了测试多目标场景,我准备了一张同时包含多种常见物体的测试图片。
图片中包含:
- 人
- 狗
- 背包
- 植物
- 笔记本电脑
- 杯子
- 椅子
- 床 / 沙发区域
- 书籍等目标
上传以后点击:
Start DetectionYOLO 最终检测到了:
16 个目标
图片尺寸为:
1634 × 962这次检测结果中比较明显的几个目标包括:
| Class | Confidence |
|---|---|
| Dog | 93.2% |
| Potted Plant | 86.5% |
| Backpack | 83.9% |
| Person | 80.4% |
比如 Dog 对应的检测结果:
Class: Dog Confidence: 93.2% BBox: [182, 410, 642, 934]Backpack:
Class: Backpack Confidence: 83.9% BBox: [1205, 584, 1584, 962]Person:
Class: Person Confidence: 80.4% BBox: [726, 47, 1175, 924]也就是说,现在平台已经不再只是输出一个类别,而是能够真正返回:
Class + Confidence + Bounding Box六、Bounding Box 到底是什么?
目标检测里的 Bounding Box 本质上就是一个矩形框。
当前接口返回:
x1 y1 x2 y2分别表示:
(x1, y1) 左上角 (x2, y2) 右下角例如:
BBox: [182, 410, 642, 934]可以理解为:
左上角 = (182, 410) 右下角 = (642, 934)然后 OpenCV 根据这些坐标在原始图片上绘制矩形。
因此最终页面中看到的框,并不是前端根据图片尺寸“猜”的,而是 YOLO 模型真实预测出来的位置。
七、这次还遇到了一个很有意思的前端 Bug
第一次真实上传图片以后,页面出现了一个现象:
YOLO 一直在转圈。
页面始终停留在:
Running YOLO inference...一开始我还以为是:
YOLO 太慢 GPU 没工作 模型加载卡住但继续排查以后发现,后端其实完全正常。
我直接绕开网页调用:
curl -F "file=@/tmp/yolo_test.jpg" \ http://127.0.0.1:8000/api/detect结果大约 4 秒就正常返回:
image: 640 x 640 detection_count: 0 detections: [] result_image exists: True这就说明:
YOLO 后端早就跑完了,只是前端 Loading 没消失。
最后定位到了 CSS。
JavaScript 中实际上已经正确执行:
function hideOverlay() { dom.overlay.hidden = true; }而且finally也会执行:
finally { hideOverlay(); busy = false; dom.detectBtn.disabled = false; }真正的问题是.overlay的 CSS 显示规则覆盖了 HTML 的hidden属性。
最终只需要补充:
[hidden] { display: none !important; }问题就解决了。
这个 Bug 其实挺典型:
后端没有卡,模型没有卡,真正卡住的是 UI 状态。
八、现在这个平台已经实现了什么?
目前项目已经能够完成:
图片上传 Drag & Drop 原图预览 YOLO11 模型加载 GPU 推理 Confidence Threshold IoU Threshold 多目标检测 类别识别 置信度显示 Bounding Box 绘制 检测数量统计 图片尺寸统计 Detection List 异常处理 FastAPI API pytest 测试模型信息也能直接显示:
Model: yolo11n.pt Device: 0 Confidence: 0.25 IoU: 0.70 Loaded: yes Classes: 80对于一个从零开始搭建的 YOLO 实验平台来说,第一阶段的基本功能已经完整跑通。
九、从 CNN 到 YOLO,任务发生了什么变化?
做到这里以后,之前几篇文章的路线就比较清晰了。
最开始:
CNN ↓ 这张图片是什么?然后:
Feature Map ↓ 卷积层提取了什么?再到:
ResNet + Grad-CAM ↓ 当前类别主要响应在哪里?而现在进入:
YOLO ↓ 图片里有什么? 它们分别在哪里?这实际上就是从:
Image Classification
正式进入:
Object Detection
总结
这一次我使用码道 Agent 从零完成了一个 YOLO Object Detection Lab。
最终真实运行结果包括:
Model: YOLO11n GPU: RTX 4090 Classes: 80 pytest: 34 passed Multi-object Test: 16 detected objects Dog: 93.2% Potted Plant: 86.5% Backpack: 83.9% Person: 80.4%同时开发过程中还真实遇到了:
CPU / GPU 配置问题 ↓ 真实 YOLO 推理验证 ↓ API 独立测试 ↓ Loading 一直不消失 ↓ 定位 hidden CSS 问题 ↓ 完成修复所以这一篇对我来说也不只是“调用了一次 YOLO”。
而是把:
模型 → 后端 → API → 前端 → 测试 → GPU → 可视化
整个目标检测流程真正串起来了。
项目地址:
yolo-object-detection-lab:基于 FastAPI 与 Ultralytics YOLO 的图像目标检测实验项目 - AtomGit
下一步可以继续在这个项目上加入:
Confidence / Class Filter、摄像头实时检测、视频检测以及自定义数据集训练。