
简介基于YOLOv8的热轧带钢表面缺陷检测源码与配套数据集包面向深度学习初学者、工业视觉开发者及钢铁质检场景解决带钢表面横向裂缝、纵向裂缝、龟裂、坑槽、修补网状裂缝等典型缺陷的自动识别问题。包内共2000个文件以txt标注/说明、md教程笔记、py训练与推理脚本为主另含cpp/h工程文件、yaml配置与html文档压缩包约74.49MB目录结构便于对照学习。目前已有841人学习下载。内容包含完整源码、标注数据集及详细使用教程覆盖环境配置、数据预处理、YOLOv8模型训练、参数调优、推理测试与mAP/召回率评估等关键环节并针对常见问题给出排错思路可直接复现热轧带钢表面缺陷检测流程适合用于项目实战、课程设计与科研入门。1. 热轧带钢表面缺陷检测为什么难yolov8在这个场景到底解决什么热轧带钢从精轧机出来时表面温度高、运行速度快氧化铁皮、裂纹、麻点、划伤、辊印、夹杂这些缺陷混在金属本身的纹理里传统机器视觉靠灰度阈值和形态学只能应付“深色背景上的亮色划痕”这类简单场景一遇到光照变化和氧化铁皮底色就疯狂误报。基于yolov8的热轧带钢表面缺陷检测把问题重新定义为“在图像里同时定位缺陷和判断类别”不再依赖人工设计的特征而是让模型自己学习缺陷的纹理、形状和对比度规律这是它能在这个场景落地的主要原因。这篇笔记按数据准备、训练、验证、部署、避坑依次展开适合刚拿到带钢缺陷源码包正准备跑训练的工程师也适合想评估yolov8在工业质检方向值不值得投入的算法朋友。我把实操中踩过的坑直接标注在对应章节照着做能省掉不少调试时间。2. 热轧带钢缺陷检测的数据准备六类缺陷与yolov8的数据集格式2.1 为什么选yolov8而不是传统视觉方案热轧带钢表面的难点在于“背景本身就是纹理”。钢板经过精轧之后表面有细密的轧制纹路、深浅不一的氧化铁皮、水渍反光传统的阈值分割和边缘检测在这种背景下会把轧制纹路当缺陷也会把真正的细小裂纹漏掉。做这类项目我一般不会花时间调形态学参数直接上目标检测模型更可控这也符合当前工业质检的主流做法。yolov8相比yolov5的几个重要改动值得了解骨干网络换成了C2f结构颈部用PAN-FPN做多尺度融合检测头改成了anchor-free的解耦头。对带钢缺陷这种尺度差异很大的场景anchor-free意味着不用像yolov5那样先聚类算anchor尺寸模型对小目标的位置回归更直接。配合ultralytics的完整训练、导出、部署生态从训练到ONNX再到板端推理链路都比自己拼装代码省事。选型上给一个经验参考带钢产线如果要实时检测优先yolov8n或yolov8s帧率压力大的时候用n离线抽检或复判阶段用yolov8m已经足够。我的原则是先用小模型把流程跑通再根据精度缺口决定是否换更大的模型不要一上来就用l或xCPU机器上损失的是时间。2.2 先理清六类缺陷数据集目录与steel_defect.yaml怎么写做热轧带钢表面缺陷检测数据几乎决定上限。常见公开的带钢缺陷数据集会把缺陷分为六类裂纹、夹杂、斑块、麻点、氧化铁皮、划伤。这六类的视觉特征差别很大裂纹是细长的暗色线状夹杂通常成片出现且边缘不规则斑块是大面积灰度变化麻点是密集的微小点状氧化铁皮是深浅不一的块状压入划伤是方向一致的亮色细线。拿到一份源码包或自己整理数据时我建议先按这个结构放文件方便后面套yolov8训练脚本steel_defect/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── steel_defect.yamllabels目录下的每个txt文件与对应图片同名一行代表一个目标格式是“class_id x_center y_center width height”其中坐标和宽高都是相对于图片宽高的归一化值。steel_defect.yaml是yolov8的数据配置内容示例path: /path/to/steel_defect train: images/train val: images/val test: images/test names: 0: cracks 1: inclusion 2: patches 3: pitted_surface 4: rolled_in_scale 5: scratches这里name的顺序必须和标注文件里的class_id一一对应顺序错一个整个训练就白跑。我见过不止一次因为把“0”当成背景导致类别全串的情况yolov8的类别编号从0开始不是从1开始。2.3 把labelme/VOC标注转成yolov8格式的txt一个能直接跑的脚本大多数人在标注阶段用的不是labelimg就是labelme前者直接存txt后者存JSON。公开数据集里VOC格式的XML也很常见。提供一个VOC XML转yolov8 txt的脚本处理带钢缺陷这类数据时可以直接套用import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) txt_name os.path.basename(xml_path).replace(.xml, .txt) with open(os.path.join(out_dir, txt_name), w) as f: 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) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) classes [cracks, inclusion, patches, pitted_surface, rolled_in_scale, scratches] os.makedirs(labels, exist_okTrue) for xml_file in os.listdir(xmls): if x64.endswith(.xml): voc_to_yolo(os.path.join(xmls, xml_file), labels, classes)脚本的逻辑是把XML里的物体框坐标从“左上角右下角”转成“中心点宽高”再除以图片宽高做归一化。要注意的是缺陷类别名称必须与yaml里一致比如“rolled_in_scale”写成“scale”会导致类目缺失但脚本不报错。转换完一定要抽查几个txt确认坐标数值都在0到1之间出现大于1的值基本就是标注框越界需要回源头检查标签。2.4 mosaic和mixup在带钢数据上别全开增强参数怎么配yolov8默认开启mosaic增强把四张图拼成一张训练这个设计对小目标检测收益很大。但带钢缺陷有一个特殊情况拼图之后不同钢板的亮度和纹理被硬切在一起如果原图采样不够模型很容易学到“拼接缝”这种伪特征而不是真正的缺陷纹理。我处理带钢数据时一般保留mosaic但降低强度并且在最后十个epoch把它关掉因为这个阶段模型需要在接近真实分布的图上精修。mixup类似它把两张图按透明度叠加适合缺陷颜色分布多样的场景但叠得太狠会让细小划痕和麻点变得模糊。如果原始数据集里小缺陷占比高建议把mixup关掉否则小目标的学习信号会被稀释。参数配置直接写在训练命令里yolo detect train ... mosaic0.5 mixup0.0 close_mosaic10这个配置的含义是mosaic概率降到0.5mixup关闭训练最后10个epoch不启用mosaic。具体数值可以按数据量调整数据量只有几百张时强化增强是必要的上千张时反而要减少合成噪声让模型多学真实分布。记住一点增强不是为了炫技是为了让模型在验证集和现场数据上都能用。3. 用yolov8训练自己的数据集从环境搭建到首次跑通3.1 ubuntu20.04搭建yolov8环境cpu版本与gpu版本的分岔路拿到一个带钢缺陷检测的源码包我建议先不要急着跑训练第一步打开目录看三样东西requirements.txt、数据处理脚本、数据yaml。很多所谓“跑不起来”的问题不在代码而是数据集路径、类别名、依赖版本对不上。环境搭建上ubuntu20.04是yolov8的常见运行环境。CPU版本的做法相对省事直接用conda建一个独立环境装ultralytics就行日常调试、验证小样本足够用conda create -n yolo python3.9 -y conda activate yolo pip install ultralytics pandas matplotlib pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu上面第二行pip命令是PyTorch官方的CPU轮子安装地址适用于没有NVIDIA显卡的机器。GPU版本的区别在于torch要装成CUDA版需要先确认驱动支持的CUDA版本再用对应cu版本安装。例如下命令会安装CUDA 12.1版本的torch常见于gtx1660ti、rtx 3060这类卡的场景pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121我在gtx1660ti这台6GB显存的老卡上跑yolov8n的结论是imgsz640、batch8可以跑跑yolov8m就会溢出。如果你的机器显存在8GB以下建议不要尝试大模型这不是代码问题是显存上限决定的。环境装好之后验证一下yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg这条命令会下载yolov8n预训练权重并跑一张示例图能顺利输出结果说明ultralytics环境已经就绪。3.2 最小训练命令从yolov8n起步六个参数先记住训练自己数据集的完整命令不复杂但每个参数都要知道为什么这么设。给一个我跑带钢缺陷数据时的基准命令yolo detect train \ modelyolov8n.pt \ datasteel_defect.yaml \ epochs100 \ imgsz640 \ batch16 \ optimizerAdamW \ lr00.01 \ lrf0.01 \ patience20 \ cacheTrue \ seed42逐个说参数model填yolov8n.pt表示加载预训练权重继续训练这比从空权重训练收敛快得多数据量不大时尤其明显。epochs先定100带钢缺陷特征比较集中通常训练到60到80轮mAP就趋于平稳再往后基本在浪费时间。imgsz640是平衡速度和精度的默认值带钢上的细小划痕在640尺度下可能只有几个像素如果显存允许可以试960但训练时间会翻倍。batch16是显存允许范围内的较大值batch太小会让梯度方向噪声变大、训练震荡optimizer我偏好AdamW尤其是小数据集上它比SGD更容易找到好局部解。lr0是初始学习率0.01是yolov8的默认起点如果loss爆了就降到0.001。lrf是学习率最终衰减到的比例0.01意思是结束时学习率是初始的百分之一。patience20表示20个epoch验证指标没有提升就自动早停这个机制在训练到瓶颈时能帮你省时间不用干等100轮。seed42固定随机种子让多次训练结果可对比排查问题时也能复现。cacheTrue会把数据集提前缓存到内存里第一次会慢之后再跑训练能省掉大量磁盘IO时间。CPU机器上缓存效果更明显但内存占用会增大8GB内存的机器建议改成cacheFalse。3.3 训练时怎么看loss曲线判断模型在学results.csv自绘损失曲线训练开始后ultralytics会在runs/detect/train目录下生成results.csv和results.png。很多人只看mAP我建议先看loss。loss曲线能帮你第一时间判断模型是不是真的在学理论上train/box_loss和train/cls_loss应该平滑下降val loss应该跟着下降并最终平稳。想画自己的损失曲线直接用results.csv里的数据import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns [c.strip() for c in df.columns] plt.figure(figsize(10, 6)) plt.plot(df[epoch], df[train/box_loss], labeltrain box loss) plt.plot(df[epoch], df[val/box_loss], labelval box loss) plt.legend() plt.savefig(loss_curve.png, dpi150)这段代码把每个epoch的box损失画成曲线可以直观比较训练集和验证集的差距。如果train/box_loss持续下降而val/box_loss先降后升说明模型开始过拟合对策是减少epochs、加大数据增强或换小模型。如果两边loss都在高位震荡不下降先怀疑学习率太大把lr0降到0.001再跑一轮次要看数据标注是不是有大量错误。loss是训练过程里最直接的黑匣子探针比盯着mAP等结果可靠得多。4. 验证与部署mAP怎么算、模型怎么上产线4.1 用best.pt跑验证集predict命令与输出文件说明训练结束后runs/detect/train/weights下会有best.pt和last.ptbest.pt是按验证集指标挑出来的最优权重后续验证和部署都用它。快速验证一批图片的推理命令yolo detect predict modelruns/detect/train/weights/best.pt \ sourcesteel_defect/images/test \ conf0.25 \ saveTrue \ save_txtTruepredict参数里只有source是必填conf是置信度阈值低于这个值的预测会被过滤掉。saveTrue把画了框的结果图存下来save_txtTrue把每个框的坐标和类别写入同名txt方便后面做统计分析。跑完注意看runs/detect/predict目录里的输出第一张开图最要紧确认画框位置是真实的缺陷而不是钢板边缘。这一步是性价比最高的模型体检如果常见缺陷能框出来位置基本贴边说明数据流程没问题如果框得乱七八糟先不要调参数回头检查数据集和标注。4.2 哪些指标对工业质检有用分类别AP和混淆矩阵的读法验证命令是yolo detect val modelruns/detect/train/weights/best.pt datasteel_defect.yaml它会输出mAP0.5、mAP0.5:0.95、precision、recall以及每个类别的AP。带钢缺陷检测里我建议优先看mAP0.5因为这个指标只要求预测框和真实框IoU达到0.5就算命中对细长裂纹这种天生IoU难算高的目标更宽容。mAP0.5:0.95通常数值偏低不代表模型不能用把它理解为更苛刻的定位要求更合适。更重要的是分类别AP。六类缺陷里经常出现“裂纹AP很高麻点AP很低”的情况这时要单独把低AP类别拎出来看是漏检还是误检。混淆矩阵也一样如果模型总把划伤识别成裂纹说明这两类在特征空间里太接近解决方向是补充两类各自典型的样本而不是拼命调网络结构。工业场景里真正关心两个数漏检率对应recall误报率对应precision。质检员不会关心mAP小数点后几位他们只想知道“这块钢板到底有没有病”因此事后用测试集统计每一类的误报和漏报比看总指标更有价值。4.3 从PyTorch到ONNX再到RKNNrk3588部署的导出链路带钢产线的检测终端很少直接跑PyTorch现场常见平台是x86工控机或RK3588这类带NPU的板卡。yolov8导出ONNX的命令yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 imgsz640imgsz必须和训练时的输入尺寸一致否则导出后推理尺寸不匹配。如果部署端需要动态batch可以在导出参数里加dynamicTrue但RK3588上的RKNN转换工具对动态shape支持有限建议固定640分辨率导出最省事。ONNX拿到手之后先在onnxruntime上跑一遍推理确认输出与best.pt结果基本一致再做RKNN转换。这个过程最常见的坑是模型里带了不支持的算子比如某些注意力模块在RKNN里不支持解决思路是回退到yolov8n这种结构简单的模型而不是硬改转换工具。5. 带钢缺陷检测避坑手册五个翻车现场与后悔药5.1 现象train loss不降反升训练到第二个epochtrain/box_loss没有下降反而震荡甚至升高。最常见的原因是学习率太大尤其在小数据集上AdamW搭配默认的0.01对于几百张图可能过于激进。第二个原因是数据集路径错误导致图片和标签没有对齐模型等效于在随机猜测。解决办法是先确认labels目录里每个txt都有对应图片然后查看训练时打印的“training images”数量是否和预期一致再把lr0降到0.001或0.005重跑几个epoch观察loss。如果loss仍然不降从train_batch*.jpg里看增强后的图里有没有正确画出框这一步能当场暴露标签错位。5.2 现象验证集mAP不错现场误报一堆测试集mAP0.5到了0.9但产线现场灰度图一上来就满屏误报。原因是数据分布不一致公开数据集或实验室图片里钢板表面光照均匀现场工业相机下反光、水渍、氧化铁皮底色都在干扰模型。解决方向是两个一是收集现场真实图像加入训练集让模型见过现场的光照分布二是把现场推理的conf阈值从0.25往上调到0.4甚至0.5多测试几组看误报下降幅度。注意调阈值只是缓解如果想根治必须补现场数据这个没有捷径。5.3 现象细小麻点和划伤全部漏检模型对裂纹、斑块这类大目标检测良好但麻点和细小划伤的recall接近零。因为brago这类缺陷在原图里占比很小经过640输入和多次下采样后在深层特征图上只剩一两像素的响应难以被检测头捡起来。解决思路从三个方向同时做把imgsz提升到960增加小目标像素数用切片推理对小图区域放大检测训练时把小缺陷图片单独重复采样缓解类别不平衡。如果这些做完小目标AP还是低再考虑换yolov8s等更大容量的模型但显存和速度成本也要评估。5.4 现象CPU机器训练慢到怀疑人生没有GPU的机器上训练带钢数据集跑100轮可能要几天时间。这不是资源浪费而是流程没设计好。先做两件事用yolov8n epochs30 imgsz320跑一个缩小版实验验证数据流程和代码链路是通的确认数据集缓存开启cacheTrue让图片预加载进内存减少磁盘读取开销。GPU机器的钱不该省但省下来的是用CPU反复试错的时间条件允许的话先用小规模云GPU实例验证效果再回到本地做最终训练。这个顺序能避免在CPU上熬一天之后才发现数据标签有问题。5.5 现象训练完发现部分图片标注错误等训练结束才在结果图里发现某一批图框错了位置这类问题最隐蔽也最伤时间。原因通常是多人标注时标准不一致或者标注工具导出时坐标偏移。这里有一个检查习惯很值得养成训练开始后每个epoch都会生成train_batch*.jpg花五分钟翻看这批增强图如果发现某张图的框明显贴错位置立即修正标注并删除对应图片或重新标注。还可以写一个简单脚本检查所有标签文件中坐标值是否都在0到1之间过滤掉宽高为零或超过图片边界的异常框。在训练前把数据清洗这一步做到位比事后反复训练省得多。6. 进阶用切片推理把麻点和细小划伤找出来并验证小目标AP是否提升6.1 切片推理的代码与参数如果你已经跑通基础流程但小目标缺陷还是漏检下一个性价比最高的动作是切片推理常见做法是配合sahi库使用。它的思路是把原图切成小块分别推理再把结果拼接起来相当于变相提高输入分辨率但不需要重训模型。安装和推理代码pip install sahifrom sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model AutoDetectionModel.from_pretrained( model_typeultralytics, model_pathruns/detect/train/weights/best.pt, confidence_threshold0.25, image_size640, devicecuda:0 ) result get_sliced_prediction( imagesteel_defect/images/test/xxx.jpg, detection_modelmodel, slice_size512, overlap_ratio0.2 ) result.export_visuals(export_diroutput_sliced/)slice_size决定切片边长对小目标我一般用512甚至256overlap_ratio是相邻切片的重叠比例设0.2可以避免缺陷恰好被切在边缘。代价是推理时间成倍增加一张640原图切成512的4块速度约为全图推理的4倍。所以在产线实时场景里切片推理适合离线复判、抽检和缺陷样本收集不适合直接放在高速主流程里。我的建议是先跑一批验证集比较切片推理和全图推理的分类别AP如果麻点和划伤的AP提升超过3个百分点就说明模型本身能力够了只是输入尺度限制了它。6.2 验证方法与我的一点习惯判别一个技巧值不值得投入最终要看验证集上的分类别AP变化。做法是先记录全图推理时每个类别的AP再记录切片推理后的AP两者对比只留下有提升的方案。我做过一次带钢表面检测的对比实验切片推理让麻点AP从0.52升到0.76但划伤AP提升很有限原因是划伤横跨切片多个区域被切断后失去整体线状特征。这说明切片推理不是万能的具体效果依赖缺陷形态。做这类对比实验时固定随机种子、固定conf阈值才能保证差异来自推理方式而不是随机波动。我现在的习惯是每次验证完都把漏检图单独建目录按缺陷类别归档定期和现场质检员一起复盘看漏检到底是标注问题、类别混淆还是亮度边界情况。这个流程坚持下来模型会随着数据迭代越用越顺手而不是训完之后就变成谁也不懂的黑匣子。希望帮到你。本文还有配套的精品资源点击获取