news 2026/9/23 1:19:46

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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这三类的特征在低分辨率下非常相似,如果你用默认imgsz=640训练,小缺陷很容易被当作背景滤掉。所以在数据准备阶段,不要急着把所有图片都缩小到统一尺寸,而应保留原始分辨率的标注信息,训练时再通过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', encoding='utf-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_ok=True) 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官方配置里已经做了这个策略,但你也可以直接关闭,在训练参数里写mosaic=0.0。

对于热轧带钢这类表面纹理比较一致的图像,水平翻转可以开,垂直翻转要谨慎。如果产线图像的拍摄方向固定,带钢在画面中不会出现上下颠倒的情况,那flipud建议设为0。hsv增强和灰度增强可以适当调大,因为现场光照变化大,金属表面反光会改变局部灰度分布,增强这部分鲁棒性比增加图片数量更划算。常见做法是hsv_h=0.015, hsv_s=0.7, hsv_v=0.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 python=3.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 \ data=steel.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ patience=20 \ project=runs/steel \ name=yolov8n

参数说明:

  • data指定yaml文件路径,model是预训练权重,yolov8n.pt在第一次运行时会自动下载,如果你的机器无法访问外网,需要手动把权重文件放到当前目录。
  • epochs是训练轮数。热轧带钢数据集规模通常不大,几百到几千张图片,100个epoch足够,不需要像COCO那样训练300轮。
  • imgsz是输入图像尺寸。如果你发现缺陷目标普遍比较小,可以改成960,但显存占用会明显上升。对于CPU环境,建议保持640。
  • batch是批大小,默认16。GPU显存不足时先降到8,CPU环境设成2或4即可,尽量不要超过8。
  • patience是早停轮数,连续20轮验证集指标不再提升就自动停止。这个参数对工业场景很友好,因为现场数据标注成本高,样本量少,训练后期很容易过拟合,早停能帮忙保留最好的那版权重。

训练结束后,在runs/steel/yolov8n/weights目录下会生成best.pt和last.pt,best.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'], label='box_loss') plt.plot(df['epoch'], df['val/box_loss'], label='val_box_loss') plt.legend() plt.savefig('loss_curve.png') "

这里有个细节:results.csv是训练时实时追加写入的,训练中断后再次续训,文件末尾会出现重复的epoch行。如果你要分析损失曲线,建议先做去重,否则曲线会往回折,看起来像损失跳变。

4. 评估、调优与部署:混淆矩阵、边缘模型和热轧缺陷的差异点

4.1 用模型评估命令输出混淆矩阵,定位类别互相干扰

yolov8训练完成后,不要直接拿best.pt上产线,先用验证集做一轮评估,把混淆矩阵找出来看。

yolo detect val \ model=runs/steel/yolov8n/weights/best.pt \ data=steel.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中具体参数为scale=0.5, translate=0.1, perspective=0.0, flipud=0.0。

4.3 误检率偏高时引入无缺陷负样本

热轧带钢表面不是每帧都有缺陷,模型很容易把氧化铁皮、水渍、光照反光当成缺陷。解决误检最有效的方法不是调阈值,而是在训练集中加入无缺陷的负样本图片,并在标注文件中不给它们写任何目标。yolov8对这类背景图片的处理方式是把每张图片视为没有目标,损失函数中的分类部分会趋向于输出背景置信度。我一般会把负样本比例控制在总样本量的10%到20%,太多会降低模型对真实缺陷的召回。

加入负样本后重新训练,误检下降很明显,但要注意验证集也需要同等比例的负样本,否则验证指标会虚高。

4.4 rk3588部署yolov8时的导出与推理思路

训练好的模型要部署到产线边缘设备,比较常见的是rk3588这类带NPU的板子。部署前先把权重从PyTorch格式导出成ONNX。

yolo export model=runs/steel/yolov8n/weights/best.pt format=onnx opset=12

导出的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_size=640, overlap=64): 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核心上。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 1:14:18

KMeans聚类算法实战:从特征工程到宿舍分配的无监督学习方案

简介:针对高校宿舍分配场景,基于K均值聚类算法的Python源码项目,面向数据挖掘学习者、开发者和高校信息化管理人员,演示如何用机器学习库完成学生特征聚类,将年龄、性别、专业、生活习惯等多维数据纳入分析&#xff0c…

作者头像 李华
网站建设 2026/9/23 1:08:37

紧耦合差分对为何增大串扰?奇模偶模阻抗与高速PCB设计

简介:面向高速网络设计与PCB工程师的差分对信号完整性专题资料,系统讲解差分对这一关键拓扑。内容从基本定义入手,阐明差分信号与共模信号的本质区别,并给出奇模、偶模驱动下的阻抗特性:差分阻抗为奇模阻抗的两倍&…

作者头像 李华
网站建设 2026/9/23 1:07:15

银河麒麟下源码编译安装SVN服务端及svnserve配置全攻略

简介:面向银河麒麟操作系统的运维与开发人员,这份文档详实记录了在国产Linux环境下从零搭建SVN版本控制服务的完整流程。全文以实操为主线,涵盖Subversion及其依赖组件apr、apr-util、SQLite的源码下载、编译安装,环境变量配置、版…

作者头像 李华