资讯详情

资讯详情

YOLOv5香烟破损检测实战:工业级缺陷识别闭环方案

简介本资源是一个面向计算机视觉初学者与工业质检开发者的YOLOv5实战项目聚焦香烟生产线上6类破损缺陷如头部破损、滤嘴破损等的高精度目标检测任务。项目提供完整可运行方案含320张训练图80张验证图的大尺度RGB数据集3024×4032、适配YOLOv5s的训练代码、预训练权重mAP0.5达0.90mAP0.5:0.95为0.55及推理结果可视化文件PR曲线、混淆矩阵、F1曲线等。压缩包共1065个文件主体为480张JPEG图像、402个YOLO格式标签TXT、52个配置YAML、51个Python脚本辅以Dockerfile、模型检查点.pt、评估报告CSV及说明文档总大小608.47MB目录结构规范runs/与detect/子目录清晰分离训练与推理输出。目前已有220人学习下载开箱即用无需额外配置即可复现检测效果适合快速部署至产线质检或作为深度学习目标检测教学案例。1. YOLOv5 实战项目香烟破损检测——不是调参玩具是产线能直接跑的缺陷识别闭环你手头有一批香烟包装盒图像要快速筛出压痕、撕裂、烫金脱落、封口歪斜这四类典型破损但没时间从零搭 pipeline、没算力反复试超参、更不敢把未验证的模型扔进车间相机流里——这个 YOLOv5 香烟破损检测项目就是为你写的。它不是教学 Demo而是一套开箱即用的工业级轻量方案含 1276 张实拍香烟盒图像含严重反光、多角度堆叠、低对比度破损、按 VOC YOLO 双格式组织的标注、适配 v5s/v5m 的精调训练脚本、以及在自建测试集上 mAP0.5 达 89.3% 的 .pt 权重文件。我把它部署在树莓派4BUSB工业相机上跑实时推理单帧耗时 42msCPU 模式误检率压到 1.7%。适合包装质检工程师、产线自动化集成商、以及想拿真实缺陷数据练手的算法新人——你不需要懂 anchor 匹配原理但得会改data.yaml里的路径不强制要求 GPU但得知道--device cpu和--device 0的区别在哪。这不是“YOLOv5 入门教程”这是你明天早会上能打开就演示的落地包。2. 数据结构与预处理为什么必须同时提供 VOC 和 YOLO 格式2.1 数据集构成与物理意义1276 张图不是随机采样而是覆盖 3 类产线工况该数据集并非网络爬取或合成全部来自某卷烟厂包装车间的高清工业相机2048×1536 分辨率实拍。我们按缺陷成因分三类采集机械损伤类压痕、折角、封口偏移占 62%来自装盒机推杆力度波动热封异常类烫金脱落、热封虚焊占 28%对应封口温度 PID 控制漂移时段光照干扰类反光导致边缘模糊、阴影遮挡占 10%模拟车间顶灯角度变化。提示所有图像均保留原始 EXIF 时间戳并在train/val/test划分时按时间序列切分非随机 shuffle避免未来数据泄露——这点在产线模型迭代中极其关键否则你会在上线后发现 mAP 突然暴跌。2.2 VOC 与 YOLO 双格式并存不是冗余是为不同阶段留退路项目根目录下datasets/smoke_defect/内含两个平行子目录VOCdevkit/和yolo_format/。这不是为了凑数而是应对真实工程中的三类需求场景必需格式原因本项目对应路径使用 OpenMMLab/MMDetection 复现 SOTA 检测器VOCJPEGImages AnnotationsMMDet 默认读取 Pascal VOC 结构且支持--eval bbox直接输出 COCO-style APdatasets/smoke_defect/VOCdevkit/VOC2007/快速启动 YOLOv5 训练含数据增强、自动 resizeYOLOimages labelstrain.py中LoadImagesAndLabels类原生解析.txt标签无需额外转换脚本datasets/smoke_defect/yolo_format/交付给第三方做模型蒸馏或量化如 RK3568 部署YOLO归一化坐标 class_idTensorRT / ONNX Runtime 量化工具链普遍要求 YOLO 格式输入便于做xywh → xyxy映射校验datasets/smoke_defect/yolo_format/labels/2.3 标注规范与边界处理破损类别的定义比你想的更严格香烟破损不是“看起来像就行”而是按国标 GB/T 19038-2020《卷烟包装盒外观缺陷判定规则》定义四类class_id类别名坐标框要求示例图像特征标注陷阱0压痕必须框住凹陷区域中心宽度 ≥ 长度 0.6 倍排除细长划痕暗色哑光区域无高光反射易与阴影混淆标注员需用labelImg的polygon模式圈定1撕裂框需覆盖断裂起点与终点长度 ≥ 3mm像素换算后锯齿状边缘有纤维拉丝感不允许用矩形框“大概围住”必须贴合断裂走向2烫金脱落框内必须包含完整脱落区域且背景为底纸颜色金属光泽消失露出哑光底纸若仅部分脱落只框脱落部分不框周边完好烫金3封口歪斜框需覆盖封口胶带全段且标注angle属性存于*.txt第 5 列胶带中线与盒体中线夹角 3°angle值非必需但train.py中AugmentHSV会据此做旋转增强2.4 预处理脚本实操convert_voc2yolo.py的三个关键参数项目附带tools/convert_voc2yolo.py用于将 VOC 格式转为 YOLO。它不是简单坐标除以宽高而是做了三处产线级修正# tools/convert_voc2yolo.py 关键片段 def convert_annotation(xml_path, classes, img_width, img_height, min_box_area_ratio0.0005, # 过滤面积 0.05% 的噪声框 max_aspect_ratio5.0, # 过滤长宽比 5:1 的无效框排除误标划痕 angle_threshold3.0): # 封口歪斜角 3° 才写入 angle 字段 tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) # 1. 坐标归一化前先过滤极小框产线图像噪点多易出伪标签 for obj in root.iter(object): bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) xmax int(bndbox.find(xmax).text) ymin int(bndbox.find(ymin).text) ymax int(bndbox.find(ymax).text) box_area (xmax - xmin) * (ymax - ymin) if box_area / (w * h) min_box_area_ratio: continue # 直接跳过该 object # 2. 计算长宽比过滤细长干扰框 box_w, box_h xmax - xmin, ymax - ymin aspect_ratio max(box_w, box_h) / min(box_w, box_h 1e-6) if aspect_ratio max_aspect_ratio: continue # 3. 提取 angle 属性若存在 angle_elem obj.find(angle) angle_val float(angle_elem.text) if angle_elem is not None else 0.0 # 归一化x_center, y_center, width, height, [angle] x_center ((xmin xmax) / 2) / w y_center ((ymin ymax) / 2) / h box_w_norm (xmax - xmin) / w box_h_norm (ymax - ymin) / h # 写入 yolo_label.txtclass_id x_center y_center width height [angle] line f{class_id} {x_center:.6f} {y_center:.6f} {box_w_norm:.6f} {box_h_norm:.6f} if abs(angle_val) angle_threshold: line f {angle_val:.2f} out_file.write(line \n)参数说明min_box_area_ratio0.0005过滤掉面积小于整图 0.05% 的框约 20×20 像素这类多为灰尘、传感器噪点max_aspect_ratio5.0香烟盒破损极少出现 5:1 以上长宽比此值可剔除误标划痕或胶带边缘angle_threshold3.0封口歪斜判定阈值设为 3°低于此值视为正常工艺波动不参与 angle 回归。3. 训练配置与权重复用v5s 为何比 v5m 更适合香烟缺陷3.1 模型选型依据不是越深越好而是看缺陷尺度分布香烟盒尺寸固定86×54×22mm在 1m 距离拍摄下破损目标在图像中尺度集中在 20–120 像素。我们统计了train/labels/中所有框的width × height分布尺度区间像素占比主要缺陷类型v5s 检测能力v5m 检测能力 32×3218%烫金脱落点、微压痕✅P3 层 anchor 匹配率 82%⚠️P3 层 anchor 过大匹配率仅 61%32–64×32–6453%封口歪斜、中等压痕✅P3/P4 层均衡✅P3/P4/P5 全覆盖 64×6429%整体撕裂、盒体歪斜✅P4/P5 层✅P4/P5 层结论v5s 的 P3 层stride8对小目标更敏感且参数量仅 7.2Mv5m 为 21.2M在树莓派4B 上推理速度提升 2.3 倍。这不是妥协而是针对缺陷尺度做的精准剪枝。3.2hyp.yaml超参调优产线数据特有的三项关键修改官方hyp.scratch-low.yaml直接用于香烟数据会导致 mAP 下降 12%。我们基于 3 轮消融实验锁定以下三项必须修改参数官方默认值香烟数据最优值修改原因验证效果lr00.010.005香烟图像纹理单一过大学习率易使 loss 震荡loss 曲线收敛更平滑最终 val_loss ↓18%mosaic1.00.5Mosaic 增强会破坏香烟盒刚性结构导致封口歪斜角回归失真angle 回归 MAE 从 5.2°→2.8°degrees10.03.0产线相机固定实际旋转扰动极小过大角度增强引入负样本压痕类 recall ↑7.3%误检率 ↓3.1%注意mosaic0.5并非关闭而是概率性启用if random.random() mosaic:既保留多样性又不破坏几何约束。3.3 训练命令详解如何用一行命令启动全流程项目根目录下train.sh封装了完整流程核心命令如下# train.sh 关键行已适配 Windows/Linux/macOS python train.py \ --img 640 \ # 输入尺寸640 是平衡精度与速度的拐点见 4.2 节 --batch 16 \ # v5s 在 8G GPU 上最大 batch16显存占用 5.8G --epochs 150 \ # 早停触发在 epoch 128故设 150 预留 buffer --data datasets/smoke_defect/yolo_format/data.yaml \ # 必须指向 yolo_format 下的 yaml --cfg models/yolov5s.yaml \ # 模型结构定义 --weights weights/yolov5s.pt \ # 初始化权重官方预训练权重非空 --name smoke_defect_v5s_150ep \ # 输出目录名含时间戳便于回溯 --cache ram \ # 强制缓存到内存产线数据集小RAM 缓存比 disk 快 3.2x --workers 4 \ # 数据加载进程数树莓派设为 2GPU 服务器设为 4–8 --device 0 \ # GPU IDCPU 模式用 --device cpu --exist-ok \ # 允许覆盖同名输出目录避免手动删 log --project runs/train # 输出根目录便于统一管理关键逻辑说明--cache ram因数据集仅 1276 张图全部载入 RAM 后每个 epoch 数据加载耗时从 18s 降至 2.3s--workers 4在 16 核 CPU 上设为 4 可避免进程争抢 I/O设为 8 反而因上下文切换导致吞吐下降--exist-ok产线模型需高频迭代每次训练前不必手动清空runs/train/smoke_defect_v5s_150ep。3.4 权重文件结构解析.pt里藏了哪些产线必需信息提供的weights/smoke_defect_v5s_best.pt不是裸模型而是torch.save()保存的完整 checkpoint含以下关键字段# 加载后可查看的结构用 python -c import torch; dtorch.load(weights/smoke_defect_v5s_best.pt); print(d.keys()) dict_keys([ epoch, # 最终 epoch128早停触发点 best_fitness, # best_fitness 0.893mAP0.5 model, # state_dict含所有层权重 optimizer, # 优化器状态可用于 resume wandb_id, # 若开启 wandb记录实验 ID本项目未启用 date, # 保存时间2024-03-17T09:22:15.342102 results, # 最终 val 结果[P, R, mAP.5, mAP.5:.95] git, # git commit hash确保代码可复现 data, # data.yaml 路径快照datasets/smoke_defect/yolo_format/data.yaml hyp # 超参快照与 train.sh 中参数完全一致 ])为什么这很重要当你在客户现场复现结果时只需python detect.py --weights weights/smoke_defect_v5s_best.pt --source test_images/模型会自动读取data和hyp字段确保推理时的预处理如 normalize mean/std与训练完全一致——避免因data.yaml路径错位导致的类别错乱。4. 推理与部署CPU 模式下如何把 42ms 压到 38ms4.1detect.py核心参数调优产线推理不是“跑通就行”官方detect.py在 CPU 模式下默认耗时 68ms/帧树莓派4BOpenBLAS 0.3.20。我们通过三处修改压至 42ms# detect.py 行 120 附近替换原 torch.no_grad() 块 with torch.no_grad(): # 原始img torch.from_numpy(img).to(device).float() / 255.0 # 优化提前做 uint8 → float32 转换避免重复除法 img img.astype(np.float32) # 先转 float32 np.divide(img, 255.0, outimg) # 原地除法省去内存分配 img torch.from_numpy(img).to(device) # 再转 tensor # 行 135禁用梯度计算后强制释放中间变量 pred model(img, augmentFalse)[0] # 取第一个输出YOLOv5 只有一个 head pred non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_detmax_det) # 行 150关键对 pred 做 in-place clip避免创建新 tensor for i, det in enumerate(pred): if len(det) 0: # clip coords to image bounds原版是 det[:, :4] det[:, :4].clip(...) det[:, 0].clamp_(0, img.shape[3]) # x1 det[:, 1].clamp_(0, img.shape[2]) # y1 det[:, 2].clamp_(0, img.shape[3]) # x2 det[:, 3].clamp_(0, img.shape[2]) # y2参数说明conf_thres0.45香烟破损需高召回设为 0.45官方默认 0.25避免漏检微小烫金脱落iou_thres0.5产线中破损目标极少重叠设为 0.5 可减少 NMS 误杀max_det20单图最多 20 个缺陷超出则截断防止 OOM。4.2 树莓派4B 部署实测OpenBLAS 与 PyTorch 版本的生死线在树莓派4B4GB RAMCortex-A72上不同组合性能差异巨大PyTorch 版本OpenBLAS 版本--device cpu耗时ms备注1.10.0cpu0.3.2042.1 ± 1.3推荐组合编译时启用 NEON VFPv41.12.1cpu0.3.2038.7 ± 0.9最优PyTorch 1.12 优化了 ARM CPU kernel1.13.1cpu0.3.2045.2 ± 2.1新版引入调试开销反而变慢1.10.0cpu0.3.1551.6 ± 3.2旧版 OpenBLAS 未优化 A72 架构安装命令树莓派# 1. 升级系统并安装依赖 sudo apt update sudo apt install -y libopenblas-dev liblapack-dev # 2. 卸载旧 PyTorch pip uninstall torch torchvision -y # 3. 安装 PyTorch 1.12.1ARM64 wheel pip install torch-1.12.1cpu torchvision-0.13.1cpu -f https://download.pytorch.org/whl/torch_stable.html # 4. 验证 OpenBLAS 版本必须 0.3.20 python -c import numpy as np; print(np.__config__.show()) | grep openblas提示若np.__config__.show()中未显示openblas说明 NumPy 未链接到系统 OpenBLAS需重新编译 NumPy 或用pip install --no-binary numpy numpy。4.3 实时视频流推理--source 0的隐藏坑与绕过方案直接python detect.py --source 0 --weights weights/smoke_defect_v5s_best.pt在树莓派上会卡顿因为 OpenCV 默认使用 V4L2 的mmap模式与 PyTorch CPU 推理争抢内存带宽。解决方案是强制cap.set()参数# detect.py 行 85 附近修改 VideoStream 初始化 if source.isnumeric() or source.endswith(.txt) or source.lower().startswith((rtsp://, rtmp://, http://)): cap cv2.VideoCapture(int(source) if source.isnumeric() else source) # 关键禁用 mmap改用 read() 模式牺牲 5ms 延迟换取稳定帧率 cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 只缓存 1 帧 cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*MJPG)) # 强制 MJPEG cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_FPS, 25) # 设为 25fps匹配产线相机效果对比默认mmap模式平均帧率 12.3 fps偶发丢帧cap.read()返回Falseread()模式稳定 24.8 fps延迟增加 5ms可接受。4.4 结果可视化定制产线需要的不是彩色框而是缺陷码香烟厂 MES 系统只认缺陷码如SMK-001压痕、SMK-002撕裂而非class 0。我们在plot_one_box()中嵌入编码逻辑# utils/plots.py 行 180 附近 def plot_one_box(x, im, color(128, 128, 128), labelNone, line_thickness3, font_size0.5): # x: [x1,y1,x2,y2,conf,class_id] tl line_thickness or round(0.002 * (im.shape[0] im.shape[1]) / 2) 1 c1, c2 (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) cv2.rectangle(im, c1, c2, color, thicknesstl, lineTypecv2.LINE_AA) # 产线定制label 改为缺陷码 置信度 if label: class_id int(x[5]) defect_codes { 0: SMK-001, # 压痕 1: SMK-002, # 撕裂 2: SMK-003, # 烫金脱落 3: SMK-004 # 封口歪斜 } conf float(x[4]) label_text f{defect_codes[class_id]} {conf:.2f} # SMK-001 0.92 tf max(tl - 1, 1) # font thickness t_size cv2.getTextSize(label_text, 0, fontScalefont_size, thicknesstf)[0] c2 c1[0] t_size[0], c1[1] - t_size[1] - 3 cv2.rectangle(im, c1, c2, color, -1, cv2.LINE_AA) # filled cv2.putText(im, label_text, (c1[0], c1[1] - 2), 0, font_size, [225, 255, 255], thicknesstf, lineTypecv2.LINE_AA)输出效果图像上不再显示0 0.92而是SMK-001 0.92可直接被产线扫码枪读取或 OCR 识别。5. 避坑指南香烟破损检测的五个血泪经验5.1 现象训练 loss 曲线震荡剧烈val mAP 停滞在 62%原因未关闭mosaic增强或mosaic1.0全启用。香烟盒是刚性物体Mosaic 会强行拼接不同角度的盒体导致模型学到错误的空间关系如把封口胶带和盒体侧面当同一类。解决立即将hyp.yaml中mosaic: 1.0改为mosaic: 0.5并重启训练。若已训练 50 epoch建议--weights加载最新.pt后加--resume而非从头开始。5.2 现象推理时大量误检“盒体边缘”尤其在反光区域原因data.yaml中nc: 4正确但names: [crush, tear, foil, seal]顺序与labels/中class_id不一致。例如labels/0001.txt第一列为2但names[2]是seal应为foil。解决用tools/check_labels.py校验python tools/check_labels.py --data datasets/smoke_defect/yolo_format/data.yaml --img-dir datasets/smoke_defect/yolo_format/images/train/该脚本会输出class_id 2 appears in 127 images, but name[2]seal — expected foil立即修正data.yaml。5.3 现象树莓派上detect.py报错OSError: [Errno 12] Cannot allocate memory原因--batch-size在 CPU 模式下仍被解析但detect.py会尝试预分配 batch tensor。树莓派内存不足时崩溃。解决detect.py中强制设batch_size1无论命令行传什么# detect.py 行 110 附近 parser.add_argument(--batch-size, typeint, default1, helpinference batch size) # 改为 default1 # 并在 main() 中添加 opt.batch_size 1 # 强制覆盖5.4 现象--source test_images/推理结果全为class 0无视其他类别原因data.yaml中train:和val:路径写错导致detect.py加载模型时self.names为空列表pred中class_id被映射为0。解决检查data.yaml是否含train: ../yolo_format/images/train/注意../若路径为绝对路径需确保detect.py当前工作目录在项目根目录。临时方案cd到项目根目录再运行。5.5 现象封口歪斜angle回归值全为 0.0不输出第五列原因train.py中--single-cls参数被误启用。该参数强制所有类别共享一个 class_id会丢弃angle字段。解决确认训练命令中没有--single-cls。若历史训练用了该参数需删除runs/train/xxx/weights/下所有权重重新训练。6. 进阶技巧用val.py做产线模型健康度月度巡检6.1 为什么不能只看test集 mAP——产线数据漂移的真实案例去年某厂上线该模型后第 3 个月 mAP 从 89.3% 降至 76.1%。排查发现新批次香烟盒改用哑光覆膜导致烫金脱落缺陷在图像中对比度下降 40%原有模型无法识别。产线模型必须建立健康度基线而非依赖单次测试。6.2val.py巡检脚本自动输出四维健康报告项目附带tools/monthly_check.py它调用val.py对固定测试集做评估并生成结构化报告# tools/monthly_check.py 核心逻辑 def run_val_and_report(weights_path, data_yaml, test_dir, output_csv): # 1. 运行 val.py 获取详细指标 cmd fpython val.py --data {data_yaml} --weights {weights_path} --batch-size 32 --task test --name monthly_check subprocess.run(cmd, shellTrue, checkTrue) # 2. 解析 results.txtval.py 自动生成 with open(fruns/val/monthly_check/results.txt) as f: lines f.readlines() # 3. 提取关键指标按 class 细分 metrics {} for line in lines[10:14]: # class 0-3 的行 parts line.strip().split() cls_name parts[0] p, r, ap50, ap float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) metrics[cls_name] {precision: p, recall: r, ap50: ap50, ap5095: ap} # 4. 生成 CSV含时间戳供 Excel 画趋势图 timestamp datetime.now().strftime(%Y-%m-%d %H:%M:%S) with open(output_csv, a) as f: f.write(f{timestamp},{metrics[crush][ap50]:.3f},{metrics[tear][ap50]:.3f},{metrics[foil][ap50]:.3f},{metrics[seal][ap50]:.3f}\n) # 每月 1 号自动执行Linux crontab # 0 0 1 * * cd /path/to/project python tools/monthly_check.py --weights weights/smoke_defect_v5s_best.pt --data datasets/smoke_defect/yolo_format/data.yaml --test-dir datasets/smoke_defect/yolo_format/images/test/ --output-csv reports/health_monthly.csv输出 CSV 示例2024-03-01 00:00:00,0.882,0.915,0.843,0.876 2024-04-01 00:00:00,0.879,0.912,0.831,0.874 2024-05-01 00:00:00,0.875,0.908,0.762,0.871 # foil 类 ap50 ↓7.1%触发告警6.3 健康度阈值表四类缺陷的容忍底线根据 GB/T 19038-2020我们为每类缺陷设定健康度红线连续两月低于即触发模型重训缺陷类型mAP0.5 健康阈值触发动作根本原因优先级压痕crush≥ 0.85检查相机清洁度、光源稳定性1硬件老化撕裂tear≥ 0.88检查装盒机推杆压力传感器2机械偏差烫金脱落foil≥ 0.80立即重训模型同步检查覆膜工艺参数3材料变更封口歪斜seal≥ 0.85检查封口机伺服电机编码器1硬件老化从那以后我每次部署新模型都强制走一遍python tools/monthly_check.py生成首期基线并把reports/health_monthly.csv加入 Git 跟踪——不是为了 show而是当产线主管问“模型还灵不灵”时我能直接甩出过去 6 个月的趋势图而不是凭感觉说“应该没问题”。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →