ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

轮胎缺陷检测实战:从YOLOv8训练到TensorRT产线部署的Python源码实现

轮胎缺陷检测实战:从YOLOv8训练到TensorRT产线部署的Python源码实现 简介这份资源面向计算机视觉方向的本科毕业生与深度学习入门者提供一套基于深度学习的轮胎磨损与缺陷检测完整Python实现可用于毕业设计选题、课程项目或算法练手。压缩包共34个文件约6.22MB以25个Python源码为主体辅以PNG效果图、JSON配置、TXT依赖说明与Markdown文档覆盖训练、测试、配置解析、日志记录等环节。代码按功能拆分为磨损检测与缺陷检测两条主线包含模型训练脚本、推理测试脚本、配置文件及可视化模块并附有README说明整体流程便于读者快速理解项目结构与运行方式。目前已有144人学习下载适合希望掌握工业缺陷检测落地思路、需要可运行参考代码的读者可在此基础上替换数据集、调整网络结构或迁移到其他表面缺陷检测任务中。1. 轮胎缺陷检测为什么总在胎侧翻车从一份毕业设计源码说起轮胎缺陷检测这件事真正做过产线的人都知道难点从来不在能不能识别出缺陷而在胎侧那道弧形反光到底算不算缺陷。我见过太多团队拿着公开数据集训出 99% 准确率一上产线就崩原因就一个实验室里拍的是平面样本产线上拍的是带曲率、带反光、带帘线纹理的黑色橡胶。这份毕业设计标题里的高效轮胎磨损缺陷检测算法实现 python 源码本质上要解决的就是把深度学习从干净数据集搬到这种脏场景里的落地问题。它适合三类人一是做毕业设计、需要一套能跑通、能改、能写进论文的完整 pipeline 的学生二是刚转深度学习、想找一个工业缺陷检测真实案例练手的工程师三是产线侧做视觉方案、想评估深度学习到底能不能替代传统 OpenCV 阈值法的技术负责人。整篇文章我会按数据怎么造 → 模型怎么选 → 训练怎么调 → 部署怎么快 → 坑在哪这条线讲透代码全部可复现参数全部给区间不玩虚的。2. 轮胎缺陷检测的数据集构建从 OpenCV 预处理到 YOLO 格式转换2.1 为什么轮胎缺陷检测不能直接用公开数据集公开的缺陷检测数据集比如 NEU-DET 钢材缺陷、MVTec AD它们的成像条件是受控的固定光源、固定距离、固定背景。轮胎不一样胎侧是弧形黑色橡胶表面有帘线纹理、有模具编号、有硫化痕迹这些在传统阈值法里全是疑似缺陷。我一般会先做一件事把原始图像做一次局部对比度增强让缺陷和背景的灰度差拉开再送进网络。这一步不做后面模型再深也白搭。轮胎缺陷大致分四类胎侧鼓包bulge、胎面磨损wear、裂纹crack、异物嵌入foreign object。磨损是回归问题磨损程度其余三类是检测问题定位分类。毕业设计里常见做法是统一成检测任务用边界框标出来磨损用框的宽度占比来近似程度。这个简化在论文里要写清楚不然答辩会被问。2.2 用 OpenCV 做 CLAHE 增强与 ROI 裁剪轮胎图像里真正有信息的区域只占 40% 左右四周是背景和轮毂。先裁 ROI 再增强能省一半训练时间。import cv2 import numpy as np def preprocess_tire(img_path, clip_limit2.0, tile_grid(8, 8)): 轮胎图像预处理ROI 裁剪 CLAHE 局部对比度增强 clip_limit: 对比度限制轮胎场景建议 1.5~3.0太高会放大帘线纹理 tile_grid: 分块大小8x8 适合 640x640 输入 img cv2.imread(img_path) h, w img.shape[:2] # 裁掉上下各 15% 的背景保留胎侧主体 roi img[int(h * 0.15):int(h * 0.85), int(w * 0.1):int(w * 0.9)] # 转 LAB只对 L 通道做 CLAHE避免色偏 lab cv2.cvtColor(roi, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimitclip_limit, tileGridSizetile_grid) l_eq clahe.apply(l) merged cv2.merge((l_eq, a, b)) out cv2.cvtColor(merged, cv2.COLOR_LAB2BGR) return out if __name__ __main__: result preprocess_tire(tire_001.jpg) cv2.imwrite(tire_001_clahe.jpg, result)逻辑说明先裁 ROI 是因为轮胎图像的有效信息集中在胎侧中段上下边缘是轮毂和地面送进网络只会引入噪声。转 LAB 再对 L 通道做 CLAHE是因为直接在 BGR 上做直方图均衡会改变颜色而轮胎缺陷的颜色信息比如鼓包偏暗、异物偏亮是有用的。clip_limit这个参数是血泪经验设到 4.0 以上帘线纹理会被放大成假裂纹模型直接学偏。参数说明clip_limit建议 1.5~3.0胎面磨损场景可以取 2.5胎侧裂纹取 1.8tile_grid在 640 输入下用 8x8在 1280 输入下用 16x16块太小会引入块状伪影。2.3 标注格式转换从 LabelImg 的 XML 到 YOLO 的 TXT毕业设计里最容易被忽略的一步是格式转换。LabelImg 存的是 Pascal VOC 的 XMLYOLO 要的是归一化后的 TXT。转换脚本写错一个坐标训练 loss 会正常下降但 mAP 永远是 0这个坑我踩过。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_dir, out_dir, classes): 将 VOC XML 转为 YOLO TXT classes: 类别列表顺序必须和训练时 data.yaml 一致 os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # YOLO 格式中心点 宽高全部归一化到 0~1 cx (x1 x2) / 2.0 / w cy (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) txt_name xml_file.replace(.xml, .txt) with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) if __name__ __main__: voc_to_yolo(./annotations, ./labels, [bulge, wear, crack, foreign])逻辑说明YOLO 的坐标是归一化的中心点格式不是左上右下。cx (x1x2)/2/w这一步如果写成x1/w训练时模型会学到偏移的框表现为预测框整体偏左上。类别顺序必须和data.yaml里的names完全一致否则会出现框对了但类别全错的玄学现象。参数说明classes列表顺序一旦确定就不能改改了就重新训练归一化保留 6 位小数足够再多是浪费。2.4 数据增强轮胎场景该用哪些、不该用哪些轮胎缺陷检测的数据增强有禁区。水平翻转可以用因为胎侧左右对称垂直翻转不能用因为轮胎上下纹理方向不同翻了就是假样本。Mosaic 增强可以用但mosaic1.0会让小缺陷被拼没建议 0.5。HSV 增强里h通道要关掉轮胎是黑色色相变化没意义还引入噪声。增强方式建议参数原因水平翻转0.5胎侧左右对称安全垂直翻转0上下纹理方向不同禁用Mosaic0.5太高会丢失小缺陷HSV-H0黑色橡胶无色相信息HSV-V0.3模拟产线光照波动旋转±10°超过 15° 会出现黑边3. 模型选型YOLOv8 还是 RT-DETR轮胎缺陷检测该怎么选3.1 两类模型的本质差异YOLOv8 是单阶段 anchor-free 检测器速度快适合产线实时RT-DETR 是 Transformer 架构的端到端检测器不需要 NMS 后处理小目标召回更好。轮胎缺陷里裂纹和异物属于小目标鼓包和磨损属于大目标。如果你的数据集里小目标占比超过 30%RT-DETR 的召回率会明显高于 YOLOv8如果追求推理速度产线要求 30 FPS 以上YOLOv8n 或 YOLOv8s 更稳。我一般会这样选毕业设计场景优先 YOLOv8s因为生态成熟、教程多、改起来快如果论文要体现创新点用 RT-DETR 做对比实验两个都跑用数据说话。热搜里提到的基于 RT-DETR 的手机屏幕缺陷检测就是这个思路屏幕缺陷和轮胎裂纹在形态上有相似性都是细长小目标可以借鉴。3.2 YOLOv8 训练配置与关键参数from ultralytics import YOLO # 加载预训练权重轮胎数据集小必须用预训练 model YOLO(yolov8s.pt) results model.train( datatire.yaml, # 数据集配置 epochs150, # 轮胎数据 100~200 足够再多过拟合 imgsz640, # 输入尺寸小目标多可上 960 batch16, # 显存 8G 用 812G 用 16 lr00.01, # 初始学习率 lrf0.01, # 最终学习率 lr0 * lrf momentum0.937, weight_decay0.0005, warmup_epochs3.0, # 预热防止早期梯度爆炸 mosaic0.5, # 轮胎场景降到 0.5 fliplr0.5, # 水平翻转 flipud0.0, # 垂直翻转必须关 hsv_h0.0, # 色相关闭 hsv_v0.3, # 亮度增强 patience30, # 30 轮不涨就早停 device0 )逻辑说明lr00.01是 YOLOv8 的默认值但轮胎数据集如果小于 2000 张建议降到 0.005否则早期 loss 震荡。warmup_epochs3.0不能省黑色橡胶图像梯度大不预热容易在第一个 epoch 就发散。patience30是后悔药轮胎数据标注噪声大模型可能在 80 轮后突然涨点早停太早会错过。参数说明imgsz从 640 提到 960小目标召回能涨 5~8 个点但推理速度降一半产线要权衡batch受显存限制显存不够就降 batch 同时把lr0按比例降。3.3 RT-DETR 的对比实验配置from ultralytics import RTDETR model RTDETR(rtdetr-l.pt) model.train( datatire.yaml, epochs120, imgsz640, batch8, # Transformer 显存占用高 lr00.0001, # DETR 系列学习率要小 weight_decay0.0001, device0 )逻辑说明RT-DETR 的学习率比 YOLO 小一个数量级用 0.01 会直接不收敛。batch8是因为 Transformer 的注意力机制显存占用是 CNN 的 2~3 倍。RT-DETR 不需要 NMS后处理代码可以省掉但推理速度在同等精度下比 YOLOv8 慢 30% 左右。参数说明lr00.0001是 RT-DETR 的推荐值数据集小可以到 0.00005epochs120是因为 DETR 系列收敛慢但轮胎数据 120 轮足够。4. 训练过程排查loss 不降、mAP 为 0、过拟合的实战处理4.1 loss 正常下降但 mAP 恒为 0现象训练日志里box_loss、cls_loss都在降但验证集mAP50一直是 0。原因90% 是标注格式问题。要么是类别 ID 从 1 开始YOLO 要求从 0要么是坐标没归一化要么是data.yaml里的names顺序和标注不一致。解决先跑一遍官方校验脚本yolo checks会检查数据集配置再随机抽 5 张图用cv2.rectangle把 TXT 里的框画回原图肉眼确认框位置对不对。这一步花 10 分钟能省一天。4.2 训练到 50 轮后 mAP 突然掉现象前 50 轮 mAP 稳步上升50 轮后突然掉 10 个点loss 反而降。原因过拟合。轮胎数据集如果小于 1500 张模型在 50 轮左右就记住了训练集验证集开始崩。解决加数据增强Mosaic 提到 0.7、加dropoutYOLOv8 在model.yaml里改、或者直接早停。我一般会在 50 轮时保存一个 checkpoint掉了就回滚。4.3 小缺陷裂纹、异物召回率低现象鼓包和磨损检测很好裂纹和异物漏检严重。原因小目标在 640 输入下只有几个像素特征图下采样后信息丢失。解决把imgsz提到 960 或 1280或者在model.yaml里把 P3 层的检测头权重调高再不行就切片推理SAHI把大图切成小图分别检测再合并。4.4 推理速度达不到产线要求现象模型精度够但单张推理 200ms产线要求 30ms。原因模型太大或输入分辨率太高。解决换 YOLOv8nimgsz降到 416用 TensorRT 或 ONNX Runtime 加速。TensorRT 在 NVIDIA 显卡上能提速 3~5 倍但转换时要注意 opset 版本YOLOv8 建议 opset 12。4.5 不同批次图像亮度差异导致误检现象白天拍的图检测正常晚上拍的图全是误检。原因产线光照不稳定模型学到了亮度和缺陷的伪相关。解决训练时加hsv_v0.5的亮度增强让模型对亮度不敏感推理前做一次直方图匹配把当前图对齐到训练集的平均亮度。5. 从训练到部署ONNX 导出、TensorRT 加速与产线集成5.1 ONNX 导出与校验from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.export( formatonnx, imgsz640, opset12, # YOLOv8 建议 12 simplifyTrue, # 简化计算图 dynamicFalse # 固定 batch产线用 )逻辑说明opset12是兼容性最好的版本opset 17 在部分 TensorRT 版本上会报错。simplifyTrue会用 onnx-simplifier 去掉冗余节点推理快 5~10%。dynamicFalse固定输入尺寸TensorRT 能更好地优化。参数说明imgsz必须和训练时一致不一致精度会掉opset如果部署到 Jetson用 11 更稳。5.2 TensorRT 加速与 FP16 量化trtexec --onnxbest.onnx \ --saveEnginebest.engine \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x640x640 \ --optShapesimages:1x3x640x640 \ --maxShapesimages:1x3x640x640逻辑说明--fp16开启半精度速度提升约 2 倍精度掉 0.5 个点以内轮胎检测可以接受。--workspace4096是 4G 显存工作区太小会编译失败。min/opt/maxShapes三个都设成一样因为产线 batch 固定为 1。参数说明如果精度要求高去掉--fp16用 FP32速度慢但精度无损workspace根据显卡显存调8G 卡设 2048。5.3 产线集成从图像采集到结果输出产线集成的核心是流水线设计。我一般用生产者-消费者模式一个线程负责从相机抓图一个线程负责推理一个线程负责结果输出和报警。推理线程用 TensorRT 的 Python API单张 640 输入在 RTX 3060 上约 8ms加上前后处理约 15ms满足 30 FPS。import pycuda.driver as cuda import tensorrt as trt import numpy as np class TRTInfer: def __init__(self, engine_path): self.logger trt.Logger(trt.Logger.WARNING) with open(engine_path, rb) as f, trt.Runtime(self.logger) as runtime: self.engine runtime.deserialize_cuda_engine(f.read()) self.context self.engine.create_execution_context() # 分配输入输出显存 self.inputs, self.outputs, self.bindings [], [], [] for i in range(self.engine.num_bindings): shape self.engine.get_binding_shape(i) dtype trt.nptype(self.engine.get_binding_dtype(i)) size int(np.prod(shape)) host cuda.pagelocked_empty(size, dtype) device cuda.mem_alloc(host.nbytes) self.bindings.append(int(device)) if self.engine.binding_is_input(i): self.inputs.append({host: host, device: device, shape: shape}) else: self.outputs.append({host: host, device: device, shape: shape}) def infer(self, img): np.copyto(self.inputs[0][host], img.ravel()) cuda.memcpy_htod(self.inputs[0][device], self.inputs[0][host]) self.context.execute_v2(self.bindings) cuda.memcpy_dtoh(self.outputs[0][host], self.outputs[0][device]) return self.outputs[0][host].reshape(self.outputs[0][shape])逻辑说明TensorRT 的推理分三步——host 到 device 拷贝、执行、device 到 host 拷贝。pagelocked_empty分配锁页内存比普通内存快 2~3 倍。execute_v2是同步执行产线要异步的话用execute_async_v2加 CUDA stream。参数说明engine_path是上一步 trtexec 生成的.engine文件输入 shape 必须是1x3x640x640和导出时一致。6. 轮胎缺陷检测的进阶技巧切片推理与置信度阈值动态调整6.1 切片推理SAHI解决小目标漏检裂纹和异物在整图里可能只占 20x20 像素640 输入下下采样 32 倍后只剩不到 1 个像素模型根本看不到。切片推理的思路是把 1920x1080 的原图切成 6 块 640x640 的小图分别推理再合并。代价是推理时间翻 6 倍但小目标召回能从 60% 提到 85% 以上。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathbest.pt, confidence_threshold0.25, devicecuda:0 ) result get_sliced_prediction( tire_001.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, # 20% 重叠防止缺陷被切断 overlap_width_ratio0.2 ) result.export_visuals(export_dir./vis)逻辑说明overlap_ratio0.2是关键太小缺陷会被切在边界上太大推理时间浪费。SAHI 会自动做 NMS 合并不用手写。confidence_threshold0.25比常规的 0.5 低因为切片后每块图里缺陷占比大置信度天然偏高阈值可以降。参数说明slice_height/width建议等于训练时的imgszoverlap_ratio0.2~0.3缺陷越小重叠越大。6.2 置信度阈值的动态调整固定阈值 0.5 在轮胎场景不适用。鼓包特征明显0.5 够裂纹特征弱0.5 会漏。我一般按类别设不同阈值鼓包 0.5、磨损 0.4、裂纹 0.25、异物 0.3。这个值不是拍脑袋是在验证集上画 P-R 曲线取 F1 最大点。缺陷类别建议阈值调整依据鼓包0.50特征明显高阈值降误检磨损0.40边界模糊中等阈值裂纹0.25特征弱低阈值保召回异物0.30形态多样中等偏低6.3 一个我踩过的坑模型在验证集上很好产线上全是误检这个坑我花了三天才定位。验证集用的是标注过的干净图产线图里有大量没标注的疑似缺陷——帘线接头、模具编号、硫化痕迹。模型在验证集上没见过这些产线上全报成缺陷。解决办法是在训练集里加入 200 张负样本有这些纹理但无缺陷的图让模型学会区分。加完之后误检率从 15% 降到 3%。这件事给我的教训是缺陷检测的瓶颈从来不在模型结构而在数据分布。你验证集再干净产线不干净就是白搭。我现在的习惯是任何缺陷检测项目先花一周时间蹲产线把各种看起来像缺陷但不是的样本收集齐再开始标数据。这个习惯帮我省了无数次返工。希望帮到你。本文还有配套的精品资源点击获取
返回列表