基于 YOLO11 的钢材表面六 类 缺陷智能检测系统
把热轧钢板、冷轧钢板表面的"裂纹、夹杂、麻面、划痕……"这些工业缺陷,从靠老师傅打手电变成镜头一拍就出报表。
一、背景
1.1 行业痛点
钢材是工业制造的"骨头",但产线上的钢板/钢卷绕不开一件事——表面缺陷。这些缺陷既是质量门槛,也是合规底线:
- 裂纹:轧制应力或冷却不均产生的细长裂纹,关系强度与寿命;
- 夹杂:钢材中的非金属杂质或氧化物,会显著降低疲劳寿命;
- 斑块:成片色差或纹理异常,常见于热轧氧化或表面污染;
- 麻面:密集小坑,多由腐蚀或脱落造成;
- 氧化皮压入:氧化皮被轧辊压进基体,剥落后形成凹坑;
- 划痕:搬运/轧制过程中尖锐物刮擦的线性损伤。
传统的人工目检:
- 工序快、缺陷小,老师傅在线一天看 8 小时眼睛都能看花;
- 不同班组打分口径不一致,质量数据难沉淀;
- 一旦漏检流到下游冲压、焊接环节,返工成本极高。
本项目用 YOLO11n 做"六类钢材表面缺陷"的目标检测,配套 Streamlit 前端,让一线质检员从"打手电+笔记本"变成"上传图片 → 自动出缺陷位置 + 类别 + 风险等级"。
视频演示与源码 下载

包含: 📦完整项目源码 📦 预训练 模型权重
🗂️数据集
1.2 项目运行效果


1.3 项目介绍
核心创新点:
| 维度 | 说明 |
|---|---|
| 六类全覆盖 | 裂纹 / 夹杂 / 斑块 / 麻面 / 氧化皮压入 / 划痕,对齐 NEU-DET 公开数据集 |
| 风险分级 | 高/中/低三档风险,UI 自动用不同颜色标识 |
| 多输入 | 单图 / 批量 / 视频 / 摄像头四种输入,与产线相机、巡检视频自然对接 |
| 工程化 | 5MB 级模型 + ONNX 导出,可部署到边缘 AI 盒子或工业 PC |
| 配置驱动 | 类别说明、风险等级、UI 配色全部从 configs/project.yaml 注入 |
风险等级(写进 UI 图例与悬浮提示):
| 类别 | 风险 | 说明 |
|---|---|---|
| 裂纹 | high | 直接影响材料强度 |
| 氧化皮压入 | high | 剥落后形成凹坑 |
| 夹杂 | medium | 影响疲劳寿命 |
| 麻面 | medium | 易成腐蚀源 |
| 斑块 | low | 表面外观异常 |
| 划痕 | low | 线性机械损伤 |
技术栈:
| 层 | 选型 |
|---|---|
| 检测模型 | YOLO11n(ultralytics 官方,预训练 yolo11n.pt) |
| 训练框架 | ultralytics ≥ 8.3 |
| 后端推理 | Python 3.10 + PyTorch(CPU / MPS / CUDA 自适应) |
| 前端 | Streamlit + Plotly |
| 视频解码 | OpenCV + imageio-ffmpeg |
| 部署形态 | Streamlit / Docker;可导出 ONNX 给工业边缘盒子 |

二、设计框架
┌──────────────────────────────────────────────┐
│ 产线相机 / 质检员手机 / 巡检 PAD │
│ 单图 / 批量 / 视频 / 摄像头 │
└──────────────┬───────────────────────────────┘
▼ HTTP(默认 8501)
┌──────────────────────────────────────────────┐
│ Streamlit 应用 app/streamlit_app.py │
│ ├─ infer_image_path() 单帧推理 │
│ ├─ 类别 → 风险等级(high / medium / low)映射 │
│ └─ render_batch_analysis() 缺陷分布 + 风险图 │
└──────────────┬───────────────────────────────┘
▼ ultralytics.YOLO
┌──────────────────────────────────────────────┐
│ YOLO11n 推理引擎 │
│ model/best.pt(6 类钢材表面缺陷) │
└──────────────────────────────────────────────┘
YOLO11 网络结构(一图速通):
输入 640×640
│
┌───▼──── Backbone(C3k2 + SPPF) ────┐
│ 纹理 / 边缘 / 微小斑点特征提取 │
└───┬───────────────────────────────┘
│
┌───▼──── Neck(FPN + PAN) ─────────┐
│ 小目标(裂纹/夹杂)+ 大目标(斑块)│
└───┬───────────────────────────────┘
│
┌───▼── Head(Decoupled + DFL) ─────┐
│ 6 类分类 + DFL 边框回归 │
└───┬───────────────────────────────┘
│
输出:N×(x1,y1,x2,y2,conf,缺陷类)
为什么选 YOLO11n:钢材缺陷大多是长宽比悬殊的小目标(细长裂纹、点状夹杂、线状划痕),YOLO11 的多尺度特征 + DFL 回归对这种形态非常友好;5MB 级模型也方便下沉到产线边缘 AI 盒子。
检测流程:
钢板图 ──▶ letterbox 640 ──▶ YOLO11n 推理
│
▼
conf ≥ 0.25 + NMS(IoU 0.7)
│
▼
result.plot() 画框
│
▼
class_name → 风险等级 → 缺陷位置/严重程度报告

