ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于YOLOv8的热轧带钢表面缺陷检测系统从训练到部署

基于YOLOv8的热轧带钢表面缺陷检测系统从训练到部署 简介基于YOLOv8的热轧带钢表面缺陷检测毕业设计资源面向工业视觉开发者、研究人员及学生旨在解决生产线中划痕、压痕、裂纹等表面缺陷依赖人工检测、效率与稳定性不佳的问题。压缩包共2000个文件以Python/C源码、YAML模型配置、TXT标注数据和MD教程文档为主体整体仅74.49MB目录划分清晰便于按数据、模型、训练和部署模块检索。已有82人加入学习。资源除完整可运行的源码和带标注的数据集外还配有详细使用教程涵盖数据预处理、模型训练、性能评估、后处理以及生产线部署等关键环节。借助该套件使用者可快速搭建一套基于YOLOv8的热轧带钢缺陷检测系统深入掌握深度学习在工业质检中的落地流程也为毕业设计或工程实践提供可靠参考。1. 热轧带钢表面缺陷检测为什么值得用YOLOv8重做一版热轧带钢的生产线速度通常在每秒十米以上表面缺陷如果靠人工肉眼盯屏幕两小时就会进入视觉疲劳期漏检率明显上升。传统的机器视觉方案用的是固定阈值加形态学滤波对光照变化和钢材表面的氧化皮纹理非常敏感换一卷钢就要重新调参数。深度学习检测模型把这件事简化成了两个步骤输入图像输出缺陷的类别和位置框。YOLOv8在COCO上的推理速度和精度平衡已经被大量落地项目验证过而它在工业检测场景里真正让我满意的点是Anchor-Free设计省掉了聚类锚框的步骤以及C2f结构让特征复用更充分小目标比如细划痕、小麻点的召回率比之前几个版本明显好。这套源码包解决的正是从零搭建热轧带钢缺陷检测系统的问题。它包含了完整的训练数据和标注、模型训练与推理的源码、以及一份能跟着走完整个流程的教程。对于要交毕业设计的学生来说最怕的不是训练模型而是数据收集和工程封装这些琐碎环节对于刚接触工业视觉的工程师这套结构也能作为改造自有产线检测方案的起点。本文从数据集构造写到模型训练参数再拆解源码包里的推理实现和部署方法最后给出几个实际调优时最容易踩的坑。2. 数据是工业检测的命门缺陷类型与标注格式的细节2.1 热轧带钢表面缺陷的六类典型特征热轧带钢表面缺陷数据集最常用的是东北大学发布的NEU-DET这套源码包里的数据集也沿用了同样的六类分类标准。轧制氧化铁皮rolled-in scale呈现为不规则的暗色压入块状常出现在精轧前段因为除磷不彻底导致划痕scratches是细长条状的灰度突变方向通常与轧制方向一致麻点patches是分散的暗色斑点密集时容易覆盖大面积区域斑块plaquette的灰度变化比麻点更重边界也相对清晰裂纹cracks是最轻微也最难检测的缺陷灰度对比度低形态细碎夹杂inclusion则表现为亮色或暗色的条状异物嵌入。这六类缺陷在成像上的灰度特性差异很大有些是暗目标在亮背景上比如氧化铁皮压入有些灰度范围与正常纹理几乎重叠比如裂纹。如果只用单阶段检测器而不做数据增强裂纹这一类的AP值通常会比氧化铁皮低十个百分点以上。标注时有一个容易被忽略的问题相邻缺陷之间的间距很小有些框会重叠或者贴在一起训练时如果使用普通的NMS策略这些密集目标在推理阶段容易被合并成一个检测框。标注时尽量保持框之间的最小间距对后续的检测效果有明显帮助。2.2 数据集目录结构与标注文件格式拿到源码包后先把数据目录结构调整成YOLO训练的标准形式。常见的目录组织结构如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── classes.txtYOLO格式的标注文件是每个图像对应一个同名txt文件放在labels目录下的对应子目录中每行包含一个目标的信息。每行五个数值含义按顺序是类别id从0开始、归一化后的中心点x坐标、归一化后的中心点y坐标、归一化后的框宽度、归一化后的框高度。归一化的分母是图像的宽和高坐标值范围在0到1之间。检查数据时我一般会写一段小脚本来验证标注的正确性避免因为个别标注文件格式错误导致训练中断import os from PIL import Image def verify_labels(img_dir, label_dir): for img_name in os.listdir(img_dir): stem os.path.splitext(img_name)[0] label_path os.path.join(label_dir, stem .txt) if not os.path.exists(label_path): print(f[缺失标注] {img_name}) continue img Image.open(os.path.join(img_dir, img_name)) w, h img.size with open(label_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f[格式错误] {label_path}: {line}) continue cls int(parts[0]) cx, cy, bw, bh map(float, parts[1:]) x1 (cx - bw / 2) * w y1 (cy - bh / 2) * h x2 (cx bw / 2) * w y2 (cy bh / 2) * h if x1 0 or y1 0 or x2 w or y2 h: print(f[越界] {label_path}: {line}) verify_labels(dataset/images/train, dataset/labels/train)这段代码的核心逻辑是遍历训练图像对每张图像的标注文件逐行解析然后把归一化坐标还原成实际像素坐标检查是否超出图像边界。标注框越界在手工标注的数据集中很常见尤其是靠近图像边缘的目标如果不加处理训练时边界框回归会不稳定。另外要注意data.yaml文件里的类别列表必须与标注文件中的类别id严格对应训练前先跑一遍这个脚本能省下不少排查时间。2.3 数据增强策略怎么配才不破坏工业图像语义热轧带钢表面图像与自然图像不同它的纹理方向有明确的物理含义。比如划痕的方向和轧制方向强相关如果使用随机的90度旋转增强会把横向划痕转成纵向这实际上是在制造错误样本。我一般会使用Mosaic增强配合小角度旋转和轻微的色彩抖动而关闭大角度旋转和上下翻转。裁剪和缩放比例也要控制缺陷区域占整幅图像的比例通常比较小过度的随机裁剪容易把缺陷裁掉一半。在源码包的使用教程中训练阶段的超参数配置直接写在配置文件中。以缺陷检测场景为例建议值是degrees设为10度以内scale设为0.5到1.5hsv_h和hsv_s可以适当增强来模拟不同轧制温度下的颜色变化但flipud也就是上下翻转对于水平辊道上的带钢来说物理意义不大关闭即可。验证集上不要做任何随机增强只用resize和归一化。3. YOLOv8模型结构拆解与训练参数设定3.1 从YOLOv5到YOLOv8C2f模块带来的特征提取变化YOLOv8的网络结构相比YOLOv5最大的改动是用C2f模块替换了C3模块。C3模块的路径是先将输入分支成两路一路经过若干Bottleneck另一路直接连接最后在末端concat。C2f在此基础上增加了更多的梯度分流路径每一层Bottleneck的输出都会参与后续的拼接操作这让梯度在反向传播时有更丰富的通路有利于深层网络训练时的梯度流动同时在不显著增加计算量的前提下提升了特征表达能力。Backbone部分延续了SPPF空间金字塔池化的结构在不同尺度上聚合特征。Neck部分仍然是PANet的路径聚合结构负责把高层语义信息与低层空间细节进行融合。Head部分则是YOLOv8最大的结构变化从YOLOv5的耦合检测头改成了解耦检测头分类分支和回归分支使用独立的卷积层这解决了分类和回归任务对特征关注点不同的问题。同时YOLOv8全面转向Anchor-Free每个位置只预测四个偏移量和一个旋转角度相关的目标描述减少了锚框超参数调优的工作量这对刚上手用YOLOv8训练自己数据集的时候特别友好。# 在源码包的配置目录中模型结构参数一般这样定义 # yolov8s.yaml 对应的参数部分节选 backbone: - [-1, 1, Conv, [64, 3, 2]] # downsampling, 输出 80x80 - [-1, 1, Conv, [128, 3, 2]] # downsampling, 输出 40x40 - [-1, 3, C2f, [128, True]] # 3个C2f层堆叠 - [-1, 1, Conv, [256, 3, 2]] # downsampling, 输出 20x20 - [-1, 6, C2f, [256, True]] - [-1, 1, Conv, [512, 3, 2]] # downsampling, 输出 10x10 - [-1, 6, C2f, [512, True]] - [-1, 1, Conv, [1024, 3, 2]] # downsampling, 输出 5x5 - [-1, 3, C2f, [1024, True]] - [-1, 1, SPPF, [1024, 5]]以YOLOv8s为例网络中下采样倍数分别是2、4、8、16、32最终特征图尺寸为输入图像的1/32。对于分辨率为640x640的输入三个检测头的输出尺度分别为80x80、40x40和20x20分别负责小、中、大目标的检测。在热轧带钢缺陷场景中划痕和裂纹这类细长缺陷主要靠80x80这个尺度的特征图来召回所以输入分辨率不要降得太低源码教程中默认使用640是合理的。3.2 训练命令与超参数的作用域使用源码包训练时最直接的方式是使用ultralytics的训练入口。训练前需要确认环境中的依赖版本torch版本建议1.8以上CUDA版本建议11.7以上源码包里的requirements.txt已经列出了所有需要的库。训练命令参考如下yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs200 \ imgsz640 \ batch16 \ device0 \ workers8 \ optimizerAdamW \ lr00.001 \ lrf0.01 \ momentum0.937 \ weight_decay0.0005 \ warmup_epochs3 \ close_mosaic10参数含义逐一说清楚。imgsz指训练时的输入分辨率640是最稳妥的选择如果显卡显存足够且希望更好检测细小裂纹可以提升到960但训练时间会增加约一倍。batch受显卡显存限制16G显存跑YOLOv8s批量大小16没问题显存不够就降到8。optimizerAdamW对缺陷检测这类数据集规模不算大的场景收敛更稳但最终精度可能和SGD相差不大。lr0是初始学习率lrf是最终学习率与初始学习率的比值配合warmup_epochs3做一个线性预热。close_mosaic10表示最后10个epoch关闭Mosaic增强这很重要因为Mosaic生成的合成图像与真实分布有偏差最后几个epoch用纯真实图像让模型适应真实数据分布能避免最终AP出现波动。3.3 训练日志的判读与早停判断训练过程中要盯住两个指标box_loss和cls_loss在验证集上的变化趋势。如果box_loss持续下降而cls_loss震荡上升说明模型在过拟合此时patience参数会自动触发早停但更可靠的办法是定期保存验证集上mAP50最高的权重。YOLOv8默认的save_period参数是-1也就是只在最后一次迭代保存建议改成10因为训练过程中间结果对调参有参考价值。yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs300 \ imgsz640 \ batch16 \ seed42 \ save_period10 \ cacheTruecacheTrue会把图像加载到内存中加速每个epoch的数据读取对于千张级别的数据集训练时间能缩短20%左右。种子参数seed42保证实验可复现改网络结构或调超参数时固定随机种子才能准确比较不同修改变量的影响。另外数据增强是每个epoch动态生成的固定种子后增强序列也会固定对比实验更公平。4. 源码包推理链路解析从权重到生产可用的检测结果4.1 inference.h与inference.cpp的接口设计源码包中的推理代码用C实现这贴合工业部署场景。Python模型的性能在生产环境中受GIL限制而且部署时需要额外的Python运行时C推理接口则可以直接嵌入PLC控制的质检工位程序。inference.h头文件声明的核心接口通常如下// inference.h 关键接口 #pragma once #include opencv2/opencv.hpp #include vector struct DetectionResult { int class_id; float confidence; cv::Rect bbox; }; class YOLOv8Inference { public: YOLOv8Inference(const std::string engine_path, const cv::Size input_size); ~YOLOv8Inference(); std::vectorDetectionResult infer(const cv::Mat image); private: void preprocess(const cv::Mat image, float* buffer); void postprocess(float* output, std::vectorDetectionResult results); void* engine_ nullptr; // TensorRT engine void* context_ nullptr; cv::Size input_size_; };这个类是典型的单模型推理封装。构造函数接受TensorRT引擎文件路径和输入尺寸infer方法接收一张OpenCV的Mat图像返回检测结果列表。注意postprocess内部需要实现置信度阈值过滤和NMS非极大值抑制。工业场景中阈值建议设置为conf_thres0.4、iou_thres0.5这个组合在缺陷检测中能平衡漏报和误报。如果要更激进地追求召回率可以把conf_thres降到0.25但随之而来的是更多的误检框后续如果要按PLC信号联动误检框会导致频繁误报警。4.2 preprocess里的letterbox与归一化细节preprocess函数的核心是letterbox操作。YOLOv8训练时代对输入图像做了等比缩放和灰色填充推理时也必须做相同的操作否则检测精度会明显下降。具体做法是计算缩放比例使图像长边缩放到640短边按相同比例缩放不足的部分用114这个灰度值填充。这里的114是COCO数据集的平均像素值也是训练时的默认填充值。如果加载的模型是用自定义数据集训练的建议检查训练配置中的pad参数保持一致。以下是一个完整的C预处理实现void YOLOv8Inference::preprocess(const cv::Mat image, float* buffer) { cv::Mat resized; float r std::min(input_size_.width / (float)image.cols, input_size_.height / (float)image.rows); int new_w (int)(image.cols * r); int new_h (int)(image.rows * r); cv::resize(image, resized, cv::Size(new_w, new_h), 0, 0, cv::INTER_LINEAR); cv::Mat canvas(input_size_.height, input_size_.width, CV_8UC3, cv::Scalar(114, 114, 114)); resized.copyTo(canvas(cv::Rect((input_size_.width - new_w) / 2, (input_size_.height - new_h) / 2, new_w, new_h))); // BGR to RGB, HWC to CHW, 归一化到 [0, 1] for (int c 0; c 3; c) { for (int i 0; i input_size_.height; i) { for (int j 0; j input_size_.width; j) { int ch c 0 ? 2 : (c 1 ? 1 : 0); // BGR - RGB buffer[c * input_size_.height * input_size_.width i * input_size_.width j] canvas.atcv::Vec3b(i, j)[ch] / 255.0f; } } } }这段代码有两个值得注意的细节。第一letterbox等比缩放后原图并没有被拉伸变形等比操作保留了缺陷的长宽比这对后续恢复检测框坐标至关重要。第二BGR to RGB的通道转换是OpenCV读图与PyTorch训练时数据加载顺序不一致带来的必要适配漏掉这一步会导致检测结果全面漂移且难以排查。4.3 ONNX导出与TensorRT加速部署在C环境调用PyTorch权重不现实标准流程是先导出为ONNX再转TensorRT引擎。导出命令yolo export modelbest.pt formatonnx opset12 simplifyTrue tensorrt_engine trtexec --onnxbest.onnx --saveEnginebest.engine --fp16opset12是兼容性与算子支持的良好折中。simplifyTrue会移除计算图中的冗余节点让TensorRT转换时更容易做层融合。--fp16开启半精度推理在T4及以上显卡上速度可提升约两倍检测精度损失通常在0.5%以内对于缺陷检测这类目标对比度差异大的场景FP16带来的误差影响可以忽略。这里有一个容易踩的坑如果训练时的imgsz设为960导出模型时需要用--imgsz 960指定否则导出模型接受的输入尺寸是默认的640推理时letterbox到960的输入会被强制resize到640长宽比就破坏了。源码包教程中建议训练、导出、转换三步都使用同一输入尺寸这是保证部署后精度不下降的关键前提。5. 评估曲线、混淆矩阵与现场调优的三个快速手段5.1 用val模式跑出完整评估报告训练完成后不要只看验证集最后一批次的结果。用测试集独立评估才能反映模型真实泛化能力yolo detect val \ modelruns/detect/train/weights/best.pt \ datadataset/data.yaml \ splittest \ batch32 \ conf_thres0.001 \ iou_thres0.6conf_thres0.001是为了绘制完整的PR曲线如果使用默认的0.25生成的PR曲线会截断低置信度区间mAP值虚高。splittest明确指定评估集为test目录而不是默认的val目录。评估完成后结果目录下会有混淆矩阵图片和曲线这些比单看一个mAP数值更能反映模型在六类缺陷上的真实表现。混淆矩阵的判读重点看两点裂纹类是否大量被预测为背景这表示小目标漏检严重氧化铁皮与麻点之间是否互相混淆这说明特征区分度不够。前者通过提高输入分辨率缓解后者需要通过增加样本量或者调整损失函数中的类别权重来解决。5.2 现场推理置信度阈值和NMS阈值的联动调节在实际产线部署中模型权重只是系统的一半阈值设置才是影响用户体验的关键。置信度阈值conf_thres控制哪些框会被输出NMS阈值iou_thres控制重叠框的合并策略。两者通常是联动的conf_thres设得低会产生大量低质量候选框此时如果iou_thres设得高重叠的框不会被合并导致同一个缺陷输出多个框视觉上表现为重复报警iou_thres设太低紧挨着的两个真实缺陷会被错误合并成一个框。对于热轧带钢表面缺陷我建议先用conf_thres0.25和iou_thres0.5跑出一批测试图观察输出框的质量分布再根据实际误报和漏报的占比微调。如果现场允许偶尔的误报而不允许漏报就走低阈值路线如果报警后需要人工复核尽量走高阈值减少干扰。5.3 训练中途发现损失不降时的排查路径训练到第30个epoch如果损失曲线还是一条水平线按顺序检查以下三个点。第一检查data.yaml中path路径是否写成绝对路径换机器后路径失效会导致数据集加载为空模型在空数据上训练损失自然不降。第二查看标注类别数量与nc参数是否一致nc默认是80如果自定义数据集是6类而忘了改训练时类别标签会越界报错或静默错误。第三检查学习率lr0如果大于0.01对于YOLOv8s在小型数据集上很容易发散AdamW场景下0.001是一个相对安全的起点。第三个快速手段是直接使用源码包训练好的best.pt在测试集上跑几张图用可视化结果判断问题出在训练还是推理链路yolo predict modelruns/detect/train/weights/best.pt sourcetest_images/ saveTrue conf0.25如果保存的检测图上框的位置和类别明显不对基本可以确定是训练数据或者模型参数的问题如果检测图输出正常但与现场工况不符问题出在数据分布差异需要采集现场图像补充到训练集里做增量训练。本文还有配套的精品资源点击获取
返回列表