从零到上线:一次真实的计算机视觉实战项目经验分享
引言:为什么我要写这篇技术文章?

去年,我所在的公司接了一个图像识别的外包项目,目标是开发一套基于摄像头的“物品分类识别系统”,用于零售行业的智能货架管理。听起来不复杂吧?然而,随着项目的推进,我们才发现,真正的问题远不止模型准确率那么简单。
作为一个团队的技术负责人,我全程参与了这个项目的研发、调试与交付过程。过程中我们踩了不少坑,也收获了宝贵的经验。今天就结合这个真实项目,和大家分享一下我在计算机视觉实战中的一些思考与实践心得。
项目背景与需求分析

项目来源与业务场景
客户是某大型连锁超市集团,他们的核心诉求是希望通过安装摄像头+边缘计算设备,实现对货架上商品的实时识别与统计。最终目的是:
- 实时监控货品库存状态
- 提前预警缺货或摆错位的商品
- 分析销售趋势与补货策略
简单来说,这个系统要做的就是:“摄像头拍一张图 → 自动识别出画面中有哪些商品 → 统计数量和类别”。
乍一看,就是一个标准的目标检测任务嘛?其实不然。等后面详细讲挑战的时候,你就会明白为啥这个事情没想象中容易。
初步调研与方案设计
为了满足客户的需求,我们首先需要明确几个关键点:
- 识别精度要求:至少达到85%以上的召回率,支持50种常见商品识别。
- 部署平台限制:希望在边缘端部署(即在本地NVIDIA Jetson系列设备运行),而不是全部依赖云端。
- 响应时间要求:单帧处理时间控制在200ms以内,以保证视频流的流畅性。
- 训练数据问题:客户能提供一部分商品照片,但远远达不到深度学习的要求,需要我们自己补充。
综合这些因素,我们决定采用以下技术栈:
- 模型架构:YOLOv5 + 数据增强 + 迁移学习
- 部署框架:TensorRT + ONNX + OpenCV + GStreamer
- 硬件平台:Jetson AGX Xavier NX
- 模型训练环境:PyTorch + AWS GPU实例集群
这便是整个项目的基本技术框架,接下来才是真正的“战斗”开始。
遇到的实际挑战

