简介:面向深度学习和目标检测开发者,这是一套基于YOLOv8的玻璃表面缺陷检测可运行源码,针对点状缺陷、划痕缺陷和擦伤缺陷三类问题,提供从数据准备、模型训练到可视化检测的完整实现。资源共7个文件、约10KB,包含3个Python脚本、1个YAML配置文件和1个TXT依赖清单,分别对应训练流程、GUI检测界面、示例数据生成和运行环境说明,结构精简,便于快速调试与二次开发。已有95人学习。代码涵盖依赖安装、data.yaml创建、预训练模型加载、训练参数调整及准确率/召回率评估等关键环节,搭配8000张玻璃缺陷图像数据集即可直接运行训练流程;PyQt5图形界面还能实时展示检测结果,降低入门门槛。适合刚接触YOLOv8的初学者,也适合需要快速搭建缺陷检测方案的研究者参考。 玻璃缺陷检测一直是工业视觉里的硬骨头,传统算法面对划痕、气泡、杂质这些目标时,特征设计要费很大劲,而且换一条产线、换一种光源,规则基本就要推倒重来。YOLOv8出来之后,这个问题的解法就变得直白多了——准备好带标注的缺陷数据,训练一个检测模型,推理阶段直接输出缺陷位置和类别。这篇文章我就围绕“YOLOv8玻璃缺陷检测[可运行源码]”这个项目,把数据集制作、环境配置、训练调参、部署推理全流程拆开讲清楚,重点说那些代码跑通之后你才会遇到的坑,以及我怎么用GTX 1660Ti这种入门卡把模型练到可用的程度。
这个项目适合谁?如果你是做机器视觉的工程师,刚接触深度学习目标检测,或者你在学校做相关课题,手里已经有一批玻璃缺陷图片但不知道从哪下手,这篇内容应该能帮你省掉至少一周的试错时间。我会把GitHub上常见的“可运行源码”背后那些没写出来的细节补齐,包括标注格式怎么转、增量训练怎么避免灾难性遗忘、损失函数曲线怎么看,以及导出ONNX部署时容易忽略的细节。
1. 项目整体设计与方案选型
1.1 为什么玻璃缺陷检测选择了YOLOv8
玻璃表面的缺陷有一个特点:小目标多、对比度低、形态差异大。气泡、结石、划痕、夹杂物,每种缺陷的尺寸可能只有十几个像素到几十个像素,背景又是透明或半透明的玻璃本体。传统机器视觉用阈值分割加形态学处理,只能搞定特定光照下、特定类型的缺陷,一旦产品切换,算法工程师就得重新调参,维护成本非常高。
YOLOv8的优势在于它是端到端的检测框架,不需要手动设计特征。网络自己从数据里学习“什么是缺陷”,对不同缺陷形态的适应能力远强于传统方法。相比YOLOv5,YOLOv8在Backbone和Neck部分做了优化,引入C2f模块替代原来的C3模块,梯度流更丰富,小目标特征提取能力有实打实的提升。加上Decoupled Head(解耦头)把分类和回归分成两个分支,收敛速度和精度都比之前的耦合头更好。对于玻璃缺陷这种类别少、目标小的场景,YOLOv8的性价比非常高。
1.2 可运行源码的完整技术链路
一个真正“可运行”的玻璃缺陷检测项目,绝对不止是一堆训练代码。把它拆开来看,完整链路包含四部分:
- 数据端:原始缺陷图像采集、标注格式转换(LabelMe/VOC格式转YOLO格式)、数据集划分
- 训练端:YOLOv8环境搭建、预训练权重选择、超参数配置、增量训练策略
- 评估端:损失函数曲线、PR曲线、混淆矩阵、mAP指标分析
- 部署端:模型导出为ONNX/TensorRT、推理脚本编写、实时检测演示
很多“可运行源码”只给了训练部分,数据准备和部署部分一笔带过,结果新手卡在第一步——标注完的数据不知道怎么转成YOLO格式。我后面会直接给出一段脚本解决这个问题,这也是我踩过坑之后沉淀下来的东西。
2. 环境配置与数据准备的关键细节
2.1 环境版本与硬件适配
先说环境。YOLOv8基于PyTorch,Python版本建议3.8到3.11之间。我自己的实测环境是Python 3.10 + PyTorch 2.0.1 + CUDA 11.8,GTX 1660Ti 6GB显存。这个组合在Ultralytics官方仓库的requirements.txt基础上,没有额外装任何东西,直接能跑。
如果你是N卡用户,CUDA版本确认很重要。命令行里输入nvidia-smi,看右上角的CUDA Version,那个是驱动支持的最高版本,不是当前环境实际使用的版本。PyTorch实际调用的是你通过pip安装的CUDA运行时。所以哪怕驱动显示CUDA 12.2,你仍然可以装CUDA 11.8版本的PyTorch,只要驱动版本不低于要求的470以上就行。
# 创建虚拟环境 conda create -n glass python=3.10 -y conda activate glass # 安装PyTorch(以CUDA 11.8为例) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装YOLOv8 pip install ultralytics6GB显存跑YOLOv8s是没问题的,训练时把batch size设为8,图片尺寸640x640,显存占用大概在4GB左右。如果你只有4GB显存,就换成YOLOv8n或者把batch降到4,也能跑,就是训练时间会长一些。别一开始就上YOLOv8x,那个在没有24GB以上显存的卡上做训练基本是折磨自己。
2.2 数据标注与格式转换是第一个大坑
玻璃缺陷检测的数据集常见来源是产线相机采集,或者网上公开的玻璃缺陷数据集(比如东北大学的带钢表面缺陷数据集思路类似,但玻璃的要自己攒)。拿到原始图片后,标注工具我推荐LabelImg或者X-AnyLabeling。前者轻量,后者支持自动标注和交互式分割,效率高不少。
标注完导出的格式一般是Pascal VOC(XML文件)或者COCO(JSON文件),而YOLOv8训练需要的是YOLO txt格式:每行一个目标,格式为class_id x_center y_center width height,坐标是归一化后的值。这里我直接给一个从VOC格式转YOLO格式的Python脚本,实测可以直接用:
import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_file, class_names, output_dir): tree = ET.parse(xml_file) root = tree.getroot() img_w = int(root.find('size/width').text) img_h = int(root.find('size/height').text) yolo_lines = [] for obj in root.iter('object'): class_name = obj.find('name').text if class_name not in class_names: continue class_id = class_names.index(class_name) bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) x_center = (xmin + xmax) / 2 / img_w y_center = (ymin + ymax) / 2 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") txt_path = Path(output_dir) / (Path(xml_file).stem + '.txt') with open(txt_path, 'w') as f: f.write('\n'.join(yolo_lines)) # 使用示例 class_names = ['bubble', 'scratch', 'inclusion', 'crack'] # 根据你自己的类别修改 xml_dir = 'annotations' output_dir = 'labels' os.makedirs(output_dir, exist_ok=True) for xml_file in Path(xml_dir).glob('*.xml'): voc_to_yolo(xml_file, class_names, output_dir)这里特别提醒一下:标注的时候框一定要贴合缺陷边缘,不要留太多背景。玻璃缺陷本身对比度低,如果标注框里包含大量正常玻璃区域,模型学到的特征会被稀释,收敛后精度会明显下降。我见过有人标注气泡时框比实际气泡大了两三倍,最后mAP怎么调都上不去,重新标了一轮数据立刻就好了。
2.3 数据集划分与类别分布
YOLO格式的数据准备好了,接下来要准备数据集配置文件。目录结构建议这样组织:
glass_defect/ ├── data.yaml ├── train/ │ ├── images/ │ └── labels/ ├── valid/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/data.yaml内容如下:
path: D:/projects/glass_defect # 数据集的绝对路径 train: train/images val: valid/images test: test/images nc: 4 names: ['bubble', 'scratch', 'inclusion', 'crack']划分比例我建议训练集70%、验证集20%、测试集10%。注意一个关键点:划分时要按“缺陷样本”划分,而不是按“图片”划分。如果一张图片里有多种缺陷,就把这张图片整体挪到同一个集合里,千万别把同一张图的一部分缺陷分到训练集、另一部分分到验证集,那样会造成数据泄露,验证指标虚高。
3. 训练核心配置与调参实战
3.1 预训练权重选择与增量训练策略
YOLOv8训练玻璃缺陷检测,最关键的决策之一是用预训练权重还是从零开始训练。我的建议是:用yolov8s.pt做迁移学习,除非你的缺陷数据超过几万张,否则不要从零训练。原因很简单,玻璃缺陷数据集通常只有几百到几千张,这点数据量不够网络从头学到底层特征,而预训练模型已经在COCO上见过海量真实世界图片,它学到的边缘、纹理、形状特征对玻璃缺陷同样适用。
迁学习训练的时候,默认情况下Ultralytics会冻结Backbone的权重吗?不会,整个网络都会参与训练。如果你希望保留更多底层特征,只训练头部,可以这样写:
yolo detect train data=glass_defect/data.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=8 device=0 freeze=10freeze=10表示冻结前10层(通常是Backbone部分),只在Neck和Head上做微调。这种策略适合数据量很小(几百张)的情况,能有效防止过拟合。如果数据量有2000张以上,我一般不再冻结,让整网络自适应调整,效果更好。
增量训练是另一个高频需求——产线上隔一段时间就会新增一批缺陷样本,不可能每次都从头开始训练。YOLOv8增量训练很简单,把model参数从上一次训练得到的best.pt开始接着跑就行:
yolo detect train data=glass_defect/data.yaml model=runs/detect/train/weights/best.pt epochs=50 imgsz=640 batch=8 device=0这里有个惨痛教训:增量训练的学习率一定要调小,建议lr0=0.001左右,比正常训练小一个量级。如果还用默认的0.01,新数据会把已经学好的特征冲掉,出现灾难性遗忘,表现为旧类别召回率骤降,新增数据也没学好。我第一做增量训练就吃过这个亏,损失曲线看起来在下降,但推理时旧缺陷全部漏检,后来把学习率降到0.001才恢复正常。
3.2 损失函数曲线图怎么看
训练过程中,runs/detect/train/下会自动生成results.png,这个图包含训练损失、验证损失、精度、召回率、mAP等曲线。很多新手只看train loss下降就觉得万事大吉,这是不对的。
正确看曲线的方式是同时对train loss和val loss:
- 两条线都平稳下降且最终收敛,说明训练正常
- box_loss下降但cls_loss高位震荡,说明类别区分度不够,回看标注数据看是不是类别标签错了
- train loss持续下降、val loss拐头上升,典型过拟合信号,需要增加数据量或加正则化
还有个容易被忽略的曲线是labels_correlogram.jpg,它把标注框的中心点坐标和宽高分布画出来了。如果你的缺陷目标中心点集中在图片正中间,而实际产线上缺陷可能出现在玻璃边缘,那说明训练数据的采样有偏差,模型泛化到实际场景时会出问题。看到这种情况,要主动从产线采集更多包含边缘缺陷的样本补进训练集。
3.3 GTX 1660Ti跑YOLOv8的真实体验
我用GTX 1660Ti(6GB显存)跑完整个项目,可以负责任地说,这张卡跑YOLOv8s完全可行,但需要一些策略。YOLOv8s + imgsz=640 + batch=8,训练100个epoch,大概需要4到6小时。如果换YOLOv8n,时间可以压缩到2到3小时,mAP会掉3到5个点。
单张1660Ti推理一张640x640图片大概需要30到50毫秒,也就是20到30 FPS。做离线检测完全够用,但如果要上产线做实时在线检测(要求30 FPS以上),建议导出成TensorRT用INT8量化推理,速度能提升到60到80 FPS。TensorRT这块细节比较多,我在后面部署部分专门说。
训练时还有个小技巧:开启amp=True(默认开启),混合精度训练。1660Ti的Tensor Core支持混合精度,训练速度提升接近20%,精度几乎没有损失。遇到训练时显存溢出,优先减小batch,其次是减小imgsz,不要直接换模型,不然训练时间翻倍。
4. 常见报错与部署实操心得
4.1 训练和推理中的高频报错
我帮不少人排查过YOLOv8跑玻璃缺陷数据的报错,这里整理几个出现频率最高的问题:
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
CUDA out of memory | 显存不足 | 调低batch到4或2,或者用YOLOv8n |
Dataset not found | data.yaml路径配置错误 | 检查path是否用了绝对路径,路径不能含中文 |
Expected 4D tensor... | 输入图片通道数异常 | 检查图片是否损坏,删除异常图片 |
No labels found in ... | 标注txt和图片没有对应上 | 确认txt文件名和图片文件名完全相同 |
AssertionError: class number out of range | 标签中的class_id超出nc范围 | 检查txt文件里的第一个数字是否小于nc |
这里要单独说一个问题:数据损坏。玻璃缺陷数据集中经常混入一些从产线拷出来的损坏JPG文件,图片本身打不开或者只有部分像素。YOLOv8加载数据时遇到损坏图片就会报错或者莫名其妙卡住。我写了个简单脚本提前清洗:
from PIL import Image from pathlib import Path img_dir = Path('train/images') for img_path in img_dir.glob('*.jpg'): try: with Image.open(img_path) as im: im.verify() except Exception as e: print(f'损坏图片: {img_path}') # 记得同时删除对应的labels txt文件4.2 导出ONNX/TensorRT部署的实际操作
训练收敛、验证mAP达标之后,下一步就是部署。Ultralytics官方封装了导出接口,导出ONNX很简单:
yolo export model=best.pt format=onnx imgsz=640 opset=12导出TensorRT需要NVIDIA显卡,命令也一行:
yolo export model=best.pt format=engine imgsz=640 half=Truehalf=True表示FP16精度,精度损失很小,速度提升明显。这一步做完,你得到的`.
engine`文件就可以在TensorRT Runtime里直接跑了。
实际部署时有个坑:导出时输入的图片尺寸必须和推理时保持一致。如果你导出用的是imgsz=640,推理时输入图片如果是1280x720,模型不会报错,因为YOLOv8内部做了letterbox缩放,但检测精度会受影响,因为缩放比例和训练时不一致。正确做法是推理前先做letterbox,让长边缩放到640,短边填充为灰色。Ultralytics默认的predict方法会自动做这个处理,但如果你手写推理代码,一定要把letterbox这块处理好。
代码方式加载引擎推理:
from ultralytics import YOLO # 加载TensorRT模型 model = YOLO('best.engine') # 推理 results = model.predict('test_image.jpg', conf=0.25, iou=0.45) # 结果可视化 for r in results: boxes = r.boxes for box in boxes: cls_id = int(box.cls[0]) conf = float(box.conf[0]) xyxy = box.xyxy[0].tolist() print(f'类别: {model.names[cls_id]}, 置信度: {conf:.3f}, 框: {xyxy}')4.3 玻璃缺陷检测效果优化心得
整个项目跑下来,我的体会是模型结构层面的调整对最终效果的影响远小于数据层面的精耕细作。我在这个项目里尝试过给YOLOv8引入多头注意力机制MHSA,替换过主干网络ConvNeXt V2,精度确实有提升,但涨幅有限,一般就1到2个mAP点。真正让效果有质的飞跃是以下三个操作:
第一,数据增强策略调整。玻璃缺陷是小目标,默认的Mosaic增强虽然能提升模型鲁棒性,但会导致小目标被裁剪掉。我在配置里把mosaic=0.5降到mosaic=0.3,同时把copy_paste=0.3(如果使用YOLOv8的增强策略)适当调高,小目标召回率明显改善。
第二,负样本的使用。产线上大量图片是合格的玻璃,没有缺陷。很多训练数据集只包含缺陷样本,导致模型在正常玻璃上有误检。我在训练集里加入了约15%的无缺陷负样本(标签文件为空),模型的误检率降了一半以上。YOLOv8的训练流程支持空标签文件,它能正常学习“这张图里没有任何目标”。
第三,测试时增强(TTA)。如果你对单张图片的检测置信度不满意,推理时开启TTA:
yolo predict model=best.pt source=test.jpg tta=TrueTTA会对同一张图片做多尺度缩放和翻转推理,把多次预测结果融合,精度会提升,但速度会慢几倍。适合离线分析场景,不适合实时产线。
最后再分享一个小技巧。训练完成后,除了看mAP,一定要亲自拿几张产线实际拍的照片测试,尤其是不同光照条件下的图片。我遇到过一次,模型在训练集同分布的图片上mAP有0.92,但拿到产线在清晨自然光条件下拍的照片,API直接掉到0.7。后来发现是训练数据的亮度分布太集中,模型把亮度当成了背景特征。解决办法是训练前对图片做随机亮度扰动,这也算是数据增强日常被忽视但关键时刻救命的一个点。
本文还有配套的精品资源,点击获取