1. 项目背景与整体设计思路布匹缺陷检测在纺织行业一直是刚需但很多工厂至今还在靠老师傅肉眼盯。人工检测有几个绕不开的痛点速度跟不上产线、标准不统一导致漏检率波动大、夜班人员疲劳后误判率飙升。这两年行业内陆续有人尝试引入机器视觉但传统图像处理方案比如固定阈值分割、频域滤波对纹理复杂的布匹几乎无解——不同织物表面本身就有周期性纹理棉麻的毛羽和提花的图案都容易被误判成缺陷。我最初接触这个需求是给一个搞纺织设备集成商做的验证性项目对方手里有一批从现场产线采集的布面图像想要一条能自动识别脏污、破洞、水渍等典型缺陷的检测链路。传统机器视觉试了一圈效果不理想于是把方向转向了深度学习目标检测路线也就是用 YOLO 系列检测模型直接框出缺陷位置和类别。之所以选 YOLO 而不是 Faster R-CNN 或 SSD核心是产线实时性的硬约束。一条 200m/min 的验布机意味着相机每秒要处理几十帧经线方向移动的织物画面如果单帧推理超过 30ms 就很难在线使用。YOLO 作为单阶段检测器的代表在精度和速度之间平衡最好而且生态成熟Python 端接入容易适合快速迭代验证。如果用两阶段检测器精度可能高一点但速度完全扛不住产线节奏部署也复杂得多。整体系统架构上我分了四个模块图像采集与预处理、缺陷检测模型、结果后处理与告警、可视化与统计。图像采集这块直接用工业面阵相机配合线性光源打光保证布面亮度均匀检测模型用 YOLO 系列当时实测了 V8 和 V11 两个版本后处理负责把模型输出的检测框去重、过滤、映射到实际物理坐标可视化则用 Python 的 OpenCV Tkinter 做了一个简单桌面端操作人员能看到实时检测画面和缺陷标记同时生成统计报表。这个项目最终实现了六大类布匹缺陷的识别脏污、破洞、毛头、褶皱、色差、水渍。模型推理速度在 GPU 环境下单帧约 15ms在 CPU 环境下约 90ms识别精度在验证集上 mAP0.5 达到 92% 以上。对于做工业视觉、算法落地或者毕设项目的读者这篇内容都算一份可以参照的完整复盘接下来我会按照数据、训练、部署、排障的顺序把整个过程拆开讲清楚。2. 数据集的采集与预处理2.1 缺陷类别定义与成像条件数据是工业检测项目的命脉。最开始我拿到的原始样本只有三千多张而且类别分布极不均匀——破洞这种“明显到人眼一看就知道”的缺陷样本相对多水渍和色差这种对比度低、边界模糊的缺陷样本很少。如果用这种数据直接训练模型大概率把水渍和色差全部漏掉或者干脆学歪了。先确定六类缺陷的定义标准。我参考了实际验布工的判断习惯和下游客户对缺陷等级的分级规则把类别明确为脏污布面附着的油渍、色斑、泥点形状不规则颜色与底布差异明显破洞经纬纱断裂形成的孔洞边缘可能有毛边毛头布面起毛起球、纱线头外露形成的毛羽聚集区域褶皱布面因张力不均造成的折叠压痕呈条状或块状色差局部区域颜色与整体布匹存在明显偏差常见于染色不均水渍水痕干燥后留下的痕迹通常边界较浅对比度低类别定义好后需要统一成像环境。我实测过光源角度对检测结果影响非常大。使用环形光源时破洞和褶皱这种带阴影的缺陷比较明显但脏污和水渍因为光照过亮反而被“洗”掉了改成条形光源按 45 度角斜射被测表面形成漫反射织物纹理细节突出但整体亮度不均。最终我采用的是两条线性光源对称分布、以 30 度角照射的方案这样既能突出低对比度缺陷又不会因为镜面反射造成大片过曝。成像分辨率也是一个关键选择。相机分辨率太高图像文件大、标注工作量暴增、训练速度慢分辨率太低细小缺陷比如半毫米的破洞根本看不清。现场相机使用的是 1280x1024 分辨率覆盖约 30cm 宽幅的布面经过测试这个分辨率下 1mm 以上的缺陷都能被清晰标注。训练时我再统一缩放到 640x640防止 YOLO 输入尺寸不一致导致的问题。2.2 标注工具选择与数据增强策略标注阶段我对比过 LabelImg、labelme 和 X-AnyLabeling 三个工具。LabelImg 是老牌工具界面简单但功能比较基础适合小批量标注labelme 对多边形标注支持好但布匹缺陷大多数是非规则的块状区域用矩形框标注反而更符合检测任务的定义——我们只需要知道缺陷大致位置和类别不需要精确到像素级分割X-AnyLabeling 可以加载预训练模型做自动预标注能省不少力气。最终主力标注工具用的 LabelImg把标注结果导出为 YOLO 格式的 txt 文件每一行是“类别 中心点x/宽 中心点y/高 宽/图宽 高/图高”的归一化坐标。标注时需要注意几个容易踩坑的细节。矩形框不能为了“把目标包住”就无限扩大否则背景比例太大模型会学到大量无效特征。比如褶皱这种条状缺陷我建议把框紧贴缺陷的最外边缘宁可框略小也不要框太大。另一个是边界情况的处理如果缺陷跨在图像边缘我选择把框延伸到图片边界之外归一化后坐标可能超出 0~1这种情况下 YOLO 会自动裁剪检测效果反而比强行缩小框要好。数据增强我用了 Albumentations 库这是工业视觉项目里非常好用的图像增强库。因为没有做在线增强而是提前把增强后的图片离线生成出来这样训练时迭代速度更快。增强策略包括水平翻转、垂直翻转、90度旋转、随机亮度对比度调节、随机裁剪缩放等。但我特别把色彩相关的增强幅度控制在较小范围——因为布匹缺陷检测中颜色信息本身是判别依据比如色差和脏污如果你把色调随机改变得太狠等于教模型“颜色不重要”这会直接破坏模型对色差类缺陷的判别能力。这一点和通用目标检测很不一样。COCO 数据集上做增强可以大胆随机颜色扰动因为物体类别判定主要靠形状和上下文但布匹缺陷检测里很多缺陷就是靠颜色差异来区分的所以我建议如果增强库里有 HueSaturationValue、RandomBrightnessContrast 这类操作概率设为 0.3 左右、强度设低一些就够了。2.3 数据集划分与 YOLO 格式配置划分数据集时不能简单用 random split 就完事。我遇到过这种情况同一匹布在相邻位置拍摄的多张图像非常相似如果这些相似图像同时出现在训练集和验证集验证结果会虚高模型实际泛化能力没展示出来。建议用图像来源分组的方式划分——把来自同一匹布的图像全部放到同一个集合里确保训练集和验证集在“布匹样本来源”上没有交集。原始图像来自现场测试的多批次布料我按卷号做了分组训练集占 75%、验证集占 15%、测试集占 10%。划分完后的数据集结构如下dataset/ ├── images/ │ ├── train/ # 训练集图像 │ ├── val/ # 验证集图像 │ └── test/ # 测试集图像 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml # 模型训练的数据配置文件data.yaml 里面的内容很简单指定类别数、类别名称和数据集路径path: ./dataset train: images/train val: images/val test: images/test nc: 6 names: 0: dirty 1: hole 2: fuzz 3: fold 4: color_diff 5: water_stain这里有一个容易被忽略的点类别名称最好不要用中文。后续导出 ONNX 部署或者用 OpenCV 的 DNN 模块加载时很多推理框架对中文类别名的兼容性不好甚至可能出现编码问题。我全部使用英文字符作为类别标识界面展示时再做一次映射把英文名称对应到中文显示。3. 模型选型与训练环境搭建3.1 YOLO 系列版本对比与选型逻辑标题里写了 YOLO但具体用哪个版本其实有讲究。我测试了 YOLOv5s、YOLOv8s 和 YOLOv11s 三个轻量版本在同一数据集、同一输入尺寸下的结果对比如下模型版本参数规模单帧耗时(GPU)mAP0.5单帧耗时(CPU)YOLOv5s7.2M12ms88.7%140msYOLOv8s11.2M14ms91.5%110msYOLOv11s9.4M13ms92.3%90ms从实测数据看YOLOv8s 和 YOLOv11s 对布匹缺陷的检测精度明显高于 v5而且 CPU 推理速度更快这得益于它们更高效的特征提取主干结构。后来我又测试了 YOLOv11s 的改进效果在褶皱和低对比度缺陷上确实有提升尤其是 C3k2 模块替换 C3 之后小目标的特征表达能力更好。最终主模型选择了 YOLOv11s但如果你的部署环境显卡算力比较弱选 YOLOv8s 也完全够用。YOLO 系列在布匹缺陷检测上的优势不是偶然的。缺陷尺寸变化极大——脏污能占画面 1/3水渍可能只有几个像素大小——多尺度预测机制在这一场景下非常关键。YOLOv8 和 v11 都有三个尺度的预测头分别负责大中小目标的检测P3 层负责小目标、P5 层负责大目标这种结构天生适配缺陷尺寸差异大的工业场景。传统图像处理方案做不到这种自适应必须在不同尺度上手工设计多组滤波器非常繁琐。3.2 训练环境搭建与依赖安装项目用的 Python 版本是 3.10框架版本建议遵循官方约束。实际安装时用 conda 创建独立环境避免和已有的其他项目冲突。conda create -n fabric_yolo python3.10 conda activate fabric_yolo pip install ultralytics8.3.0 pip install torch2.2.1 torchvision0.17.1 --index-url https://download.pytorch.org/whl/cu118这里有一点要特意提醒ultralytics 的版本不要追最新有些新版本会修改默认的增强策略或者输出格式导致明明改了参数却没生效。我固定 8.3.0 版本实测最稳定。GPU 版 PyTorch 的安装要看本机 CUDA 版本可以用 nvidia-smi 查看匹配不上就会出现 torch 报错“no kernel image available”。训练脚本可以直接用 ultralytics 的命令行接口也可以写 Python 脚本执行。我倾向于写脚本因为可以对参数做注释方便后续跑多组实验对比from ultralytics import YOLO # 加载预训练模型COCO 数据集上的权重可以作为起点 model YOLO(yolo11s.pt) # 训练配置 results model.train( datadataset/data.yaml, epochs300, imgsz640, batch16, lr00.01, lrf0.01, optimizerSGD, patience50, save_period10, device0, workers8, seed42, )batch size 的选择取决于显存大小。如果显存报错 OOM可以先把 imgsz 降到 480 看效果或者用梯度累积方式。我测试环境是一张 8GB 显存的卡batch 设为 16 是安全值。学习率 0.01 是 YOLO 官方预训练权重的默认推荐值如果你用随机初始化的权重不推荐学习率最好降到 0.001否则训练初期容易发散。3.3 训练过程与 Loss 曲线解读训练过程持续了大约 6 个小时300 轮迭代。需要随时关注两类曲线box_loss 和 cls_loss。box_loss 代表预测框与真实框的位置误差cls_loss 代表分类置信度的误差。理想情况是两条曲线在前 50 轮快速下降然后逐渐平缓。如果 box_loss 降到一定程度不再下降说明模型容量或者数据质量到了瓶颈这时候加大训练轮数没用需要从数据或模型结构上找原因。如果 cls_loss 先降后升说明开始过拟合了此时早停机制会自动在验证集精度不再提升时终止训练。我这里遇到一个小问题脏污和破洞类别明显是“好学”的类别loss 降得快水渍和色差这两个类别 loss 始终偏高。这说明低对比度缺陷确实难学后面我在 4.2 节专门说这个问题的处理办法。训练完成后ultralytics 会在 runs/detect/train 目录下保存 best.pt 和 last.pt。best.pt 是根据验证集 mAP 挑选的最优权重部署时直接用这个。last.pt 是最后一次迭代的权重一般不用。4. 缺陷检测核心模块的实现4.1 推理流程与后处理逻辑训练完模型的真实场景部署不是简单调用 model.predict() 就完事的。工业检测对结果输出有明确要求要知道当前图像有哪些缺陷、每个缺陷在哪、置信度是多少还要判断这些结果是否可靠。推理部分我用 ultralytics 的 YOLO 接口加载模型然后对输入图像做一次前向推理from ultralytics import YOLO class FabricDetector: def __init__(self, model_path, conf_thres0.35, iou_thres0.5): self.model YOLO(model_path) self.conf_thres conf_thres self.iou_thres iou_thres def detect(self, image): results self.model.predict( sourceimage, confself.conf_thres, iouself.iou_thres, verboseFalse, devicecuda:0, ) boxes results[0].boxes if boxes is None: return [] # 获取检测结果类别、置信度、坐标 detections [] for cls, conf, xyxy in zip(boxes.cls, boxes.conf, boxes.xyxy): x1, y1, x2, y2 xyxy.tolist() detections.append({ class: self.model.names[int(cls)], confidence: float(conf), bbox: [x1, y1, x2, y2], }) return detections这里关键在于置信度阈值的选择。阈值太高漏检率上升低对比度缺陷会被过滤掉阈值太低误检率飙升布面正常纹理会被当成缺陷。我统计了不同阈值下的表现置信度阈值漏检率每百帧误检数0.518%2.10.359%3.80.256%7.2综合产线上的容忍度我最终把阈值设为 0.35。产线上如果漏掉一个缺陷可能整匹布被下游退货损失非常大误检多报几个缺陷验布工复核后可以手动否定只是增加了一些人工负担。在工业落地场景“宁错勿漏”是基本原则所以阈值往低调是对的。后处理还有一个细节图像中可能检测到同一个缺陷在相邻位置的重叠框直接显示出来观感很差。我通过非极大值抑制NMS处理重叠框保留置信度最高的那个。ultralytics 内部已经做了 NMSiou 阈值默认 0.5但实际测试中我把 iou 阈值调到 0.45 效果更好因为布匹上两个距离很近的小缺陷比如两块紧挨的油渍如果 iou 阈值太高会被合并成一个影响计费精度。4.2 低对比度缺陷的针对性优化水渍这类缺陷是整个项目里最棘手的问题。它边缘模糊、与正常布面灰度差异小有时人眼都要盯着看两秒才能确认模型很容易漏检。第一个优化思路是调整模型输入的数据分布。前面提到水渍样本少所以我针对性做了过采样对每一张水渍图像通过亮度、对比度、锐化等操作生成 6 个增强变体扩充到训练集中。这个过程不是简单复制粘贴而是让模型看到同一缺陷在不同成像条件下的表现逼它去学真正核心的特征而不是记死某一张图的像素值。第二个思路是改进数据增强策略。在通用增强的基础上我给低对比度缺陷专门增加了一种弱对比度模拟增强把图像转换到 HSV 空间降低 V 通道的全局对比度并增加少量高斯噪声。模拟了现场夜间产线灯光衰减、光源老化导致的不良成像条件这比单纯在 RGB 空间调对比度自然得多。第三个思路是引入图像分块预测。水渍缺陷可能比较小而图像比较大直接整体预测特征已经被缩小了好几倍细节丢失严重。测试中发现对 1280x1024 原图先做 2x2 分块每个子图放大到 640x640 再推理水渍类别的召回率从 78% 提升到了 86%。代价是推理时间翻倍但对于不在核心实时链路上的场景是值得的。最终我的系统里做了一个可配置的“精细检测”开关默认开启用两路并行推理一路全图快检一路分块细检然后把两路结果合并去重。4.3 可视化界面与数据统计工业现场的检测系统不能只输出检测框要给操作人员一个直观的反馈界面。我用 OpenCV 和 Tkinter 搭建了一个轻量级桌面应用没有用繁琐的 Web 框架因为现场部署环境往往不具备 Node.js 或 Web 服务器运行条件Python 自带库最省事。界面左侧是实时视频画面缺陷框用不同颜色区分类别右侧是当前图像缺陷列表显示类别、置信度、坐标底部是统计栏更新当前的良品率、主要缺陷排行数据。每当检测到破洞和脏污这类严重缺陷时界面会弹窗提醒并把对应图像自动保存到“严重缺陷”专用目录方便后续查看。每匹布检测完成后系统生成一个 CSV 格式的报告包含缺陷类型、数量、分布位置和现场处理建议。这个统计模块的价值很快就体现出来了。项目试运行一段时间后现场反馈某批新进原料的毛头占比异常飙升生产部门顺着查下去发现是原料批次更换导致的纱线品质波动。检测系统最后成了简单的质量管理工具这是当初设计时完全没想到的附加价值。5. 系统部署与性能优化5.1 模型导出为 ONNX 并在生产环境推理如果只是为了写 Demo直接跑 .pt 权重文件问题不大。但生产环境里更推荐导出成 ONNX 格式这样可以用 ONNX Runtime 或者 OpenCV DNN 模块推理不依赖完整的 PyTorch 环境部署体积小很多而且在 CPU 上有时候推理更快。模型的导出很简单yolo export modelbest.pt formatonnx opset12 simplifyTrue导出过程有两个关键参数要注意。opset12 是兼容性比较好的选择如果设了最新版本老设备上的 ONNX Runtime 可能不支持。simplifyTrue 是启用 ONNX Simplifier 做计算图优化能去掉一些冗余算子让推理更高效。导出后建议用 onnxruntime 做一次精度对比验证确保导出的模型和 PyTorch 原模型推理结果一致。这里常遇到的一个坑是输入输出张量的形状与预期不同。YOLO 模型导出 ONNX 后输出是一个 1x84x8400 的矩阵其中 84 6 类别 4 坐标 80 置信度维度不同版本结构不同8400 是三个尺度预测头上的候选框数量。直接读取这个矩阵需要写后处理代码做解码工作量大一点因此我选择用 ultralytics 自带的推理接口作为生产环境主用ONNX 作为备份方案在边侧设备上测试。在生产环境实际推理时用的是 ultralytics 的 Python 部署模式加载的模型会自动使用 GPU 加速。如果 GPU 资源被其他任务占用可以切换为 CPU 推理并配合 OpenVINO 加速。在同一台普通办公电脑上实测OpenVINO 格式的推理速度比纯 PyTorch CPU 推理快约 40%。5.2 性能瓶颈分析与多线程流水线实际运行一段时间后我一个很深的体会就是单张图推理速度再快整体系统吞吐量也可能上不去因为瓶颈往往在数据读取和结果写入环节。相机采集一张大图本身就要几十毫秒如果推理线程在等图像GPU 就闲着反之如果推理忙不过来图像队列就会堆积导致丢帧。我采用的方案是典型的生产者-消费者模式采集线程负责从相机读图放入一个有界队列推理线程从队列取图做预处理和推理结果放入输出队列主线程负责渲染界面和写入日志。队列容量设为 16超过就丢弃最旧的帧——因为产线是连续运行的丢一帧丢一个小缺陷的风险远小于队列积压造成系统崩溃的风险。import threading import queue import time class DetectionPipeline: def __init__(self, detector, queue_size16): self.detector detector self.input_queue queue.Queue(maxsizequeue_size) self.output_queue queue.Queue(maxsizequeue_size) self.running False def start(self): self.running True threading.Thread(targetself._capture_loop, daemonTrue).start() threading.Thread(targetself._infer_loop, daemonTrue).start() def _capture_loop(self): # 从相机或视频流读取图像 while self.running: frame read_from_camera() if not self.input_queue.full(): self.input_queue.put(frame) else: time.sleep(0.001) def _infer_loop(self): while self.running: frame self.input_queue.get() detections self.detector.detect(frame) # 把检测结果和图像放入输出队列 if not self.output_queue.full(): self.output_queue.put((frame, detections))生产环境的另一个性能优化方向是图像预处理。从相机读出来的原始图像可能是 1280x1024送到模型前要 resize 到 640x640。这一步用 OpenCV 比用 PIL 快不少。如果做了数据归一化和通道顺序转换要放到预处理阶段一次完成不要在推理循环里反复做。5.3 系统在实际产线的部署要点实验室里跑得通的系统到现场可能会遇到各种意外。首先是硬件环境差异现场一般是工控机CPU 性能参差不齐GPU 可能只是入门级显卡。我部署时在两台不同配置的机器上做了基准测试发现单帧推理耗时差距接近 1 倍。于是我在配置文件中做了性能档位选择高性能模式下开启分块精细检测和全图检测双路推理低性能模式下关闭分块检测只跑全图单路推理保证基础可用。然后是产线速度匹配问题。验布机的产线速度是可调的如果速度太快相机视野内布面移动量超过检测帧率能覆盖的范围相当于每隔一段布就有一个从未被检测过的盲区。我的方案是提前和现场确认产线最高速度按照目标检测覆盖的重叠率反推出最低帧率要求然后用相机帧率参数做限制。例如布面移动速度是 3m/s相机视野宽度是 0.3m那每秒钟需要至少 10 帧才能保证每段布至少被观测一次实际留 1.5 倍余量就是 15fps。我的系统当前推理速度远高于这个值不会成为瓶颈。最后是光源波动问题。产线运行时间长了光源会持续发热亮度逐渐衰减这会导致水渍和色差的检测性能明显下降。我在系统中加了一个简单的亮度校准模块每隔一定时间自动统计图像的全局平均亮度和标准差如果偏离基准值超过阈值就在界面提示操作人员检查光源状态。这提醒了我一个道理深度学习模型只是整个系统的一部分环境稳定性不解决再好的模型也白搭。6. 实测结果与常见问题排查6.1 模型评估指标与各类别检测效果最终模型在测试集上的详细指标如下缺陷类别PrecisionRecallmAP0.5脏污91.2%88.4%93.5%破洞96.7%94.2%97.8%毛头88.5%90.1%91.3%褶皱85.6%82.9%87.4%色差83.8%78.5%84.6%水渍79.4%72.3%81.2%破洞和脏污的检测效果最好因为它们在视觉上特征明显、样本量大水渍和色差基本验证了前面的预判是最难的两个类别。整体 mAP0.5 92% 意味着绝大多数缺陷都能被准确框出。有一个参考基准行业里对这个任务的普遍要求是 mAP 能达到 90% 以上就满足初步使用条件我的结果刚好跨过这道线。Recall 指标比 Precision 更值得关注。在工业检测里Recall 是“该检出的缺陷中检出了多少”的比例漏检意味着直接经济损失Precision 是“检出的结果中多少是真正缺陷”的比例误检虽然增加人工复核量但不会造成漏失。如果你的系统资源只允许优化一个指标优先保 Recall。6.2 高频问题的排查思路与解决方案这部分是踩坑记录每一条都是真金白银的教训。问题一漏检明显的大面积缺陷排查思路先在单张图像上测试如果模型输出为空说明置信度低于阈值或者模型确实没识别出来。打开模型的预测结果日志看最大的 Top-1 置信度是多少。我遇到的情况是置信度只有 0.18低于设定的 0.35于是把阈值降低。如果置信度本身就接近 0那就要考虑是不是训练数据里该类缺陷的形态与现场差异太大需要补充现场图像做微调。问题二所有类别误检率突然飙升这通常不是模型本身的问题而是图像质量变了。有一次现场环境光源老化导致亮度下降约 15%模型对脏污的误检率翻了一倍。把图像提亮增强后再推理误检率立刻恢复正常。这就是我在部署模块里加亮度校准的原因。排查顺序建议先看图像亮度、对比度、噪点水平再怀疑模型和数据。问题三褶皱和毛头这两个类别的混淆褶皱是一块区域内的纹理方向异常毛头是表面毛羽堆积它们在灰度图像上确实有相似之处。增加这两个类别的样本量后混淆情况有所好转。另外在标注时如果细看褶皱的形状更细长、边缘有明显的走向毛头更偏向“面状扩散”。重新整理标注标准时我会把这两种难分样本的标注规则单独写在文档里要求标注员严格按照形状特征区分。问题四训练时 loss 不降或 NaNloss 不降最常见的是学习率过高和标注数据有误。如果你的标注文件里出现坐标超过 1 或小于 0 的值训练过程中模型就可能计算出 NaN导致训练崩溃。用脚本检查所有 txt 标注文件把非法坐标剔除或修正。loss 为 NaN 还有可能是 batch size 不合适减小 batch 或者降低学习率基本能解决。问题五模型对“未见过的布匹底色”失效这个项目当时训练数据里主要是一种白色坯布但现场还有不同颜色的色织布深色底布上的脏污和浅色底布上的脏污特征完全不同。模型在深色布上的检测效果明显变差。解决思路是补充深色底布的样本做微调训练。这也引出一个教训做工业检测项目要先充分调研现场的材质和颜色种类数据采集阶段就把这些变化全部覆盖不要等部署了再补救。6.3 基于实测的迭代优化记录第一版模型训练完在实验室的静态图像上测试效果不错但拿现场连续视频一跑问题马上暴露动态过程中布面在移动运动模糊导致缺陷边缘不清模型的置信度整体下降约 10 个百分点。针对这个现象我在采集端降低相机曝光时间并配合更亮的光源减少运动模糊而不是在算法端做去模糊——后者图像复原运算量大还会引入伪影。接着又发现板上钉钉的一个问题模型预测的检测框有时候比真实缺陷大了一圈特别是在褶皱这种边界本就不清晰的类别上。这会导致自动化分拣装置在取缺陷位置时覆盖到正常区域。我加了一个后处理修正逻辑针对褶皱和色差这类边界模糊的类别把检测框按比例缩小 10% 作为输出框。因为这类缺陷的标注框本来就有一定主观性缩小一些更接近“有效缺陷区域”。最后说一下类别不均衡问题的进一步优化。我尝试用 focal loss 替代默认的 BCE loss 来缓解难样本问题但 ultralytics 框架内部没有直接暴露切换接口改动成本高。退而求其次我用了类权重采样采样概率与类别样本量成反比让水渍和色差类别的图像每轮被抽到的概率更高。这个改动在训练策略难度上比改 loss 低得多效果立竿见影水渍的 Recall 提升了约 5 个百分点。7. 项目的实际应用效果与扩展价值系统上线运行后我给现场操作人员做了一个简单的操作培训主要讲清楚三件事置信度阈值不要自己乱调缺陷列表里出现误检可以直接忽略系统提示光源异常时及时报修。两周试运行下来自动检测结果与人工复核结果对比系统漏检率约 7%而纯人工检测在该产线的历史漏检率约为 12% 到 15%。在低对比度缺陷上系统的优势尤其明显——人眼容易疲劳忽略的水渍和浅色色差机器的检出率反而稳定。这个项目如果要继续扩展我看到了几个明确的方向一是增加缺陷分割功能YOLO 系列本身有 v8-seg 版本可以输出像素级掩码对缺陷面积测量、等级判定更精确对后续自动裁剪修补也更有价值二是从单机检测走向产线联动把缺陷位置坐标传给后端的自动打标机实现缺陷标记、剔除的完整闭环三是在线学习机制现场新出现的缺陷形态可以定期反馈到训练集做增量训练让系统越用越准。能把这些内容完整分享出来也是因为我在这个项目里踩了足够多的坑。从数据标注的规范到光源角度的选择从阈值设定到部署架构的线程模型每一个环节出现的问题都没有教科书答案只能在现场一点点试。这种项目真正验证了一个朴素但重要的道理目标检测模型只占整个系统的一半另一半是数据质量、环境工程和系统设计。做类似项目的朋友如果一开始看到模型在测试集上效果不错就急着上线大概率会在现场被各种意料之外的问题打回原型。先把现场条件摸透再把数据和模型做扎实这个流程走下来效果不会差。