1. 数据不足且质量参差不齐
虽然客户提供了部分商品图片,但问题很多:
- 图片角度单一,基本都是正视图,缺少不同光照、倾斜角度下的样本;
- 商品摆放密集,存在遮挡和重叠现象;
- 背景多样,包含各种货架布局、灯光反射、人员走动等情况。
为了解决这个问题,我们必须想办法扩充数据集,否则模型根本无法泛化。
2. 多品类识别下模型表现不理想
我们一开始用的是预训练的COCO权重做微调,结果发现对于某些相似商品(比如同品牌不同口味饮料)识别率极低,甚至出现大量混淆。
举个例子,可口可乐的经典款 vs 可口可乐香草味,在模型眼里可能就是两个几乎一样的矩形框,靠颜色或Logo细节来判断,但在模糊或光线不佳的情况下很容易出错。
3. 部署阶段的性能瓶颈
我们在本地模拟部署时发现,尽管YOLOv5在PC端跑得飞快,但在Jetson上却卡顿严重。主要原因包括:
- Jetson算力有限(FP32性能只有桌面显卡的1/10左右)
- OpenCV读取视频流的方式效率不高
- 内存带宽限制导致模型推理速度不稳定
于是我们不得不从模型压缩、流水线优化等多个层面下手。
4. 客户验收时提出的新需求
最头疼的不是技术难题,而是——客户改需求。就在准备上线前夕,他们临时提出:不仅要识别商品种类,还要能统计数量!
这就意味着模型不仅要定位识别物体,还得具备一定的“计数逻辑”。如果只是简单的重叠过滤还行,但如果多个同类商品堆在一起,模型会输出多个小框还是合并成一个大框?这直接影响后续后处理模块的设计。
我们的解决方案与实现思路
一、数据扩充与清洗策略
面对数据匮乏,我们采取了多管齐下的方式:
(1)主动采集数据
我们带着相机去附近的超市拍摄商品图,覆盖不同角度、光照和摆放方式。总共采集约5000张图,涵盖47个品类。
(2)使用LabelImg标注工具
手动标注每一帧图像中的商品位置,并建立统一标签体系,确保模型输入格式一致。
(3)应用数据增强技术
利用 Albumentations 对已有数据进行增强,主要包括:
transform = A.Compose([
A.RandomBrightnessContrast(p=0.3),
A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.1, rotate_limit=15, p=0.5),
A.HueSaturationValue(p=0.3),
A.HorizontalFlip(p=0.5),
A.CoarseDropout(max_holes=5, max_height=20, max_width=20, p=0.5)
], bbox_params=A.BboxParams(format='yolo'))
这套增强策略显著提升了模型在实际环境中对复杂背景的适应能力。
(4)生成合成数据(尝试失败)
我们还尝试过用Blender+Python脚本自动生成商品图,但由于贴图渲染效果太假,反而影响模型训练,后来放弃了。
二、模型训练与调优
模型选型与结构优化
我们最初用的是YOLOv5m版本,但因为部署硬件限制,最终换成了YOLOv5s轻量版。虽然参数少了一半,但通过数据增强和迁移学习弥补了性能差距。
此外,我们还在Head层做了小改动,将原本的分类头扩展为“商品+类别”的组合,提高细粒度识别能力。
训练过程中的技巧
类别不平衡处理: 使用
ClassWeight机制给稀有类加权,缓解训练过程中的偏差。冻结Backbone微调策略: 前10轮冻结特征提取层,仅训练最后三层输出层;后期再放开所有层进行微调。
学习率调度器调整: 采用
CosineAnnealingLR搭配Warmup机制,让模型在初期快速收敛。IoU阈值调整: 将默认的IoU=0.45提高到0.6,提升定位准确性。
验证指标的选择
除了常规的mAP之外,我们特别关注:
- Recall@top5:尤其针对外观相似商品,提升其召回率;
- Confusion Matrix:分析误分类情况,辅助后期数据筛选;
- FPS in Inference:在部署机器上持续监控,确保达标。
三、模型部署与性能优化
ONNX + TensorRT 加速推理
为了让YOLOv5在Jetson上跑得更快,我们将其转换为ONNX格式,并使用TensorRT进行加速。具体步骤如下:
# 导出ONNX模型
python export.py --weights best.pt --img 640 --batch 1
# 使用trtexec工具转为TensorRT引擎
trtexec \
--onnx=yolov5s.onnx \
--saveEngine=yolov5s.engine \
--fp16 \
--workspace=1024 \
--minShapes=input:1x3x640x640 \
--optShapes=input:4x3x640x640 \
--maxShapes=input:8x3x640x640
这样就能在Jetson上用TensorRT加载模型并进行高效推理。
视频流处理优化
原始OpenCV读取方法效率较低,我们改为GStreamer管道:
video_path = "rtspsrc location=rtsp://user:password@ip:554/stream latency=200 ! decodebin ! videoconvert ! appsink"
cap = cv2.VideoCapture(video_path, cv2.CAP_GSTREAMER)
这种方式有效降低了视频解码延迟,配合双缓冲异步推理机制,使帧率稳定在每秒12~15帧之间。
四、后处理逻辑设计
由于客户临时增加“计数”需求,我们在后处理环节引入了以下逻辑:
- 同一类别的包围框聚类(DBSCAN or NMS加强版)
- 面积+长宽比辅助过滤小框误检
- 移动平均滤波消除抖动带来的重复识别
这部分代码虽小,但影响巨大,极大提升了用户使用体验。
开发中的坑与填坑经验
坑1:边缘设备上的内存溢出
第一次部署时,Jetson频繁崩溃,报内存错误。排查发现是因为每次推理都申请新内存,没有释放缓存。解决办法是:
- 手动管理Tensor内存分配;
- 在主循环外预加载模型和固定尺寸buffer;
- 设置GPU内存占用上限。
坑2:ONNX导出失败
导出YOLOv5时提示“Unimplemented ONNX opset version”,这是因为PyTorch导出默认opset_version=9,而我们需要>=12才能兼容TensorRT。所以加上参数:
--dynamic --opset 13
重新导出即可。
坑3:数据泄露导致评估失真
训练集和验证集中包含了部分重复图像(同一个SKU的不同角度),导致评估准确率虚高。最终通过人工复查并拆分数据集才得以修复。
坑4:模型漂移 & 概念漂移问题
部署几个月后,客户反馈某些商品识别率下降。原因是新的商品包装上市了,而模型没更新。为此我们设计了一个定期增量训练流程,每周自动抓取新数据加入训练队列。
最终效果与上线收益
项目上线后,整体达到了预期目标:
| 指标 | 目标值 | 实际表现 |
|---|---|---|
| 推理延迟 | ≤200ms | 平均140ms |
| mAP @0.5 | ≥85% | 87.6% |
| 商品识别总数 | 50类 | 支持52类 |
| 识别准确率 | ≥90% | 91.2% |
| 日均识别次数 | - | 约80万次 |
不仅帮助客户实现了智能补货提醒,还能通过后台分析商品摆放规律,优化货架陈列策略。客户后来反馈,试点门店的人工巡架时间减少了60%,库存异常识别效率大幅提升。
我的一些建议与注意事项
作为一线开发者,我想对正在或将要从事计算机视觉项目的同学说几点真心话:
1. 不要迷信SOTA模型
很多同学一上来就想用最新的DETR或者YOLOv8。但实际上,工程落地要考虑太多因素,比如部署平台、推理速度、维护成本。有时候,“够用就好”。
2. 重视数据而非一味调模型
很多时候模型不行,其实是数据有问题。与其花一周调超参,不如多花两天收集/清洗数据。
3. 早点考虑部署场景
模型训练阶段就要确定部署平台和语言栈。不要等模型训练完了,才说“哎呀Jetson上跑不动啊”,那就晚了。
4. 多关注客户的真实意图
客户说“识别商品”,不一定真的只需要识别。背后可能藏着更深层次的需求,比如数据分析、可视化展示等。早沟通,别闷头干完才发现南辕北辙。
5. 技术文档要养成习惯写
哪怕只是记录日志、保存checkpoint路径、模型参数说明也好。半年后再回头看,你会发现“那个模型到底是怎么调的?”根本记不清细节。
6. 学会写测试代码
不管是单元测试、接口测试还是模型鲁棒性测试,都是非常有用的。尤其是在模型更新、部署变更时,能帮你快速定位问题。
结语:一场视觉之旅的结束,也是新旅程的开始
说实话,这段项目经历并不轻松,但也让我成长了很多。从最开始的数据焦虑,到后来的模型自信,再到部署时的手忙脚乱,每一个节点都是一次洗礼。
计算机视觉的魅力在于它连接了虚拟与现实世界,但它真正的难点往往不在算法本身,而在于如何把它变成产品,服务用户。希望这篇来自实战的文章能对你有所帮助,哪怕只是一点启发。
如果你也有类似的经历,欢迎一起交流。毕竟,工程师的成长,从来都不是孤独地奔跑。
文末注:本文中提到的代码片段和配置仅为示意,实际部署请根据环境自行调整。欢迎留言讨论,我会尽量回答大家的问题!

评论 0