简介:一套基于OpenCV与Python的PCB板智能检测系统代码包,面向电子制造领域从事视觉检测的工程师、高职院校相关专业学生以及图像处理入门者,解决生产线中PCB焊盘缺陷、焊点质量异常、元件缺失或错位等常见质量问题的自动识别。压缩包共19个文件,包含11个Python脚本、7个pyc编译产物和1个txt说明文件,整体大小42KB;代码按功能模块拆分,camera.py负责图像采集,imgproc.py实现灰度化、二值化与滤波去噪等预处理步骤,modbus.py用于PLC等设备通信,main.py可串联整体流程,test_ui.py则提供可视化测试界面,便于分步调试与验证。目前已有60人学习下载。整套代码展示了从采集图像、特征提取、模板匹配到缺陷判定与结果输出的完整工程链路,配合demo.py和多个测试脚本可直接运行观测检测效果;对于课程设计、毕业设计或小型项目而言,这套紧凑的代码包提供了一个清晰的功能基座,也方便读者基于实际数据调整算法参数,快速上手OpenCV在工业质检中的应用开发。
1. 为什么 PCB 质检还在用 OpenCV:一个老师傅的坚持
PCB 裸板检测在产线上常年被当成“上不了台面”的视觉需求——没有 AI 加持,不敢说智能;可真上深度学习,又发现缺陷样本少得可怜、误检率高得吓人。我做了三年 PCB 光学检测,最常被问的一句话是:“都 2024 年了,OpenCV 那套模板匹配还能打吗?”答案是能打,而且打得漂亮。对缺件、偏移、桥连、划痕这类结构化缺陷,传统视觉的稳定性和可解释性远超一通乱训的 CNN。这个基于 OpenCV 的 PCB 板智能检测系统,本质是把“标准板长什么样”和“待检板哪里不像”这两个问题用图像处理语言翻译一遍,落地成一条可复现、参数透明、加班能调通的产线质检流程。适合谁?适合做视觉工程师和 QA 自动化的人——你能拿到板子的 CAD 原图或良品模板,又不想为几个常见缺陷去標注八千张图。我会把成像、对准、差分、判定全链路拆开讲,坑也一并交代。
2. PCB 检测系统的成像与采集:先让图像听话,再谈算法
2.1 打光方案怎么选:背光、穹顶光和同轴光各自的脾气
PCB 检测八成的翻车都出在成像,而不是算法。算法再强,图像上根本没有缺陷对比度,也是白搭。先说结论:检测缺件、桥连、短路,用红色或蓝色背光,板子放光源上方,元件和焊盘形成高对比剪影;检测划痕、铜箔异物、字符残缺,用穹顶光或同轴光,让表面纹理显形。
背光方案在 OpenCV 处理里极其舒服——背景亮、板子暗、焊盘亮,阈值分割一拉就出干净二值图,几乎不需要做形态学去噪。穹顶光则能把低角度划痕“逼”出来,代价是背景亮度不均匀,预处理阶段要额外做 illumination correction。我的习惯是:一套系统里装两路光源,背光负责主体检测,穹顶光只在划痕检测工位启用,用 GPIO 切换,不在同一帧里混合。
光源颜色也有讲究。PCB 基板通常是绿色或蓝色阻焊,红色光打在绿色板上吸收严重、亮度低,反而让焊盘和走线更亮;蓝色光则相反。实际选型时拿同样一块良品板在不同波长下拍一组图,看焊盘与基板的灰度差,挑差值最大的那一路。
2.2 相机和镜头的参数匹配:不要用 500 万像素去拍 300mm 的板子
很多新手直接拿海康或 Basler 的 500 万像素黑白相机开干,结果发现整块板子拍下来,一个焊盘的宽度只占 8 个像素,缺件检测根本无从谈起。这里有个经验公式:一个焊盘在图像上至少要有 30×30 像素,划痕检测至少要 15 像素宽,否则后续算法再精细也救不回来。
镜头焦距按视野和工作距离来算,公式是焦距 = 工作距离 × 传感器靶面高度 / 视野高度。假设板子长 250mm,视野做到 300mm,工作距离 400mm,靶面高度 4.8mm,那么焦距约等于 6.4mm,选 6mm 镜头合适。如果板子更大,不要想着换更广角的镜头——广角畸变会折磨死后面的对准步骤。我的做法是分区域拍摄,把板子分成四宫格,每个格拍一张,检测逻辑共享一套参数,只是模板各自独立。
采集端还有一个别人很少提的参数:曝光时间。PCB 产线如果带振动,曝光超过 5ms 就会出现边缘模糊,二值化之后焊盘轮廓像狗啃过。开卷帘快门相机时,把曝光锁在 2ms 到 3ms,光圈收到 F8 左右,配合光源亮度把灰度直方图峰值推到 180 到 220 之间。
2.3 固定装置与相机标定:坐标系乱套,后面全是白干
相机的安装高度、角度必须可调可锁,我见过太多用胶带临时粘相机的情况——上一批板子检得好好的,下一批全偏,一看是相机被人碰歪了 2 度。正规做法是把相机固定在龙门架或 C 型臂上,用千分尺调节高度,水平度用气泡水平仪校准。
标定方面,不需要做完整的张正友标定,但要做一个像素到毫米的比例系数标定。方法很简单:放一块已知尺寸的标定片或直接拿标准 PCB 的定位孔,用 OpenCV 的cv2.findContours找出孔的轮廓,用cv2.minEnclosingCircle算直径像素数,除以实际物理直径,就得到scale。这个系数建议每班次验证一次,因为热胀冷缩和焦距微变都会影响它。检测所有物理尺寸相关的缺陷判定,都要乘以这个系数再做阈值比较。
import cv2 import numpy as np # 读取标定图像,灰度化后二值化 img = cv2.imread("calib_board.jpg", cv2.IMREAD_GRAYSCALE) _, binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 提取所有轮廓,找圆形定位孔 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: area = cv2.contourArea(cnt) if area < 1000: # 过滤噪点 continue (x, y), radius = cv2.minEnclosingCircle(cnt) diameter_pixels = radius * 2 # 假设实际定位孔直径是 3.0mm scale = 3.0 / diameter_pixels print(f"标定系数 scale = {scale:.6f} mm/pixel")这段代码的关键是cv2.minEnclosingCircle对圆形轮廓做最小外接圆拟合,抗轮廓残缺的能力比直接算boundingRect强很多。过滤面积小于 1000 像素的轮廓是为了避开灰尘和反光点。实际产线上我建议做三次标定取中位数,避免单次图像噪声造成系数偏差。
3. 图像预处理与位置对准:模板匹配的前置条件
3.1 灰度化、去噪与二值化:不要让滤波毁掉焊盘边缘
PCB 检测里灰度化不是简单的cv2.cvtColor就完事。如果是背光图,红、绿、蓝三个通道里通常有一个对比度最好,直接取那个单通道比加权灰度更可靠。我一般先分离通道,用cv2.mean算三通道的类间方差思路,挑对比度最大的通道作为处理对象。
去噪不要用高斯滤波直接上——cv2.GaussianBlur的核一大,焊盘尖角被磨圆,后面测偏移时误差立刻放大。更稳的做法是先cv2.medianBlur去孤立噪点,再用小核高斯做轻微平滑。中值滤波对椒盐噪声和灰尘颗粒有奇效,且不伤边缘。核大小 3×3 足够,5×5 只在高分辨率大板上才用。
二值化尽量用 Otsu 自适应阈值,不用固定阈值。原因是光源老化或批次板子阻焊颜色差异会导致整体亮度漂移,Otsu 自动找谷底,省去每天调阈值的麻烦。遇到背景亮度不均——比如穹顶光下板角偏暗——就先做cv2.morphologyEx顶帽操作,把不均匀背景压掉再二值化。亮场图用cv2.THRESH_BINARY,暗场图用cv2.THRESH_BINARY_INV,方向别搞反,这是最容易踩的空。
import cv2 import numpy as np def preprocess_board(img_gray, use_inv=False): # 中值滤波去孤立噪点,保护边缘 median = cv2.medianBlur(img_gray, 3) # 顶帽操作:消除不均匀背景,只留前景细节 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15)) tophat = cv2.morphologyEx(median, cv2.MORPH_TOPHAT, kernel) # 用 Otsu 找阈值,不依赖固定亮度 thr_type = cv2.THRESH_BINARY_INV if use_inv else cv2.THRESH_BINARY _, binary = cv2.threshold(tophat, 0, 255, thr_type | cv2.THRESH_OTSU) return binary这里的顶帽核 15×15 是经验值:核太小会把宽走线也当成背景消掉,核太大起不到压背景的作用。如果板子走线间距很密,建议降到 11×11,并检查走线是否断裂。二值化结果直接喂给后面的轮廓分析和模板匹配,不要再做开运算闭运算——那些操作会改变缺陷的真实形状,让后续判定失真。
3.2 用定位孔做刚体变换对准:别急着用模板匹配
PCB 板在产线上的位置不可能每次都完全一致,直接拿良品模板和待检图做差分,结果必然是满屏报警。传统做法是找板上的定位孔——通常 2 到 4 个,镀层圆孔或焊盘圆点——用它们的质心做仿射变换的锚点。
流程是:先按上文的预处理拿二值图,再用cv2.HoughCircles或轮廓面积+圆度过滤找出定位孔。HoughCircles 参数不好调,我更推荐轮廓法——找面积在合理范围内的轮廓,算cv2.arcLength与cv2.contourArea的比值,越接近圆的值越可信。找到定位孔后,用cv2.estimateAffinePartial2D算待检图到模板图的刚体变换矩阵,然后cv2.warpAffine把待检图拉正到模板坐标系。
import cv2 import numpy as np def find_fiducial_center(binary, min_area=500, max_area=5000): contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) candidates = [] for cnt in contours: area = cv2.contourArea(cnt) if not (min_area < area < max_area): continue perimeter = cv2.arcLength(cnt, True) circularity = 4 * np.pi * area / (perimeter * perimeter) if circularity > 0.85: # 接近圆的定位孔 M = cv2.moments(cnt) cx = M["m10"] / M["m00"] cy = M["m01"] / M["m00"] candidates.append((cx, cy)) return candidates # 模板和待检图各找定位孔,取前两个做仿射变换 src_pts = np.array(find_fiducial_center(real_binary)[:2], dtype=np.float32) dst_pts = np.array(find_fiducial_center(tpl_binary)[:2], dtype=np.float32) transform = cv2.estimateAffinePartial2D(src_pts, dst_pts)[0] aligned = cv2.warpAffine(real_gray, transform, (tpl_gray.shape[1], tpl_gray.shape[0]))圆度阈值 0.85 很关键——低于这个值会把一些不规则焊盘误认成定位孔;高于 0.95 又可能漏掉被部分遮挡的孔。如果 PCB 上有多个圆形特征,务必将定位孔设计得比普通焊盘大一圈,面积范围拉开差距,避免候选点混淆。定位孔数量建议至少 3 个,两个虽然理论上够算仿射,但一旦其中一个漏检,整个对准直接失败。
3.3 不同批次板的模板对齐策略:静态模板 vs 每批首件建模板
这是检测系统设计时必须做的决定。静态模板适合产品长期不变、工艺稳定的板子——一次建模板,之后所有批次都用它做基准。缺点是对阻焊色差和蚀刻工艺波动极其敏感,稍微深一点的颜色都能触发批量误报。
我实际产线上更推荐“每批首件建模板”的动态策略。流水线开始前,让作业员把一块确认合格的板子过一遍系统,采集图像存成该批次模板。检测时所有后续板子跟这个首件比。这样做有三个好处:第一,不用维护庞大的模板库;第二,光源在批次间的轻微漂移被自然抵消;第三,PCB 厂改钻孔或改丝印层时不会被旧模板误杀。代价是首件本身可能带微瑕,所以首件必须过人工目检后再建模板。
模板建立的代码同样走一遍预处理和对准,只是把对准后的图像直接存为基准图。后续检测时,所有待检图先跟当前批次模板做仿射对齐,再做差分和缺陷判定。
4. 缺陷检测与分类算法:缺件、偏移、桥连、划痕一网打尽
4.1 模板差分法:核心思想与图像减法后的处理
差分检测的原理一句话:对准后,待检图与模板图逐像素相减,差值大于阈值的位置就是缺陷候选区域。OpenCV 里用cv2.absdiff实现。但直接相减的结果是满屏的微小噪声和边缘伪影,必须配合形态学过滤才能用。
正确流程是:对两张二值图做差分 → 二值化差值图 → 用开运算去掉单个像素噪点 → 用闭运算把断裂的缺陷连接成完整区域 → 找轮廓 → 按面积过滤 → 输出缺陷框。这里每一步的核大小都会直接影响检测灵敏度,核设大了小缺陷被吞,核设小了噪声被当成缺陷。我的经验是开运算核 3×3,闭运算核 5×5,按像素为单位的 PCB 图像精度足够。
import cv2 import numpy as np def diff_detect(aligned_binary, tpl_binary, min_area=50): diff = cv2.absdiff(aligned_binary, tpl_binary) _, diff_binary = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY) # 开运算去孤立噪点,闭运算连断裂缺陷 open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) cleaned = cv2.morphologyEx(diff_binary, cv2.MORPH_OPEN, open_kernel) cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, close_kernel) contours, _ = cv2.findContours(cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) defects = [] for cnt in contours: area = cv2.contourArea(cnt) if area < min_area: continue x, y, w, h = cv2.boundingRect(cnt) defects.append((x, y, w, h, area)) return defectsmin_area是误检率的闸门。缺件检测时焊盘整体缺失会形成几百上千像素的大面积差分区域,设 50 像素完全足够;但划痕检测的差分区域可能只有十几像素,min_area 要降到 10 以下。这个参数不要试图在全板统一,按检测项目分 ROI 区域分别设值。
4.2 缺件检测:用连通域面积和焊盘坐标双重判定
缺件最容易和“焊盘反光差异”混淆。只依赖差分面积会误报,必须结合焊盘的先验坐标。做法是:先在模板图上建立每个焊盘的 ROI 列表——坐标由模板的焊盘轮廓质心给出;检测时只在这些 ROI 内部找差分区域,面积占比超过阈值就判缺件。
具体判定规则:ROI 内差分面积与焊盘面积的比值超过 30% 判缺件,低于 30% 判为脏污或反光差异。这样即使差分面积绝对值很大,只要位置不在焊盘上就不触发缺件报警。这是模板差分最容易翻车的细节——不加 ROI 约束的全局差分,看到的就是整板全红。
import cv2 import numpy as np def detect_missing(aligned_binary, tpl_binary, pad_rois, missing_ratio=0.3): defects = [] for (px, py, pw, ph) in pad_rois: roi_aligned = aligned_binary[py:py+ph, px:px+pw] roi_tpl = tpl_binary[py:py+ph, px:px+pw] diff_area = cv2.countNonZero(cv2.absdiff(roi_aligned, roi_tpl)) pad_area = cv2.countNonZero(roi_tpl) if pad_area == 0: continue if diff_area / pad_area > missing_ratio: defects.append((px, py, pw, ph, "missing", diff_area / pad_area)) return defectspad_rois怎么来?模板二值图上跑cv2.findContours,把每个焊盘轮廓的外接矩形存进列表即可。这里务必注意 ROI 位置的全属性——使用上一章的仿射变换对齐后,模板和待检图必须在同一坐标系下,否则 ROI 框里比对的就是两张错位图。如果产线振动导致大幅偏移,对齐失败时直接判为“对位失败”报警停机,不要继续检测。
4.3 偏移检测:重心对比法,比差分更抗噪声
偏移检测用不上差分。差分只能回答“这里不一样”,回答不了“焊盘是不是偏了 0.2mm”。正确做法是分别提取模板图和待检图上每个焊盘的轮廓质心,计算质心在 X 和 Y 方向的位移量,超过阈值就判偏移。
质心提取依赖二值图质量,所以前面对准步骤的成败直接决定这里的精度。质心用cv2.moments计算,位移量用欧氏距离公式。注意一点:如果待检板上有元件遮挡——贴片电容已贴上去——焊盘质心会严重偏移,所以偏移检测必须在裸板阶段做,这是系统设计时就要跟产线确认的边界条件。
import cv2 import numpy as np def check_pad_shift(aligned_binary, tpl_binary, max_shift_px=3.0): _, aligned_contours, _ = cv2.findContours(aligned_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) _, tpl_contours, _ = cv2.findContours(tpl_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(aligned_contours) != len(tpl_contours): # 轮廓数量不一致,可能是缺件或桥连,先停止偏移判定 return None shifts = [] for cnt_real, cnt_tpl in zip(aligned_contours, tpl_contours): M_real = cv2.moments(cnt_real) M_tpl = cv2.moments(cnt_tpl) if M_real["m00"] == 0 or M_tpl["m00"] == 0: continue cx_real = M_real["m10"] / M_real["m00"] cy_real = M_real["m01"] / M_real["m00"] cx_tpl = M_tpl["m10"] / M_tpl["m00"] cy_tpl = M_tpl["m01"] / M_tpl["m00"] dist = np.sqrt((cx_real - cx_tpl) ** 2 + (cy_real - cy_tpl) ** 2) shifts.append(dist) return max(shifts) if shifts else None每块板子焊盘几百个,逐对计算质心耗时大概在毫秒级,性能不用太担心。真正要关注的是max_shift_px这个参数怎么设:它对应物理位移的上限,等于max_shift_mm / scale。比如允许 0.1mm 偏移,标定系数是 0.05mm/pixel,那么阈值就是 2 像素。0.1mm 是 IPC 标准的常见偏差等级,但不同板厂工艺能力不同,首件调试时建议实测正常板的质心偏差分布,取 3 倍标准差作为阈值。
4.4 桥连与划痕检测:用直线检测和轮廓旋转框过滤特征
桥连检测依赖一个特征:相邻焊盘之间出现了一条异常连接带。OpenCV 处理时,先对差分区域做cv2.minAreaRect拿旋转外接矩形,桥连区域的长宽比通常大于 3:1,且方向与焊盘排列方向平行。用这个特征可以把桥连和圆形污点区分开。
直线相关的缺陷——比如划痕或铜箔毛刺——用cv2.HoughLinesP在差分区域的边缘图上做概率霍夫直线检测。虽然搜索词里“opencv 检测直线”热度很高,但 HoughLinesP 不是万能的,它要求直线是直的,而且参数稍调不当就全图乱画。我的经验是:差分区域的轮廓宽度大于 3 像素时,直接计算轮廓的cv2.fitLine拟合线,看拟合残差和线长度。残差小且长度超过设定值,就判为划痕。这个方法比 Hough 抗锯齿能力强得多,因为 fitLine 用的是最小二乘而不是像素投票。
import cv2 import numpy as np def detect_bridge_and_scratch(contour, scale=0.05, bridge_ratio=3.0, scratch_min_len=50): # 判断桥连:用最小外接矩形长宽比 rect = cv2.minAreaRect(contour) w, h = rect[1] if w == 0 or h == 0: return None aspect = max(w, h) / min(w, h) if aspect > bridge_ratio and max(w, h) * scale > 0.8: return "bridge" # 判断划痕:拟合直线,看残差和线段长度 if len(contour) < 5: return None [vx, vy, x0, y0] = cv2.fitLine(contour, cv2.DIST_L2, 0, 0.01, 0.01) # 计算所有点到拟合直线的平均距离,残差小 = 形状接近直线 pts = contour.squeeze() dx = pts[:, 0] - x0 dy = pts[:, 1] - y0 dist = np.abs(dx * vy - dy * vx) / np.sqrt(vx ** 2 + vy ** 2) mean_residual = np.mean(dist) # 轮廓总长度作为划痕长度 length = cv2.arcLength(contour, False) if mean_residual < 1.5 and length * scale > scratch_min_len: return "scratch" return "unknown"bridge_ratio设 3.0 已经能过滤绝大多数圆形颗粒缺陷,误判点主要集中在斜 45 度的长条形走线——因为minAreaRect也会把正常走线识别成高长宽比。所以桥连判定不能只看几何,还要叠加位置约束:桥连区的两端必须落在了两个相邻焊盘的 ROI 范围内。这个约束在代码里体现为对桥连线段两端点做坐标判断,实际调测时很好用。
5. 避坑指南:PCB 检测系统调试中的 5 个典型翻车现场
5.1 现象:同一块良品板反复报警,差分区域集中在板边
原因:板边定位孔识别不稳定,仿射变换矩阵计算时用了被污染的定位孔坐标——比如定位孔旁边有铜皮残渣,轮廓面积超出了面积过滤范围,圆度判断通过但质心偏了。
解决:把定位孔面积上下限收紧,并对每个候选定位孔计算多帧平均位置。更彻底的办法是改用三个定位孔做透视变换cv2.getPerspectiveTransform,只用三点的稳定性来抵消单点噪声,实测能将板边误报率压掉一半以上。
5.2 现象:缺件误报率高达 20%,集中在 BGA 焊盘区域
原因:BGA 焊盘阵列密集,单个焊盘面积小,差分噪声与焊盘面积的比值天然偏高,30% 的面积占比阈值对普通焊盘有效,对 BGA 焊盘则过于敏感。
解决:为 BGA 区域单独建 ROI 列表,阈值从 30% 调整为 50%。如果 BGA 焊盘只有 20×20 像素,一个灰尘颗粒造成 5 像素的差分就是 25% 面积占比,误报几乎必然。此外对 BGA 区域单独做中值滤波增强后再差分,能再降 5 到 8 个百分点的误报。
5.3 现象:划痕检测完全不报,实际板子有明显刮伤
原因:fitLine残差阈值设成了 1.5 像素,划痕宽度较大时边缘轮廓本身就有弧度,平均残差超过 2 像素,被判成了 unknown。另一个原因是划痕区域在预处理阶段被闭运算核 5×5 完全填平,差分区域消失。
解决:划痕检测使用独立的预处理分支,闭运算核降为 3×3,残差阈值放宽到 3.0。同时把划痕检测的差分图像单独输出,人工核对一遍确认缺陷区域没有被形态学吞掉,再谈阈值。
5.4 现象:产线换了一批板子后全板报警
原因:新批次阻焊油墨颜色有细微变化,二值化后焊盘和基板的面积比整体漂移,全局模板差分把颜色差异全算成了异常。静态模板方案下这是无解死局。
解决:切到“每批首件建模板”策略。首件过机时如果差分面积超过全板面积的 2%,强制人工复核后再放行;复核通过才允许将其存为本批次模板。这块的逻辑要在软件里做成防呆流程,防止作业员误操作把不良首件存成了基准。
5.5 现象:OpenCV 安装后cv2.findContours返回值数量报错
原因:OpenCV 3.x 和 4.x 的findContours签名不一致。3.x 返回三个值image, contours, hierarchy,4.x 只返回contours, hierarchy。网上搜到的代码版本混乱,照抄直接崩。
解决:统一装 4.x 版本,代码里按contours, _ = cv2.findContours(...)解包。如果确需兼容旧代码,可以用 try 分叉处理。顺便说一句,ModuleNotFoundError: No module named 'cv2'大多是 pip 装到了python3而代码跑在python,两个解释器不是同一个,看清楚 which python 再 pip。
6. 系统验证与进阶:从算法原型到产线可靠运行的最后一公里
系统做出来以后,验证阶段最能拉开差距。不要拿三块板子跑一遍就宣布完成,要做三组数据:每组取 50 块良品、20 块含缺件、20 块含偏移或桥连,统计检出率和误检率。算法层面的验收指标建议设定为:缺件检出率 100%,偏移检出率 ≥ 99%,桥连检出率 ≥ 98%,误检率 ≤ 2%。达不到就回去调 ROI 面积阈值或形态学核大小,不要先用置信度模糊糊弄过去。
部署时优先把检测逻辑封装成独立的 Python 类,接口只暴露detect(image) -> list[DefectRecord],这样换光源、换相机分辨率时,只有预处理内部需要改,判定接口保持稳定。同时把模板、标定系数、每个 ROI 的阈值统一存成 JSON 配置,换批次只改配置不动代码。这个习惯救过我太多次。
进阶方向上,建议在 OpenCV 管线之上叠加一层规则引擎:当某个缺陷连续出现在同一区域超过 N 次,自动提升该区域的关注等级或调整曝光补偿。这是从“单张图检测”走向“产线级监测”的顺滑过渡,不需要深度学习也能实现大多数 PCB 裸板的质检刚需。如果未来要处理贴片元件的检测,再考虑引入目标检测模型也不迟——但那是另一套工程,别把传统方案还没吃透的板子直接交给神经网络去翻车。
验证完精度的最后一步是记录所有缺陷图像,按缺陷类别归档。半年后你会感谢自己——当客户甩来一张模糊的缺陷板照片问“这是什么”,你翻出归档里的同款图像跟他对标签,比现场争论“你们系统到底行不行”有效率十倍。算下来这个基于 OpenCV 的方案,调试成本低、参数透明可见、每块板子的检测时间按我的经验控制在 120ms 到 200ms 之间。这就是它至今仍被产线老师傅偏爱的原因。希望这次的拆解和踩坑记录能帮你的检测系统少走一次弯路,也希望你落地时把每一步参数都写进调试日志,别信存储,信纸质的工程师直觉。
本文还有配套的精品资源,点击获取