计算机视觉实战:从需求到落地的全过程复盘
去年上半年,我在一家工业质检公司负责一个计算机视觉项目的开发。项目目标是用机器视觉替代人工检测某种电子元器件的外观缺陷。这个听起来并不复杂的任务,在实际推进过程中却遇到了各种“意想不到”的挑战。
作为项目的主力开发人员,我全程参与了需求调研、方案设计、模型训练、系统集成和最终部署上线。过程中踩了不少坑,也收获颇丰。今天我就结合自己的真实经历,聊聊我是如何从零搭建这样一个CV质检系统的。
项目背景:为什么选择计算机视觉?

我们服务的客户是一家生产精密电子连接器的企业,产品广泛用于汽车、消费电子等高端领域,因此对产品质量要求极为严苛。以前他们采用人工抽检的方式,每人每小时要检查上千个零件,不仅效率低下,还容易出现漏检或误检。
老板希望借助AI技术,打造一套自动化的质检系统。这对我们来说是一个典型的工业质检场景,非常适合使用计算机视觉技术来解决。而且随着深度学习的发展,相关技术和开源工具也越来越成熟。
面临的问题与挑战

1. 数据问题:样本太小、标签质量参差不齐
刚开始拿到的数据集不到500张图片,其中正负样本比例严重失衡(正常样本居多)。更头疼的是,客户并没有专业的标注团队,很多缺陷样本的边界都不清楚。
我们尝试让现场员工手动标注,但效果非常差——画的框有时候会包含多个对象,甚至把缺陷区域标错位置。这个问题一度导致模型训练几乎无效。
2. 环境干扰大:光照变化和角度偏移影响识别
在实际产线环境中,由于车间照明条件不稳定,加上零件摆放的角度会有微小差异,图像质量波动很大。有时同一个正常样品拍出来会呈现出不同的颜色分布,这对模型判断造成很大干扰。
我们在实验室里训练出的高精度模型,一到现场就“水土不服”,准确率骤降。
3. 实时性要求高:单帧处理时间必须控制在50ms以内
客户提出整个质检流程需要控制在800ms以内完成,而整个流程中还包括机械臂抓取、传送带停止等动作,留给图像处理的时间非常紧张。
一开始我们使用的YOLOv5在GPU上勉强达标,但当我们要把它迁移到边缘设备(Jetson AGX Xavier)上时,延迟明显超标。
解决思路和技术选型

1. 数据增强 + 小样本学习
面对样本不足的问题,我们采用了一系列策略:
- 使用Albumentations做数据增强(如旋转、裁剪、亮度调整等)
- 引入Mixup/CutMix提升泛化能力
- 使用预训练模型 + 迁移学习
- 构建少量高质量标注集供关键训练阶段使用
为了提高标注质量,我还自己写了一个简易的标注校验工具,用来检测框的位置是否合理,并提示标注员修改。
2. 模型轻量化 + 推理优化
为了满足实时性要求,我们尝试了多种模型架构:
| 模型 | 在Jetson上的FPS | 内存占用 | 准确率 |
|---|---|---|---|
| YOLOv5s | 18 | 6.3GB | 94.2% |
| EfficientDet-Lite4 | 22 | 4.1GB | 92.7% |
| PP-YOLO Tiny | 26 | 3.8GB | 91.5% |
最后我们选择了PP-YOLO Tiny作为主干网络,并进行了以下优化:
- ONNX转TensorRT加速推理
- 使用FP16精度
- 并行执行非依赖操作(如图像预处理和模型推理)
此外,我们还在前端增加了缓存机制,减少重复计算。
3. 多模态融合 + 知识蒸馏
为了解决环境干扰带来的问题,我们引入了双摄像头系统(RGB + IR),并设计了一个简单的融合模块。同时我们还尝试了知识蒸馏的方法,用ResNet-101作为教师模型,指导学生模型学习更鲁棒的特征表达。
关键代码实现

下面是一段我写的图像预处理和模型推理核心代码:
import cv2
import numpy as np
import tensorrt as trt
from cuda import cudart
class TRTInfer:
def __init__(self, engine_file):
self.engine = self.load_engine(engine_file)
self.context = self.engine.create_execution_context()
self.buffers = self.allocate_buffers()
def load_engine(self, engine_file):
with open(engine_file, 'rb') as f, trt.Runtime(trt.Logger(trt.Logger.WARNING)) as runtime:
return runtime.deserialize_cuda_engine(f.read())
def allocate_buffers(self):
inputs = []
outputs = []
bindings = []
stream = cudart.cudaStreamCreate()[1]
for binding in self.engine:
size = trt.volume(self.engine.get_binding_shape(binding)) * self.batch_size
dtype = trt.nptype(self.engine.get_binding_dtype(binding))
# Allocate host and device buffers
host_mem = cuda.pagelocked_empty(size, dtype)
device_mem = cuda.mem_alloc(host_mem.nbytes)
bindings.append(int(device_mem))
if self.engine.binding_is_input(binding):
inputs.append({'host': host_mem, 'device': device_mem})
else:
outputs.append({'host': host_mem, 'device': device_mem})
return {'inputs': inputs, 'outputs': outputs, 'bindings': bindings, 'stream': stream}
def preprocess(self, img):
img = cv2.resize(img, (320, 320))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = img.astype(np.float32) / 255.0
img = np.transpose(img, (2, 0, 1)) # HWC -> CHW
return img