三、代码结构(核心 50 行)
# app/streamlit_app.py(节选)
from pathlib import Path
import streamlit as st, pandas as pd, yaml
from ultralytics import YOLO
ROOT = Path(__file__).parent.parent
MODEL_PATH = ROOT / "model" / "best.pt"
CFG = yaml.safe_load(open(ROOT / "configs" / "project.yaml", encoding="utf-8"))
APP = CFG.get("app", {
})
SEVERITY = APP.get("class_severity", {
}) # ① 风险等级映射
@st.cache_resource(show_spinner=False)
def load_model(p: str) -> YOLO:
return YOLO(p) # ② 缓存权重
def infer_image_path(model: YOLO, image_path: Path, conf: float):
result = model.predict(str(image_path), conf=conf, verbose=False)[0] # ③ 推理
annotated = result.plot()
rows = []
if result.boxes is not None:
for box in result.boxes:
cls_id = int(box.cls.item())
x1, y1, x2, y2 = [float(v) for v in box.xyxy[0].tolist()]
cls_name = result.names[cls_id]
rows.append({
"class_name": cls_name,
"severity": SEVERITY.get(cls_name, "low"), # ④ 自动打风险等级
"confidence": round(float(box.conf.item()), 4),
"x1": round(x1, 1), "y1": round(y1, 1),
"x2": round(x2, 1), "y2": round(y2, 1),
})
return annotated[:, :, ::-1], pd.DataFrame(rows)
# ---------- Streamlit 入口 ----------
st.set_page_config(page_title=APP.get("title", "Steel Defect AI"), layout="wide")
conf = st.sidebar.slider("置信度阈值", 0.1, 0.9, 0.25, 0.05)
model = load_model(str(MODEL_PATH))
mode = st.radio("输入类型", ["单张图片", "批量图片", "视频", "摄像头"], horizontal=True)
if mode == "单张图片":
up = st.file_uploader("上传待检测钢板图片", type=["jpg", "jpeg", "png", "webp", "bmp"])
if up is not None:
annotated, df = infer_image_path(model, Path(up.name), conf)
col1, col2 = st.columns(2)
col1.image(up.getvalue(), caption="原图")
col2.image(annotated, caption="检测结果")
# 高风险计数
high_n = int((df["severity"] == "high").sum()) if not df.empty else 0
st.metric("高风险缺陷数", high_n)
st.dataframe(df)
5 段解析:
SEVERITY—— 把"裂纹/氧化皮压入 = high,夹杂/麻面 = medium,斑块/划痕 = low"做成可配置的字典,业务专家想调整无需动 Python 代码。@st.cache_resource—— Streamlit 会话级缓存权重,刷新页面只加载一次。model.predict(...)[0]—— ultralytics 一行完成 letterbox、NMS、置信度过滤。- 在结果 DataFrame 里当场打上 severity 字段,下游"高风险缺陷数"卡片、风险柱状图、CSV 导出全部基于这一字段。
st.metric("高风险缺陷数", high_n)—— 把"看几张图能看出来什么"这件事,从图片直接转成数字 KPI,质检主管一眼就能看到产线状态。
四、训练效果
模型基于 yolo11n.pt、imgsz=640、batch\=16,在 NEU-DET 六类钢材缺陷 数据集上训练 。
模型在测试集上检测效果良好,可稳定识别裂纹、夹杂、斑块、麻面、氧化皮压入、划痕这六类钢材表面缺陷,已能满足产线初筛、巡检与质检数字化等场景的使用需要。
五、项目总结
做对了什么:
- 任务对齐工业语义:检测结果不止有类名,还自动带"高/中/低"风险等级,直接可对接质检系统的告警与放行规则。
- 轻量 + 边缘友好:5MB 级权重,可导出 ONNX 给产线工业 PC、嵌入式 AI 盒子。
- 配置驱动 UI:类别说明、风险等级、配色等都从
configs/project.yaml注入,把"换品类(如铝材表面缺陷)"这件事压成一份 yaml + 一份新权重。
还能怎么做:
- 同时输出缺陷面积比:基于检测框面积 / 钢板可视区域比例计算"单板缺陷率",更对得上工业 PPM 指标;
- 多模态融合:可见光 + 表面轮廓激光 / 红外,对低对比度的氧化皮压入、麻面更稳;
- 追加缺陷分割:检测框只定位,再叠一个轻量分割头能给出像素级缺陷面积,直接对接退货/降级规则;
- 数据扩充:加入更多车间真实工况图像,提升模型在不同光照、不同钢种下的鲁棒性。
一句话总结: 用 YOLO11n 把"钢板表面缺陷在哪+什么类+多大风险"这套质检小流程跑通,是 5MB 模型撬动一条产线在线质检的典型样例。