ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

yolov8热轧带钢表面缺陷检测:从数据集标注到边缘部署实践

yolov8热轧带钢表面缺陷检测:从数据集标注到边缘部署实践 简介基于YOLOv8的热轧带钢表面缺陷检测项目面向工业质检工程师、计算机视觉学习者与算法研究者提供一套从数据准备、模型训练、性能评估到推理部署的完整解决方案。数据集包含横向裂缝、纵向裂缝、块状裂缝、龟裂、坑槽等典型缺陷的标注图像结合源码可快速复现训练与检测流程。压缩包内共2000个文件其中1808个txt文件存储缺陷标注框信息14个Python脚本实现训练、验证与推理逻辑161个Markdown文档分步讲解环境搭建、参数配置、数据增强和mAP评估等核心内容另有YAML模型配置、C辅助部署程序及HTML说明页面整体大小74.49MB目录结构清晰便于查找。目前已有841人学习使用教程中给出的依赖安装、调参策略和常见排错方法能大大降低入门门槛既适合高校毕业设计也可作为企业产线质检方案的技术参考。1. 热轧带钢表面缺陷检测不是通用目标检测yolov8要解决的是产线上持续跑的问题热轧带钢表面缺陷检测与普通目标检测有个明显差别你面对的是一张宽幅的金属表面图像上面有氧化铁皮、水渍、光照不均带来的反光而缺陷本身可能只有几十个像素比如麻点、划伤、裂纹和夹杂它们之间形态接近又存在严重的类别不平衡。很多人第一次拿yolov8官方权重去跑热轧带钢图片结果漏检一片原因不是模型不行而是数据集组织、标注方式和训练参数都不适配工业现场。这篇文章沿一条可落地的路线走一遍从缺陷类别定义和标注转换到ubuntu20.04搭建yolov8环境并训练自己的数据集再到用混淆矩阵和损失函数曲线调优最后给出一个在边缘设备上部署时特别好用的瓦片切分技巧。适合刚接触yolov8但手里只有现场图片的工程师也适合需要把缺陷检测模型从实验推到产线的人员。2. 构建热轧带钢缺陷数据集从标注格式到yolov8能直接训练的数据组织2.1 热轧带钢表面缺陷的类别定义与常见标注体系做热轧带钢表面缺陷检测第一步不是选模型而是把类别定义清楚。业界用得比较多的是东北大学的NEU-DET公开数据集它把热轧带钢表面缺陷分成六类这六类基本覆盖了产线上最常见的缺陷形态crazing裂纹、inclusion夹杂、patches麻点、pitted_surface氧化铁皮压入、rolled_in_scale氧化铁皮、scratches划伤。实际现场采集的数据可能更多比如还有辊印、擦伤、压痕等但在模型起步阶段维护六至八个类别就够了类别太多反而会让相互之间形态接近的缺陷更难区分。下表是这六类缺陷在训练时常用的class_id和视觉特征。标注属性参考NEU-DET的风格但没有必要完全照抄如果你有自己的现场数据可以按这个结构扩展。class_id名称常见成因视觉特征0crazing热应力导致的表面裂纹细小网状或线状纹理对比度低1inclusion杂质卷入基体点状或短线状暗斑边界不规则2patches表面局部腐蚀或氧化片状暗色区域灰度不均匀3pitted_surface氧化皮压入后剥落密集凹坑呈点状集群4scratched机械刮擦连续直线或曲线亮痕方向性强5rolled_in_scale氧化铁皮压入表面大块暗色压入物形状不规则这里有个容易踩的细节NEU-DET中crazing和patches、pitted_surface这三类的特征在低分辨率下非常相似如果你用默认imgsz640训练小缺陷很容易被当作背景滤掉。所以在数据准备阶段不要急着把所有图片都缩小到统一尺寸而应保留原始分辨率的标注信息训练时再通过imgsz参数控制输入大小。2.2 用labelme标注后转换成yolo格式现场采集的热轧带钢图像通常没有现成标注一般的做法是用labelme画矩形框或任意多边形然后导出JSON文件。yolov8训练时并不直接吃JSON或XML它要求每张图片对应一个同名的txt文件每行内容为“class_id x_center y_center width height”并且所有坐标值必须归一化到0到1之间。下面这段代码可以把labelme导出的JSON批量转换成yolo格式的txt文件。import json import os def labelme_json_to_yolo(json_path, out_dir, class_names): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] out_lines [] for shape in data[shapes]: label shape[label] if label not in class_names: continue cls_id class_names.index(label) points shape[points] # labelme的矩形框是两点坐标多边形则取最小外接矩形 xs [p[0] for p in points] ys [p[1] for p in points] xmin, xmax min(xs), max(xs) ymin, ymax min(ys), max(ys) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h out_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if out_lines: txt_name os.path.splitext(os.path.basename(json_path))[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(out_lines)) if __name__ __main__: class_names [crazing, inclusion, patches, pitted_surface, scratched, rolled_in_scale] json_root data/labelme_annotations out_root data/yolo_labels os.makedirs(out_root, exist_okTrue) for json_file in os.listdir(json_root): if json_file.endswith(.json): labelme_json_to_yolo( os.path.join(json_root, json_file), out_root, class_names )这段代码先读入JSON中的图片宽高然后遍历每个标注形状。labelme的矩形框通常只有两个点但手工标注时可能画出多边形所以代码里统一取所有点的最小外接矩形。输出时x_center和y_center都除以图片宽高归一化这样不管训练时imgsz设多少标注都能正确映射。需要留意的是如果原始图片分辨率很大比如5000像素宽标注框的x_center在归一化后会变成一个很小的浮点数写txt时保留6位小数够用但建议不要小于6位否则坐标精度损失会让小目标的定位偏差变大。转换完成后把整个数据集组织成yolov8期望的目录结构train和val两个子集建议按图片数量比例8:2切分同时保证每个类别在两个子集中都有分布。datasets/ steel/ images/ train/ val/ labels/ train/ val/2.3 处理数据集用于yolov8训练时的增强参数选择数据增强对热轧带钢表面缺陷检测的影响比其他场景更明显。yolov8默认开启mosaic增强它会把四张图拼接成一张这对小目标检测通常是好事但有一个坑当缺陷本身很小时mosaic拼接会把缺陷缩得更小导致模型学不到足够的纹理细节。我一般建议训练前期用mosaic训练最后十到二十个epoch自动关闭。ultralytics官方配置里已经做了这个策略但你也可以直接关闭在训练参数里写mosaic0.0。对于热轧带钢这类表面纹理比较一致的图像水平翻转可以开垂直翻转要谨慎。如果产线图像的拍摄方向固定带钢在画面中不会出现上下颠倒的情况那flipud建议设为0。hsv增强和灰度增强可以适当调大因为现场光照变化大金属表面反光会改变局部灰度分布增强这部分鲁棒性比增加图片数量更划算。常见做法是hsv_h0.015, hsv_s0.7, hsv_v0.4这是yolov8默认值但如果你的数据集中反光样本很少可以把hsv_v提高到0.6。3. 环境配置与训练那条最短路径yolov8最小命令从装环境到出模型3.1 ubuntu20.04搭建yolov8环境的cpu与GPU两种选择如果你手头没有NVIDIA显卡用CPU也能把yolov8跑起来只是训练时间长一些。先创建一个干净的conda环境Python版本选3.10或3.11都可以yolov8官方支持这两个版本。装依赖时不用手动去装PyTorch直接pip install ultralytics会把配套的环境带起来。下面这组命令在ubuntu20.04上验证过步骤很简单。conda create -n yolov8 python3.10 -y conda activate yolov8 pip install ultralytics安装完成后用下面的命令验证环境是否正常。如果你只有CPU这个导入操作会自动下载torch的CPU版本训练前建议确认一下torch.cuda.is_available()的返回值。import torch import ultralytics print(torch.__version__) print(ultralytics.__version__) print(torch.cuda.is_available())如果你的机器是NVIDIA显卡想用GPU训练需要手动安装与驱动匹配的PyTorch版本。常见做法是先装CUDA toolkit再执行pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121最后装ultralytics。这样能避免pip自动把torch的CPU版本装进去。注意这里cu121对应CUDA 12.1不是CUDA版本越高越好要以显卡驱动支持的版本为准。3.2 数据集配置文件steel.yaml的写法与路径规则yolov8训练时通过YAML文件指定数据集的路径和类别名。下面是热轧带钢数据集对应的配置文件路径要以你实际存放数据集的位置为准。path: /home/user/datasets/steel train: images/train val: images/val names: 0: crazing 1: inclusion 2: patches 3: pitted_surface 4: scratched 5: rolled_in_scale这里有个很容易忽略的点names字典里的类别顺序必须和标注txt中的class_id一致。很多人在前面用labelme转换时已经指定了class_names列表的顺序那么yaml里的names也必须按同样顺序写否则训练出来的模型在推理时会把类别标签错位。path这里我写的是绝对路径你如果要在多台机器上复现也可以写成相对路径但yolov8会把相对路径锚定到当前工作目录不如绝对路径稳妥。3.3 训练自己的数据集训练命令与关键参数逐项说明环境通了数据集配置好了就可以开始训练。第一次跑建议用yolov8n这个模型最小训练速度快能先把整个数据链路跑通之后再换yolov8m或yolov8l追求精度。yolo detect train \ datasteel.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ projectruns/steel \ nameyolov8n参数说明data指定yaml文件路径model是预训练权重yolov8n.pt在第一次运行时会自动下载如果你的机器无法访问外网需要手动把权重文件放到当前目录。epochs是训练轮数。热轧带钢数据集规模通常不大几百到几千张图片100个epoch足够不需要像COCO那样训练300轮。imgsz是输入图像尺寸。如果你发现缺陷目标普遍比较小可以改成960但显存占用会明显上升。对于CPU环境建议保持640。batch是批大小默认16。GPU显存不足时先降到8CPU环境设成2或4即可尽量不要超过8。patience是早停轮数连续20轮验证集指标不再提升就自动停止。这个参数对工业场景很友好因为现场数据标注成本高样本量少训练后期很容易过拟合早停能帮忙保留最好的那版权重。训练结束后在runs/steel/yolov8n/weights目录下会生成best.pt和last.ptbest.pt是验证集上表现最好的权重后续推理和部署都用它。3.4 训练过程的监控损失函数曲线和results图怎么读训练完成后用yolov8画损失函数曲线图这是一个很实用的技能。训练过程中ultralytics会自动生成results.png里面包含box_loss、cls_loss、dfl_loss三条损失曲线以及precision、recall、mAP50、mAP50-95的变化曲线。我在实际项目里一般先看box_loss和cls_loss是不是都平滑下降如果cls_loss在训练后半段反弹大概率是过拟合了这时候回看patience早停的epoch位置确认best.pt不是最后一个epoch。如果box_loss已经很低但mAP50-95不涨说明定位已经足够好问题出在边界框和真实框的IoU分布上可以检查是不是有小目标因为标注框太小导致IoU计算不稳定。要单独绘制某一条曲线可以读取训练过程中自动保存的results.csv用pandas画图。下面的命令可以快速预览。python -c import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/steel/yolov8n/results.csv) plt.plot(df[epoch], df[train/box_loss], labelbox_loss) plt.plot(df[epoch], df[val/box_loss], labelval_box_loss) plt.legend() plt.savefig(loss_curve.png) 这里有个细节results.csv是训练时实时追加写入的训练中断后再次续训文件末尾会出现重复的epoch行。如果你要分析损失曲线建议先做去重否则曲线会往回折看起来像损失跳变。4. 评估、调优与部署混淆矩阵、边缘模型和热轧缺陷的差异点4.1 用模型评估命令输出混淆矩阵定位类别互相干扰yolov8训练完成后不要直接拿best.pt上产线先用验证集做一轮评估把混淆矩阵找出来看。yolo detect val \ modelruns/steel/yolov8n/weights/best.pt \ datasteel.yaml执行完会在runs/steel/yolov8n/目录下生成混淆矩阵图片confusion_matrix.png和PR曲线。热轧带钢表面缺陷检测中最常见的问题是pitted_surface和patches互相误判因为这两类在图像上都表现为局部暗色区域只是纹理粒度不同。如果混淆矩阵里这两类的交叉值很高不要急着加数据先回到标注层面检查是不是标注框标准不统一比如同样是麻点有人把整个区域标成一个框有人只标局部这种标注不一致会让模型学到一个模糊的边界。4.2 小缺陷召回率低的三个常用调整方向热轧带钢表面缺陷检测的难点不在大缺陷而在小缺陷。mAP50-95低通常是小目标拖后腿。常见做法按优先级排序第一增大imgsz。把imgsz从640调到960小缺陷在输入图像中的像素占比变大特征提取更充分。显存不够时配合batch减半。第二调整增强策略。关闭mosaic或者仅在训练前中期开启否则小缺陷被四张图缩放拼接后几乎不可见。第三移除或减少强数据增强。金属表面图像本身纹理重复度高radiate、perspective这类空间增强会让缺陷形态变得不真实建议全部设为0。yolov8中具体参数为scale0.5, translate0.1, perspective0.0, flipud0.0。4.3 误检率偏高时引入无缺陷负样本热轧带钢表面不是每帧都有缺陷模型很容易把氧化铁皮、水渍、光照反光当成缺陷。解决误检最有效的方法不是调阈值而是在训练集中加入无缺陷的负样本图片并在标注文件中不给它们写任何目标。yolov8对这类背景图片的处理方式是把每张图片视为没有目标损失函数中的分类部分会趋向于输出背景置信度。我一般会把负样本比例控制在总样本量的10%到20%太多会降低模型对真实缺陷的召回。加入负样本后重新训练误检下降很明显但要注意验证集也需要同等比例的负样本否则验证指标会虚高。4.4 rk3588部署yolov8时的导出与推理思路训练好的模型要部署到产线边缘设备比较常见的是rk3588这类带NPU的板子。部署前先把权重从PyTorch格式导出成ONNX。yolo export modelruns/steel/yolov8n/weights/best.pt formatonnx opset12导出的ONNX模型可以先用onnxruntime在PC上做一次推理验证确认输出尺寸符合预期。yolov8的ONNX输出是一个1x84x8400的矩阵84由4个边界框坐标加80个类别概率组成但这对应的是COCO数据集。你的模型只有6类所以输出应该是1x10x8400类别数变了导出时模型结构会自适应调整。部署到rk3588时一般需要把ONNX再转成rknn格式这个转换工具在Rockchip官方仓库里转换前需要准备一张校准图片做量化。量化精度通常选int8热轧带钢图像的灰度范围比较集中int8量化后mAP下降不超过2%的话可以接受。5. 一个提升小缺陷召回率的具体做法瓦片切分与重叠推理在热轧带钢现场相机拍到的原始图像往往很大比如4096x2000直接resize到640输入会丢失大量小缺陷。最后这一节给出一个改动成本低、效果又挺明显的方法把大图切成多块小图分别推理再合并结果。这比单纯调imgsz更可控因为切分后的每块小图缺陷占比变大等效于把一个小目标放大了。import cv2 import numpy as np def split_image_into_tiles(img, tile_size640, overlap64): h, w img.shape[:2] step tile_size - overlap tiles [] coords [] ys list(range(0, h - tile_size 1, step)) xs list(range(0, w - tile_size 1, step)) if (h - tile_size) % step ! 0: ys.append(h - tile_size) if (w - tile_size) % step ! 0: xs.append(w - tile_size) for y in ys: for x in xs: tiles.append(img[y:y tile_size, x:x tile_size]) coords.append((x, y)) return tiles, coords tiles, coords split_image_into_tiles(large_img)切分后每个tile用yolov8的model.predict单独推理输出框的坐标是相对tile的需要加上coords中的偏移恢复到原图坐标。重叠区域的好处是如果某个缺陷正好被切分线切成两半只要缺陷在至少一个tile中完整出现就能被检出来后续用普通NMS把重叠框合并即可。这里overlap设成64像素对于热轧带钢表面缺陷来说是个经验值因为大多数小缺陷直径在20到50像素之间64像素重叠能保证缺陷不会被完全切掉。合并框时注意置信度处理同一目标在重叠区域可能出现多个框传统NMS是保留置信度最高的框但在工业检测里如果两个框来自不同tile置信度都很低用NMS的IoU阈值0.5可能保留一个不够稳。我一般会用weighted NMS也就是对重叠的同类框按置信度加权平均坐标这样定位坐标会比直接NMS更稳。实现方式是把所有恢复坐标后的框收集起来按类别分组然后做标准NMS再把保留的框和它周围的同类框做一次加权。这一步虽然增加了一点推理耗时但能明显减少漏检。部署到rk3588这类NPU设备时因为单次推理耗时低四到六个tile的串行推理也能跑在实时要求不高的抽检场景如果产线速度较高可以先用小的tile_size观察准确率再把并行推理放到多个NPU核心上。本文还有配套的精品资源点击获取
返回列表