先说一下这个项目是怎么来的。某工厂的安全员找过我,说每天人工翻监控查工人有没有戴手套,实在太折磨人——几路视频同时挂在那里,盯到眼花也不一定能发现违规,而且事后追溯还要手动截取片段,效率低得离谱。我就用YOLOv8帮他做了一套安全手套佩戴识别检测系统,摄像头对着操作工位,画面里一旦出现未佩戴手套的情况,系统自动记录并弹出警示,这套流程跑起来之后,人工巡检的压力一下子就小了很多。
这套项目覆盖了完整的落地链路:YOLOv8深度学习模型、自建的YOLO格式数据集、图形化UI界面、Python工程源码以及训练好的模型权重。如果你是做工业安全、智能制造或者是算法岗的同学,拿它来学习目标检测从数据到部署的全流程非常合适;如果厂区本来就有监控系统,也可以直接把它作为PPE(个人防护装备)检测中的一个子模块嵌进去用。下面我把这个项目从需求分析、数据准备、模型训练,到UI界面开发和部署排查的完整过程拆开讲,所有经验和踩坑记录都会写出来。
1. 项目整体拆解:安全手套检测到底在解决什么问题
1.1 场景痛点与需求分析
先分析一下这个项目产生的真实背景。很多制造车间里,手部伤害事故常年排在工伤事故的前几位,搬运、装配、机加工等工位都要求工人佩戴防护手套。但一线工人嫌手套碍事、闷热,经常偷偷摘掉,这就给安全管理带来了一个巨大的矛盾:管理者不可能派专人一对一盯守,而传统的事后视频抽查又存在严重的滞后性。
这个项目的核心需求,本质上是把“事后追溯”变成“实时预警”加“证据留存”。系统不需要理解工人为什么没戴手套,只需要输出两个结果:画面里的手部区域在哪,以及这只手有没有戴手套。前者是目标检测任务,后者是图像分类任务,但把它们合并成“两类检测”来做会更高效——即直接把“戴手套的手”和“未戴手套的手”分别作为两个检测类别,让模型一次推理就拿到结果。这样设计的好处是流程简单、工程实现容易,而且后续如果想把项目扩展成安全帽、反光衣检测,只需要在数据集里增加类别,不需要改动检测框架。
1.2 技术选型:为什么是YOLOv8而不是其它方案
做目标检测可选的方案不少,拿Faster R-CNN、SSD、YOLOv5和YOLOv8做了一圈对比之后,我最终把YOLOv8定为主模型。很多人可能觉得选型就该选精度最高的,但在工业场景里,“能部署、能实时、好维护”往往比账面精度更重要。
YOLOv8相比早期版本有几个实实在在的优势。它采用了Anchor-Free的检测头设计,不再需要像YOLOv5那样预设一堆anchor框,省去了聚类分析和调参的过程,训练更稳定。C2f模块在保持轻量的同时增强了梯度回传,模型更容易收敛。解耦头把分类和回归分开处理,收敛速度和最终精度都有提升。最后也是很重要的一点,Ultralytics官方把训练、验证、导出、推理封装得非常完善,数据标注完丢进去就能跑,这对快速交付项目非常关键。
对比之下,Faster R-CNN虽然精度上限高,但推理速度在CPU上完全跑不动实时检测,GPU上帧率也偏低;SSD速度尚可,但小目标检测能力偏弱,而手套手部这种在监控画面里占比不高的目标,恰恰需要较强的中小目标检测能力。YOLOv8n/s这种轻量级版本在GPU上可以跑到几百帧,部署在工控机上配合摄像头做实时检测,完全够用。
2. 数据集构建:决定模型上限的关键一步
2.1 数据采集规范与类别设计
说句实在话,整个项目里最考验功底的环节不是写代码,而是弄数据集。模型能不能在真实环境里稳定工作,七成取决于训练数据是否贴近现场。训练数据的采集,我建议直接去目标产线实地拍摄,而不是在网上东拼西凑下载通用手部数据集。原因很简单:不同工厂的光照条件、手套样式、背景环境差异非常大,用网上公开数据集训练出来的模型,到了你自己车间里很可能水土不服。
采集的时候要注意覆盖以下几个维度。第一是不同时段的光照,白班日光充足和夜班灯光昏暗,画面特征差别极大;第二是不同工位和拍摄角度,固定枪机、半球机、手机补拍的角度都要尽量涵盖;第三是手套种类的多样性,常见的纱线手套、乳胶手套、防割手套外观差异明显,最好都能纳入训练集,避免模型只认得某一种手套。
类别设计上,这个项目采用了两个类别:with_glove(戴手套的手)和without_glove(未戴手套的手)。为什么不单独加一个hand类别?因为我们的业务目标就是判断是否佩戴,二分类已经能完整表达需求。如果加了裸手类别,反而会让模型在戴手套和裸手之间产生混淆,增加标注和训练成本。但注意,如果你的场景里需要区分左手右手,或者需要区分手套颜色来匹配不同岗位要求,那就要重新设计类别体系。
2.2 标注工具与标注规范
标注工具推荐用LabelImg或者x-anylabeling,两个都是开源免费的工具,支持YOLO格式直接导出。x-anylabeling还支持PaddleOCR和SAM辅助标注,对于大量图片可以省不少时间。标注的规范比工具更重要,我踩过几个坑,总结成几条硬性规则:
- 边界框必须完整包裹手部区域。如果手指部分露出来而框只框到手掌,模型学到的手部特征就是残缺的,推理时很容易漏检。
- 手套与手部接触的边缘不用纠结,按照视觉上“手”的轮廓来框就行。戴手套的手和裸手在轮廓上差异不大,模型主要靠纹理和颜色特征区分。
- 模糊帧不能全部丢弃。监控视频里运动模糊是常态,适当保留一部分模糊样本,模型在真实场景中的鲁棒性反而更好。
- 遮挡样本按实际可见范围标注。手被零件挡住一半的情况,就只框可见部分,不要强行脑补完整边界框。
标注完成后,记得做一遍质量检查。我会把标注好的图片随机抽样,用脚本画框可视化,逐一确认框的贴合程度。如果有大量框偏移超过5%,这轮标注就需要返工,否则后面训练出来的模型会带着同样的偏差。
2.3 数据增强策略与数据集划分
数据集规模上,我最终积累了约4000张图片,其中戴手套和未戴手套各占一半左右,总标注框数超过6000个。如果你从零开始采集,每类至少也要攒够800到1000张图,否则模型很难学到稳定的特征。
训练时我开了YOLOv8自带的增强策略,主要包括Mosaic、随机翻转、色调扰动、缩放和平移。Mosaic增强把四张图拼成一张,相当于用有限的标注数据扩大了背景多样性,对提升模型泛化能力很有帮助。但注意,Mosaic在训练最后几个epoch建议关闭,因为拼接图的分布和真实场景还是有差异,全程开启反而会让模型在真实图片上表现打折。
数据集划分采用8:1:1的比例,即3200张训练、400张验证、400张测试。划分的时候要用随机种子固定下来,保证每次实验的可复现性。我习惯把同一场景的连续帧全部划到同一个集合里,避免训练集和验证集出现数据泄漏,导致验证指标虚高。
3. YOLOv8训练全流程:从环境到权重文件
3.1 运行环境准备
训练环境的搭建是整个流程里最“顺滑”的部分,因为Ultralytics已经把依赖封装得很干净。Python版本建议3.8到3.10之间,安装ultralytics库会自动带上PyTorch等核心依赖。GPU方面,我用的是一块消费级显卡,8GB显存就可以训练yolov8s模型,显存更大当然更好,没有GPU的话用CPU训练也不是不行,只是速度会慢几十倍,不建议进行完整训练。
推荐用虚拟环境隔离依赖,避免和系统自带的Python包互相打架。简单列一下核心依赖版本供参考:
- Python 3.9
- ultralytics 8.0.x以上
- PyTorch 2.0.x
- CUDA 11.8(如果你的显卡驱动支持更高版本也可以)
- opencv-python 4.x
- labelimg 或 x-anylabeling
另外,如果你的机器上有多个Python版本,务必在虚拟环境里指名道姓地使用python和pip命令,不要在全局环境安装,否则不同项目的依赖冲突会把人逼疯。
3.2 训练配置与参数调优
训练前需要准备一个数据集配置文件,指明训练集、验证集路径和类别名称。路径建议全部使用绝对路径,相对路径在某些环境下会踩坑。配置文件写好后,用Ultralytics的命令行工具即可启动训练。
训练参数的选择上,我建议从yolov8n或yolov8s这种中小模型开始跑通流程,之后再根据验证集精度决定是否升级到大模型。几个关键参数设置如下:
- imgsz=640。默认值就是640,过大的尺寸会显著增加推理耗时,对于手套检测这种中等大小的目标,640已经足够。
- batch=16。8GB显存跑yolov8s可以开到16,如果显存不足就降到8,batch太小会导致BN层统计不稳定,模型收敛变慢。
- epochs=200。配合同样大小的数据集足够收敛,前提是配合早停机制使用,否则白白浪费算力。
- patience=30。连续30个epoch验证集指标不提升就自动停止训练,这个机制能省大量时间。
- workers=4。数据加载的线程数,Windows下如果遇到DataLoader报错可以调小或者设为0。
这里多说一句为什么batch不能随便开大。在工业场景中,训练数据往往存在一定程度的类别不平衡,如果batch开得过大,在一个batch里可能全是同一类别的样本,梯度更新方向就会有偏。所以稳定训练比追求极限速度更重要。
训练过程的日志要重点盯三个指标:box_loss、cls_loss和验证集mAP曲线。如果loss曲线一开始就剧烈震荡,优先检查数据集里是否有标注错误;如果训练集loss下降但验证集loss上升,这是典型的过拟合,应增大数据增强强度或引入更多数据。
3.3 模型评估:不能光看mAP
训练结束后生成的最佳权重文件best.pt,要综合P(精确率)、R(召回率)、mAP50和mAP50-95这几个指标来评估。mAP50是IoU阈值为0.5时的平均精度,它衡量的是“框得差不多的算不算检测成功”;mAP50-95则是从0.5到0.95遍历多个IoU阈值的平均,对框的位置精度要求更高。安全手套检测这种偏生产场景的任务,我更看重mAP50-95,因为框位置不准会影响后续的报警联动逻辑。
但指标再漂亮,也不如实际看推理效果。我会从测试集里挑出不同场景的图片跑一遍预测,把预测结果可视化后一张张看,重点关注两类错误:一是漏检,比如暗光下没戴手套的手没被框出来;二是误检,比如把工具、零件甚至人的手臂误判成裸手。这两类错误的处理思路我会在第五章专门展开。
训练完成后的模型文件,除了best.pt,还有last.pt(最后一个epoch的权重)和跑完的结果目录。交付项目时一般带上best.pt就够,必要的时候再根据客户运行环境导出为ONNX或者TensorRT格式。
4. UI界面与端到端推理链路
4.1 界面功能规划
项目交付给客户,不能只有命令行和一堆代码,一个能上手用的图形界面是刚需。这套系统的UI基于PyQt5开发,整体功能规划围绕检测需求展开,主界面包含四个核心区域:本地图片检测、视频文件检测、摄像头实时检测和检测结果统计。
图片检测是快速验证模型效果的最直观方式,用户选择一张图片就能立即看到检测框和类别,适合演示和调参。视频文件和摄像头检测则面向实际巡检场景,支持设置检测置信度阈值,低于阈值的结果会被过滤掉,避免一大堆低质量的框刷屏。结果统计区会实时累计检测帧数、报警次数、最近一次报警的时间,这些数据后续可以对接工厂的EMS系统或者单独导出为日志。
从工程角度看,模型推理和界面显示必须分线程处理。检测线程负责接收视频帧、执行推理、生成结果;UI主线程只负责渲染画面和响应按钮操作。如果不做多线程,摄像头帧率稍微高一点,界面就会卡死到无法点击,这个一定要在架构设计阶段就考虑进去。
4.2 推理引擎的封装
推理部分,我封装了一个独立的检测器类,把模型加载、预处理、推理、后处理全部放在里面。对外只暴露两个方法:load_model()用于加载权重文件,predict(frame)用于输入一帧图像、输出检测结果。这样做的最大好处是UI层完全不关心模型内部细节,后续想换模型或者加追踪算法,只改这一个类就行。
预处理环节需要注意一个容易被忽略的细节:YOLOv8推理时会对输入图像做letterbox变形,即等比缩放并填充灰色边,使图像尺寸符合模型输入要求。但推理得到的目标框坐标是在letterbox后的图像坐标系里的,后处理时一定要按比例映射回原始图像的坐标系,否则画框位置会整体偏移。这个Bug我调试过整整一个下午,后来通过在原图上叠加检测框对比,一眼就发现了偏移量正好等于letterbox填充边距的问题。
置信度阈值和后处理NMS阈值也建议做成可配置参数。不同场景下最优阈值并不一样,室内灯光充足时阈值可以调到0.5以上减少误报,室外或者光线复杂时降到0.3左右才能保证召回率。这种灵活性能让客户在现场自行微调,省去反复改代码的麻烦。
4.3 摄像头实时检测实现
摄像头实时检测的逻辑链路相对复杂,我采用的生产级方案是这样的:OpenCV捕获视频帧,放入一个有限长度的队列;检测线程从队列里取帧执行推理;结果回传到UI线程进行绘制。队列长度要控制住,比如最长缓存2到3帧,超过就丢最老的帧。这样做的目的是防止检测速度跟不上视频帧率时,内存里堆积大量待处理帧,导致延时越来越高。
报警模块的设计也值得一提。检测到“未戴手套”时,系统除了在画面上用红色框高亮,还会自动截取当前帧保存到本地目录,并在日志中记录时间戳、摄像头编号、置信度等信息。截图保存的意义在于,它为安全管理人员提供了可追溯的违规证据,这在事故责任认定和整改跟踪中是必需的。配套的逻辑是报警后设置一个冷却时间,比如30秒内同一工位不重复报警,避免一个违规行为刷出几十条记录,把后台数据搞脏。
实时场景下的推理性能也要提前验证。我用yolov8s模型跑1080P视频,在GPU上单帧推理耗时约15毫秒,加上绘制和显示整体帧率稳定在30FPS以上;如果换到Nano模型,推理耗时能压缩到5毫秒以内。这个帧率已经能满足监控场景的实时性要求。
5. 部署落地中的常见问题与排查记录
5.1 漏检与误检的典型场景和处理方案
项目上线后在现场暴露出来的问题,远比训练时的指标更有参考价值。整理几个典型问题场景和处理方案:
场景一:白色手套在白墙背景前,模型经常漏检。原因是手套和背景颜色过于接近,特征对比不明显。处理方案是扩充训练数据,专门采集白色工位背景下的手部图片,同时加大色调扰动和对比度变换的增强强度,逼着模型去学习手套的纹理和轮廓特征,而不是单纯靠颜色来区分。
场景二:工人手上有老茧或肤色偏深,被误检为戴了手套。这说明模型将部分肤色特征与手套特征混淆了。解决办法是检查数据集中without_glove类别的多样性,把各种肤色、不同光照条件下的裸手图片都补充进来。如果还有问题,可以考虑引入注意力机制或单独做一次手部肤色分割,但在YOLOv8框架内优先还是以增加数据为主。
场景三:夜间红外补光条件下,检测率断崖式下降。红外图像整体偏灰、对比度低,和正常可见光图像的分布差异很大。处理方案是采集夜班时段的真实红外图片加入训练集,或者对可见光训练的模型做一次针对性微调,用少量红外数据在冻结部分层的基础上续训20到30个epoch。
5.2 性能优化:帧率上不去的瓶颈分析
很多人在部署阶段问我,为什么推理显示画面只有几帧?排查思路一般按照下面这个顺序来:
第一,确认推理是在GPU上执行而不是落到CPU。很多低配环境里ONNX Runtime默认用CPU,性能直接掉一个数量级,先看任务管理器确认GPU占用率。第二,检查图像预处理是否放在循环内部反复执行,比如每次读取视频帧后都做一次缩放和格式转换,这些操作可以用预分配缓冲区来避免。第三,确认推理线程和UI绘制线程是否互相阻塞,前面提到过的帧队列策略很关键。
如果以上都没问题但帧率还是不够,就该考虑模型轻量化或导出加速格式了。同一套模型导出成TensorRT INT8量化版本后,推理速度能提升两到三倍,代价是精度轻微下降,一般在实际部署中这点精度损失是完全可以接受的。CUDA环境部署时还可以开启半精度FP16推理,显存占用减半,速度也更快。
5.3 模型导出与跨平台部署方案
项目交付时,除了PyTorch原生的best.pt,我通常还会导出ONNX和TensorRT两种格式。ONNX格式的通用性最好,可以无缝对接OpenCV DNN、ONNX Runtime和各种云服务推理环境,适合客户端多样、不便统一装CUDA环境的场景。TensorRT格式则主要用于固定GPU环境的服务器或工控机,追求极致推理性能。
ONNX导出命令非常简单,Ultralytics提供了内置接口。导出后一定要用onnxruntime做一遍精度对齐测试,拿同一张图分别用PyTorch和ONNX Runtime推理,对比两者输出的类别和置信度。常见的问题是某些算子在不同框架间兼容性不佳,导致输出结果不一致,这时可以尝试简化模型结构,或者把opset版本调低。
如果是做Web端或者API服务,另一个思路是企业微信或钉钉机器人告警:检测到违规后,系统自动把截图和位置信息推送到安全员手机,让违规处置从被动抽查变成主动即时响应。这就把纯视觉检测系统升级成了一个小型的IoT告警平台,项目的实用价值也提升了一个档次。
结尾:一点个人体会
整套项目做下来,我最大的体会是:目标检测模型训练这件事,在今天的工具链下已经变得非常“平民化”,真正决定项目成败的反而是数据和工程细节。数据有没有覆盖足够多的现场场景,标注做不做得到位,推理链路有没有考虑边界情况,UI交互能不能让客户真正用起来——这些环节才是让模型从“跑通”走向“好用”的关键。
如果你正好也在做一个类似的检测项目,我建议先别急着训练模型,花一周时间把现场环境摸透、把数据采集规范定好,这个时间投入远比之后反复调参补数据划算。后续这个项目还可以往两个方向扩展:一是增加安全帽、反光衣、工服等PPE检测类别,做成一个完整的个人防护装备识别平台;二是接入视频流管理系统,实现多路摄像头的集中调度和告警统计分析。方向很多,核心还是先把单点场景做扎实。