从测试转开发三年后,我用 OpenCV + YOLO 搞定了一个“找茬”项目

指针迷路了
2025-12-19 15:17
阅读 1914

大家好,我是阿哲,坐标深圳南山科技园,目前在一家腾讯系公司做后端开发。没错,我就是那个“半路出家”的选手——三年前还是个手动点按钮的 QA,现在天天和 Docker、K8s、Rust(最近新欢)打交道。中间经历了无数个被 P0 Bug 虐哭的夜晚,也终于理解了为什么开发总说“这需求很简单,你怎么测不出来”。

今天想和大家聊聊上个月搞的一个计算机视觉小项目。起因特别接地气:产品经理在双11大促前一周突然跑来,说“用户反馈我们商品主图里经常混进竞品 Logo,能不能自动检测一下?” 我当时心里一万个草泥马奔腾而过——这不就是图像里的“找茬”游戏吗?但嘴上还得说:“OK,我评估下。”

为什么不是直接调百度 AI?

别笑,真有人这么建议。但现实很骨感:

  • 公司对数据隐私要求高,图片不能外传
  • 调外部 API 成本太高(按次收费,双11流量爆炸)
  • 最重要的是——我想自己搞!(顺便为跳槽攒点 CV 亮点)

于是,我决定自己训个模型。目标很明确:识别商品图中是否包含特定竞品 Logo(比如某宝、某东的图标)。数据集?内部爬了 5000 张带 Logo 的图,再合成 5000 张干净图,凑合能用。

选型:YOLOv5 还是 MobileNet?

一开始我想上 YOLOv8,但团队老哥一句话把我拉回现实:“你确定要在 CVM 上跑?我们可没预算开 GPU 实例。” 好吧,现实是:线上服务只能用 CPU。

于是我做了个简单对比(实测 1080P 图片,Intel Xeon 4 核):

模型 mAP@0.5 推理时间 (ms) 模型大小 (MB) 是否支持 ONNX
YOLOv5s 0.89 120 14
MobileNet-SSD 0.76 85 21
EfficientDet-D0 0.82 210 35 ❌(导出麻烦)

最后选了 YOLOv5s ——精度够用,推理速度尚可,关键是 Ultralytics 的 repo 太香了,连训练脚本都给你写好了。而且支持 ONNX 导出,方便后面用 Rust 重写推理服务(别问,问就是 Rust 真香)。

训练:从“Loss 不降”到“召回率爆表”

训练过程简直是一部血泪史。第一天跑完 100 epochs,Loss 卡在 2.5 不动,预测结果全是背景。我一度怀疑人生,直到发现:数据标注格式错了!

YOLO 要求归一化坐标 (x_center, y_center, width, height),但我导出的是 (xmin, ymin, xmax, ymax)。改完后,第二天 Loss 直接干到 0.3,验证集 mAP 冲到 0.85。那一刻,我差点在工位上跳起来(还好隔壁同事戴耳机没看见)。

调参时还踩了个坑:默认 anchor 尺寸不适合我们的 Logo(太小了)。用 kmeans 重新聚类后,小 Logo 的召回率从 60% 提升到 88%。附上关键命令:

# 用官方工具重新计算 anchors
python -m yolov5.utils.autoanchor --weights yolov5s.pt --data logo.yaml --imgsz 640

集成上线:OpenCV + ONNX Runtime 拯救世界

模型训好了,怎么塞进现有服务?我们后端是 Go + Gin,但 CV 推理这种 CPU 密集型任务,我死活不想用 cgo(怕内存泄漏背锅)。于是灵机一动:单独起个 Rust 服务!

先用 PyTorch 导出 ONNX:

model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt')
torch.onnx.export(model, dummy_input, "logo.onnx", opset_version=12)

然后用 Rust 的 tract 库加载 ONNX(比 onnxruntime 更轻量):

use tract_onnx::prelude::*;

let model = onnx()
    .model_for_path("logo.onnx")?
    .into_optimized()?
    .into_runnable()?;

let input = /* 把 OpenCV Mat 转成 NdArray */;
let result = model.run(tvec!(input.into()))?;
// 解析 output[0] 得到 bounding boxes

上线那天,运维大哥看我部署 Rust 服务一脸疑惑:“你们 Go 不香了?” 我只能苦笑:“Go 没有好的 ONNX 推理库啊...”

效果与反思:面试题素材+1!

上线两周,系统自动拦截了 1200+ 张违规图,准确率 92%,误杀率 <3%。最爽的是——再也不用半夜被“Logo 漏检”告警吵醒了!

回头想想,这个项目其实完美覆盖了 CV 工程化的全链路:数据清洗 → 模型选型 → 训练调优 → 推理部署 → 线上监控。上周组内分享时,实习生直接问:“这能当面试题讲吗?” 我笑了:“当然!现在大厂面试官最爱问这种‘端到端落地’的问题。”

比如这些灵魂拷问,我都经历过:

  • “如果 Logo 特别小怎么办?” → 答:多尺度训练 + 自定义 anchor
  • “CPU 推理太慢怎么优化?” → 答:ONNX + TensorRT(可惜我们没 GPU)
  • “误杀怎么处理?” → 答:加一层人工复核队列 + 主动学习回流

给想入坑 CV 的同学几点建议

  1. 别死磕 SOTA 模型:工业界要的是稳定、快、省资源,不是刷榜。YOLOv5 虽然老,但生态成熟,debug 友好。
  2. 数据 > 模型:我们 80% 的时间花在清洗和增强数据上。记得加旋转、模糊、亮度扰动——真实场景哪有干净图?
  3. 部署才是终极考验:训得再好,跑不起来等于零。早点考虑 ONNX、TensorRT、甚至 WebAssembly(前端也能跑!)
  4. 善用开源:Ultralytics、Roboflow、LabelImg 这些工具能省你 90% 的时间。别重复造轮子!

最后自嘲一句:作为前测试,我现在写代码都会多加几行日志——毕竟,谁也不想半夜被自己写的 Bug 叫醒,对吧?

如果你也在深圳搞 CV 或 Rust,欢迎交流!说不定哪天就在科兴科学园楼下咖啡店偶遇,一起吐槽产品经理的新需求 😎

评论 0

最热最新
暂无评论
指针迷路了Lv.1
0
影响力
0
文章
0
粉丝