3. PCB板焊点缺陷检测
任务说明
本案例针对PCB板焊点图像,通过图像分割与形态学操作,识别两类常见缺陷:桥接(相邻焊点间多余焊料连通)与缺焊(焊盘上无焊料或焊料严重不足)。输入为单张PCB焊点灰度图,输出为标注缺陷位置的图像及缺陷统计结果。
实现方案
采用OpenCV实现完整处理流水线:阈值分割提取焊料区域 → 连通域分析定位各焊点 → 形态学开运算分离桥接 → 面积与形状判据区分正常/桥接/缺焊。核心思路:正常焊点近似圆形且面积在合理区间;桥接焊点经开运算后面积显著减小;缺焊焊盘区域无焊料覆盖。
完整代码
import cv2
import numpy as np
def detect_solder_defects(img_path, min_area=80, max_area=800, circularity_thresh=0.6):
"""
检测PCB焊点缺陷(桥接/缺焊)
返回: 标注图, 缺陷统计字典
"""
# 1. 读取与预处理
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise FileNotFoundError(f"无法读取图像: {img_path}")
# 反色:焊料为亮色,背景为暗色
_, binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 2. 形态学去噪(去除孤立小噪点)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
binary_clean = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=1)
# 3. 连通域分析(原始焊料区域)
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(binary_clean, 8)
# 4. 焊盘位置估计:对原图做闭运算填充焊盘区域(用于缺焊判断)
close_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
pad_region = cv2.morphologyEx(binary_clean, cv2.MORPH_CLOSE, close_kernel, iterations=2)
# 5. 形态学开运算(分离桥接焊点)
open_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
binary_opened = cv2.morphologyEx(binary_clean, cv2.MORPH_OPEN, open_kernel, iterations=2)
num_labels_op, labels_op, stats_op, _ = cv2.connectedComponentsWithStats(binary_opened, 8)
# 6. 结果标注
result = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
defects = {"bridge": 0, "missing": 0, "normal": 0}
# 6.1 遍历原始连通域,判断桥接与正常
for i in range(1, num_labels):
x, y, w, h, area = stats[i]
if area < min_area:
continue # 忽略小噪点
# 计算圆形度
contour, _ = cv2.findContours((labels == i).astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contour:
continue
perimeter = cv2.arcLength(contour[0], True)
circularity = 4 * np.pi * area / (perimeter * perimeter) if perimeter > 0 else 0
# 判断桥接:开运算后该区域分裂成多个连通域,或面积显著减小
opened_area = np.sum(labels_op[labels == i] > 0)
if opened_area < area * 0.7 or circularity < circularity_thresh:
defects["bridge"] += 1
cv2.rectangle(result, (x, y), (x + w, y + h), (0, 0, 255), 2) # 红色框
cv2.putText(result, "bridge", (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
else:
defects["normal"] += 1
cv2.rectangle(result, (x, y), (x + w, y + h), (0, 255, 0), 2) # 绿色框
# 6.2 缺焊检测:焊盘区域(闭运算结果)中无焊料覆盖的部分
pad_labels, pad_stats = np.unique(labels[pad_region > 0], return_counts=True)
for i in range(1, num_labels):
x, y, w, h, area = stats[i]
if area < min_area:
continue
# 该连通域是否覆盖了对应焊盘的大部分
pad_mask = (pad_region > 0) & (labels == i)
if np.sum(pad_mask) > 0:
pad_area = np.sum(pad_mask)
if area / pad_area < 0.3: # 焊料面积不足焊盘30%
defects["missing"] += 1
cv2.rectangle(result, (x, y), (x + w, y + h), (255, 0, 0), 2) # 蓝色框
cv2.putText(result, "missing", (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
return result, defects
if __name__ == "__main__":
# 运行示例(需准备pcb_solder.png测试图)
img_path = "pcb_solder.png"
result_img, stats = detect_solder_defects(img_path)
print(f"缺陷统计: {stats}")
cv2.imwrite("defect_result.png", result_img)
print("标注结果已保存至 defect_result.png")
运行与验证
依赖安装:
pip install opencv-python numpy
运行方式:将代码保存为 pcb_defect_detect.py,准备一张包含正常焊点、桥接和缺焊的PCB灰度图命名为 pcb_solder.png 置于同目录,执行:
python pcb_defect_detect.py
通过条件:
- 程序无报错退出,控制台输出缺陷统计字典;
- 生成的
defect_result.png中:桥接缺陷被红色框标注、缺焊被蓝色框标注、正常焊点为绿色框; - 对已知缺陷数量的测试图,统计结果与人工标注一致(允许±1个像素级误差)。
参数调优提示:若检测效果不佳,优先调整 min_area/max_area 适配焊点实际像素尺寸;桥接误判时增大开运算核尺寸(当前为5×5);缺焊漏检时增大闭运算核尺寸(当前为15×15)以更完整覆盖焊盘。
常见问题
- 图像为彩色图:需先转灰度,可在读取后添加
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY); - 焊料为暗色背景为亮色:需反转二值化结果,将
cv2.THRESH_BINARY改为cv2.THRESH_BINARY_INV; - 焊点大小差异大:建议按实际图像分辨率等比缩放
min_area与max_area,或改用自适应阈值分割。