Markdown 博客正文草稿

大家好!最近在筹备一个工业互联网相关的比赛,平时咱们搞惯了单片机底层(比如对着 STM32 的数据手册撸寄存器、写驱动),面对自己画出来的 PCB 板子,往往只关注电气特性。但这次赛题涉及到产线后端的工业质检场景,也就是怎么用机器视觉把有瑕疵的坏板子挑出来。

今天就把我这套基于 YOLOv8n + PyQt5 构建的 PCB 缺陷智能检测系统 开源并拆解给大家。项目涵盖了从数据集格式转换、模型训练调优到最终桌面端 GUI 闭环演示的全流程。模型最终 mAP50 达到了 98.5%,权重仅 6.3MB,非常适合后续往边缘计算板卡上移植!

一、 核心痛点与技术选型

做工业质检,最大的痛点往往不是模型有多复杂,而是数据非标落地难

  • 算法侧:我选用了 YOLOv8n。带个 "n" (nano) 的原因很简单,工业现场最终是要上边缘端部署的,轻量化是第一要义。单图推理约 59.8ms,能保证检测的实时性。

  • 数据侧:采用了 DeepPCB 公开数据集,包含开路、短路、鼠咬、毛刺、针孔、伪铜共 6 类典型缺陷

  • 交互侧:采用 PyQt5 开发了桌面端可视化界面,方便做 Demo 演示,也为后续工业通信联动打底。

二、 数据预处理实战:DeepPCB 转 YOLO 格式

网上的开源数据集格式五花八门,DeepPCB 默认的 txt 标注给的是 [x1, y1, x2, y2, cls](左上角和右下角坐标)。而咱们 YOLO 训练需要的是归一化后的中心点坐标及宽高 [cls, cx, cy, w, h]

这里必须手写脚本转换,非常容易踩坑的地方在于坐标的除法归一化。以下是我的 convert.py 中的核心解析逻辑:

Python

def parse_annotation(txt_path, img_w=640, img_h=640):
    yolo_lines = []
    try:
        with open(txt_path, 'r', encoding='utf-8') as f:
            for line in f:
                parts = line.strip().split()
                if len(parts) < 5:
                    continue
                # 解析原始数据:x1, y1 (左上角), x2, y2 (右下角)
                x1,y1,x2,y2,cls = int(parts[0]),int(parts[1]),int(parts[2]),int(parts[3]),int(parts[4])
                
                # 容错处理:剔除异常坐标
                if x2<=x1 or y2<=y1:
                    continue
                
                # 核心转换逻辑:计算中心点坐标并除以图像宽高进行归一化
                cx = ((x1+x2)/2)/img_w
                cy = ((y1+y2)/2)/img_h
                w  = (x2-x1)/img_w
                h  = (y2-y1)/img_h
                
                # 注意:YOLO类别索引从0开始,DeepPCB可能从1开始,记得 cls-1
                yolo_lines.append(f"{cls-1} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}")
    except Exception as e:
        print(f"read error: {txt_path} -> {e}")
    return yolo_lines

💡 开发者避坑指南: > 很多小伙伴做视觉检测时,训练出来的框满天飞,90% 都是因为没有针对图片真实分辨率做正确归一化。本例中我统一将输入图像重置为 640x640

三、 YOLOv8 模型训练与性能验证

搞定数据后,在本地 CPU 环境(Intel i9-12900H)跑了 50 个 Epoch,耗时大概将近 4 个小时。

最终的验证集指标非常漂亮:

  • 总体 mAP50 达到了 98.5%

  • 各类缺陷检出率:其中 Pinhole(针孔) 高达 99.2%,最低的 Short(短路) 也有 97.7%。

  • 模型体积:仅 6.3MB(8.1 GFLOPs),对于算力有限的嵌入式平台极其友好。

四、 PyQt5 工业级可视化界面集成

为了让系统真正“可用”,我用 PyQt5 写了一个本地 GUI 工具(pcb_demo.py)。逻辑不复杂:上传图片 -> 触发推理 -> 解析检测框 -> 渲染状态

在实际工业场景中,操作员最关心的就是“良品(PASS)”和“不良品(NG)”。我在代码里对 YOLO 输出的 boxes 做了状态判定:

# 截取 pcb_demo.py 核心推理与告警逻辑片段
results = self.model(img)
boxes = results[0].boxes

# 判断逻辑:如果未检测到任何缺陷框,判定为 PASS
if len(boxes) == 0:
    self.status_label.setText("PASS - NO DEFECTS FOUND")
    self.status_label.setStyleSheet("font-size: 28px; font-weight: bold; color: white; background-color: #4CAF50; padding: 15px; border-radius: 8px;")
else:
    # 提取所有检测到的缺陷种类,去重后拼接到告警字符串中
    detected_classes = [self.model.names[int(c)] for c in boxes.cls]
    unique_defects = list(set(detected_classes))
    defects_str = ", ".join(unique_defects)
    
    self.status_label.setText(f"NG - DEFECT DETECTED: {defects_str.upper()}")
    self.status_label.setStyleSheet("font-size: 28px; font-weight: bold; color: white; background-color: #F44336; padding: 15px; border-radius: 8px;")

# 绘制标注框并转换为 Qt 图像显示 (注意 OpenCV 默认 BGR,Qt 需要 RGB)
annotated_img = results[0].plot()
annotated_img = cv2.cvtColor(annotated_img, cv2.COLOR_BGR2RGB)

经典踩坑点: 注意倒数第二行代码!OpenCV 读取图片默认是 BGR 格式,而 PyQt 的 QImage 默认吃 RGB 格式。如果不做 cv2.cvtColor 转换,显示出来的画面颜色会像阴间滤镜一样,这在刚开始搞 Python 视觉集成时是必踩的坑。

五、 总结与交流

整个项目走下来,我们完成了从数据集构建清洗 -> 模型训练优化 -> GUI 可视化告警 的全闭环。基于 6.3MB 的轻量化体积,这套模型接下来完全可以部署到边缘计算设备甚至高端的 ARM 核心板上,结合我们熟悉的 C 语言底层驱动,实现真正的“边缘检测 + 产线联动”。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