def predict(self, image_batch):
# Copy input data to GPU
np.copyto(self.buffers['inputs'][0]['host'], image_batch.ravel())
cuda.memcpy_htod_async(self.buffers['inputs'][0]['device'],
self.buffers['inputs'][0]['host'],
self.buffers['stream'])
# Execute model
self.context.execute_async_v2(bindings=self.buffers['bindings'],
stream_handle=self.buffers['stream'])
# Copy results back
cuda.memcpy_dtoh_async(self.buffers['outputs'][0]['host'],
self.buffers['outputs'][0]['device'],
self.buffers['stream'])
cuda.stream_synchronize(self.buffers['stream'])
return self.buffers['outputs'][0]['host']
这段代码实现了:
- 基于TensorRT的高效推理引擎
- 图像预处理管道(尺寸统一、归一化、格式转换)
- CUDA异步执行以隐藏IO延迟
踩过的那些坑

1. 标注工具引发的性能瓶颈
最开始我们想省事,直接用LabelImg做标注。结果某天晚上跑完训练后,我发现loss始终下不去,检查数据发现有很多bbox坐标越界或者标注错误。
后来我自己封装了一层验证逻辑,每次保存前都会检查框的位置是否合法,才缓解了这个问题。
小插曲:有次我偷偷在标注工具里加了个弹窗提醒:"您当前标注可能存在不合理,请复查",结果被测试同事吐槽说像在骂人😂
2. Jetson上的CUDA版本冲突
当我们把模型部署到Jetson AGX Xavier时,发现TensorRT无法初始化,报错显示CUDA Driver version too low。折腾了很久才发现,虽然NVIDIA官网说是支持的,但实际上我们需要重新刷一遍系统固件才能兼容新版驱动。
建议:Jetson平台最好一开始就按照官方推荐方式配置环境,避免后期反复折腾。
3. 光照突变导致误检飙升
有一天下班前一切都OK,第二天早上过来发现误检率突然暴增。经排查发现,夜间维护人员关掉了部分照明灯,导致图像整体偏暗。
我们临时加了一个自适应直方图均衡算法做预处理,后续又改成了基于GAN的光照不变形图像增强方法。
实际效果与收益
经过两个多月的攻坚,最终我们成功将系统部署到了两条生产线。效果如下:
| 指标 | 人工 | CV系统 |
|---|---|---|
| 检测速度(个/秒) | ~3 | 12 |
| 漏检率 | 1.2% | 0.4% |
| 误检率 | 0.8% | 0.3% |
| 单工位人力成本 | ¥8500/月 | ¥0(仅设备折旧) |
更让人欣慰的是,系统还能记录每一次检测的结果,并生成可视化报告,帮助工厂进行质量分析。客户反馈,自从上了这套系统之后,产品的客诉率下降了40%。
我的经验总结
如果你也在做类似的CV项目,这些是我总结下来的宝贵经验:
✅ 技术层面
- 数据比模型重要:哪怕是最先进的模型,遇到烂数据也会崩溃。花点时间做数据清洗和增强,绝对值得。
- 重视预处理:很多时候不是你模型不行,而是输入质量太差。做好图像增强、去噪、归一化,往往能大幅提升效果。
- 边缘设备要提前验证:不要等到最后再想着怎么移植,不同硬件平台的支持库、性能差异很大,尽早搭起原型环境试起来。
🧠 工程实践
- 保持快速迭代的习惯:先跑通pipeline再说,别一上来就追求完美。比如我们一开始就先做个简单的分类+模板匹配组合,快速做出MVP。
- 监控一定要做全:不只是看准确率,还要关注推理耗时、内存占用、掉帧情况。上线后你会发现这些指标比训练时更重要。
- 预留容错机制:哪怕准确率达到99%,也不能完全取代人工。可以设置一个置信度阈值,低于该值则触发人工复核。
💬 和客户沟通
- 管理好预期:有些客户看到demo很好,以为就能完美替代人类。实际上AI只是辅助手段,特别是在初期阶段。
- 理解业务流程:不能只站在技术角度看问题,还要深入现场了解整个质检环节是怎么走的,这样才能真正解决问题。
结语:AI赋能制造,不止于算法本身
做这个项目最大的感悟就是:计算机视觉并不是万能钥匙,它只是工具的一部分。要真正解决问题,不仅要懂算法,更要懂工程、懂业务、懂产品。
有一次调试的时候,一位老工人问我:“这台机器是不是比我看得准?”我当时其实挺犹豫的,后来回答他说:“你经验丰富,它速度快。你们要是合作起来,那才叫厉害。”
现在想来,这就是技术落地的最佳状态吧——不是取代人,而是赋能人。这也是我们每一个开发者应该努力的方向。

评论 0