
简介这份PDF资料面向从事机器视觉与图像处理的工程师及技术学习者系统梳理工业缺陷检测的完整知识体系帮助读者建立从硬件选型到算法落地的整体认知。内容围绕视觉检测系统的三大模块展开硬件部分详解光源类型与照明方式的选择逻辑涵盖LED、萤光灯、卤素灯的特性对比以及背向、前向、同轴、低角度等照射方式的适用场景并延伸至相机分类、分辨率、帧率、镜头与图像采集卡的选型要点软件部分则介绍图像预处理与检测处理的常用方法如边缘检测、模板匹配、灰度变换等并提及市面主流算法库。资源包为单个PDF文件大小约1.26MB轻量便携适合随时查阅。目前已有1188人学习内容兼顾尺寸测量、表面缺陷检测与Logo识别等典型应用可作为部门内部分享或项目选型时的参考手册。1. 机器视觉工业缺陷检测从一份 PDF 标题说起这条路到底怎么走产线上一个工件从相机底下过0.3 秒内要判断它有没有划痕、缺料、毛刺、脏污判定完还得把 NG 品吹掉——这是机器视觉工业缺陷检测最典型的场景。很多人是从一份叫《机器视觉工业缺陷检测的那些事》的 PDF 开始接触这个方向的标题看着朴素背后却是一整条从光源、工业相机、镜头选型到图像处理算法、再到和 PLC 通信的完整链路。它要解决的问题很具体用工业相机替代人眼在高速、高重复性的工况下稳定地把不良品挑出来。适合谁看适合刚入行的机器视觉应用工程师、做非标自动化的电气工程师以及想从 OpenCV 图像处理转向工业落地的开发者。这篇不聊虚的按我实际做项目的顺序把选型、打光、算法、踩坑一条条拆开讲。2. 先立住理论缺陷检测到底在检测什么2.1 缺陷的四种物理形态决定了你的技术路线工业缺陷检测不是笼统的“找不同”落到产线上缺陷基本分四类每一类对应的成像和算法思路完全不同。第一类是几何缺陷比如缺角、崩边、尺寸超差、孔位偏移。这类缺陷本质是轮廓和尺寸问题用背光打光拿到清晰边缘再做亚像素边缘提取和尺寸测量就能搞定OpenCV 里的findContours加minAreaRect是常用组合。第二类是表面缺陷划痕、凹坑、麻点、氧化斑。这类最难因为它不改变轮廓只改变局部灰度或纹理。常见做法是用低角度环形光或同轴光把缺陷“打亮”或“打暗”再用频域滤波、Gabor 滤波或者局部对比度增强把它从背景里抠出来。第三类是颜色/材质缺陷色差、混料、镀层不均。这类必须用彩色相机而且对光源色温稳定性要求极高光源一飘判定阈值就废了。第四类是装配缺陷漏装、错装、装反。这类往往靠模板匹配加区域存在性判断matchTemplate配合 ROI 掩膜是入门方案复杂装配体得上深度学习。选型的第一步不是挑相机而是先问清楚这个缺陷在图像上表现为灰度差、颜色差还是几何差答不上来后面全是白干。2.2 光源和工业相机成像质量的上限在打光阶段就定了行业里有句话打光打好了算法就成功了一半。这不是玄学是血泪经验。同一个划痕用错光源拍出来跟背景一个灰度再牛的算法也救不回来。光源选型看三个维度形状、角度、颜色。形状上环形光适合一般表面照明条形光适合大平面或配合角度打侧光同轴光适合高反光金属表面背光适合轮廓测量穹顶光Dome适合曲面和反光件的均匀照明。角度上低角度15°~30°掠射能把划痕、凹坑的阴影拉出来高角度适合整体均匀。颜色上利用互补色吸收原理——比如检测蓝色油墨上的缺陷用红色光源能让蓝色区域变暗、缺陷更突出。工业相机选型看四个参数分辨率、帧率、接口、传感器类型。参数怎么定常见坑分辨率最小缺陷尺寸 × 3~5 像素再乘视野只按视野算忽略缺陷像素占比帧率产线节拍 ÷ 单件检测时间留 30% 余量忽略曝光时间和传输耗时接口GigE 够用高速用 USB3.0 或 Camera LinkGigE 带宽不够导致丢帧传感器黑白灵敏度高彩色看色差该用黑白却上彩色白白损失灵敏度Basler、大华这些品牌的工业相机在驱动和 SDK 上各有生态选型时除了参数还要确认 SDK 是否支持你的开发语言和操作系统否则后期集成会很难受。2.3 从图像处理到深度学习什么时候该上哪套不是所有缺陷检测都值得上深度学习。我的判断标准很简单缺陷形态固定、背景稳定、能用规则描述 → 传统图像处理快、可解释、好维护。缺陷形态多变、背景复杂、规则写不出来 → 深度学习但要有足够样本。传统图像处理的典型流程是灰度化 → 滤波去噪 → 阈值分割/边缘检测 → 形态学处理 → 特征提取 → 判定。OpenCV 的膨胀腐蚀、Canny、自适应阈值这些算子能覆盖大部分简单场景。傅里叶变换在周期性纹理缺陷检测里特别好用——把图像转到频域周期性背景变成固定亮点滤掉它再逆变换缺陷就露出来了。深度学习方案常见的是分类判断 OK/NG和分割像素级定位缺陷。分类网络轻量、样本需求相对少分割网络精度高但标注成本大。实际项目里我一般先用传统方法快速验证缺陷是否“可成像”成像不行就别急着标数据训模型。3. 动手复现一套最小可跑的缺陷检测流程3.1 环境搭建与工业相机取图先搭环境。Python 生态下OpenCV 做图像处理相机 SDK 负责取图。以常见的 GigE 工业相机为例厂商一般提供 Python 或 C 的 SDK取到图后转成 numpy 数组交给 OpenCV。# 建议用虚拟环境避免和系统包冲突 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install opencv-python numpy # 相机 SDK 按厂商文档单独安装通常提供 .whl 或需要编译取图这一步的关键是曝光和增益要锁死。自动曝光在产线上是灾难因为工件反光变化会让相机不停调整导致同一缺陷在不同帧里灰度不一致。import cv2 import numpy as np # 假设相机 SDK 已经取到一帧并转为 numpy 数组 frame # frame 通常是灰度图 (H, W) 或彩色 (H, W, 3) def preprocess(frame): # 转灰度如果相机直接出灰度图可跳过 if len(frame.shape) 3: gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) else: gray frame # 高斯滤波去噪核大小按缺陷尺度调一般 3~7 blur cv2.GaussianBlur(gray, (5, 5), 0) return blur逻辑说明cvtColor把彩色转灰度是为了降低计算量并提升对比度稳定性GaussianBlur的核大小是核心参数核太大缺陷被抹掉核太小噪声去不掉一般从 3 开始试。参数没有万能值必须拿实际工件图调。3.2 用形态学和阈值分割把缺陷抠出来拿到预处理图后下一步是把缺陷区域和背景分开。表面缺陷常用“局部对比度”思路先做一个大核的均值滤波得到背景估计再用原图减背景缺陷就凸显出来了。def detect_surface_defect(blur): # 大核均值滤波估计背景核大小要大于缺陷尺寸 background cv2.blur(blur, (51, 51)) # 原图减背景得到局部差异图 diff cv2.absdiff(blur, background) # 自适应阈值分割把差异明显的区域提出来 _, thresh cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY) # 形态学开运算去小噪点闭运算连接断裂区域 kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) opened cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) closed cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel) return closed def judge(closed, min_area50): contours, _ cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) defects [] for cnt in contours: area cv2.contourArea(cnt) if area min_area: # 面积阈值过滤噪声 x, y, w, h cv2.boundingRect(cnt) defects.append((x, y, w, h, area)) return defects逻辑说明cv2.blur的核大小必须大于缺陷尺寸否则缺陷会被当成背景的一部分减掉threshold的阈值 25 是经验值实际要拿 OK 品和 NG 品的差异图统计后定min_area是最小缺陷面积直接决定误报率设太小会把灰尘当缺陷设太大会漏检小划痕。形态学开运算先腐蚀后膨胀专门去孤立噪点闭运算先膨胀后腐蚀用来把断开的缺陷连起来。3.3 傅里叶变换处理周期性纹理背景纺织、PCB、金属拉丝面这类有周期性纹理的工件空间域阈值分割很容易把纹理也当成缺陷。这时候把图像转到频域周期性纹理会在频谱上形成规律亮点滤掉它们再逆变换背景就干净了。def fft_filter(gray): # 傅里叶变换并移到中心 f np.fft.fft2(gray) fshift np.fft.fftshift(f) # 构造掩膜滤掉中心低频和周期性高频亮点 rows, cols gray.shape crow, ccol rows // 2, cols // 2 mask np.ones((rows, cols), np.uint8) # 滤掉中心低频保留整体亮度趋势可缩小半径 r 30 mask[crow-r:crowr, ccol-r:ccolr] 0 # 滤掉指定周期性亮点坐标需根据实际频谱图确定 # mask[y1:y2, x1:x2] 0 fshift fshift * mask # 逆变换回空间域 f_ishift np.fft.ifftshift(fshift) img_back np.fft.ifft2(f_ishift) return np.abs(img_back)逻辑说明fftshift把零频移到中心方便操作中心低频掩膜半径r控制保留多少整体亮度信息太小会丢失背景太大会把缺陷也滤掉周期性亮点的坐标必须看实际频谱图手动标没有通用值。这一步的坑在于掩膜设计过度会引入振铃效应逆变换后出现假的边缘所以掩膜边缘最好做渐变过渡而不是硬切。4. 避坑与排查产线上最容易翻车的五个点4.1 现象同一批工件白天判 OK 晚上判 NG原因环境光干扰。产线窗户透进来的自然光随时间变化叠加在光源上改变了整体亮度阈值分割的固定阈值就失效了。解决加遮光罩把工位封起来或者改用自适应阈值cv2.adaptiveThreshold再或者每次检测前用标准白板做一次亮度校准。最稳的是物理遮光别指望算法兜底。4.2 现象相机偶尔丢帧NG 品漏检原因GigE 接口带宽被占满或者网卡不是独立网卡、和办公网络混用。触发模式下曝光时间过长也会导致帧率跟不上节拍。解决相机单独走一块千兆网卡关闭节能模式网卡巨帧Jumbo Frame开到 9K曝光时间压到节拍允许的最小值用硬触发代替软触发减少通信延迟。4.3 现象算法在实验室跑得好上产线误报率飙升原因实验室用的是挑出来的“标准图”产线上工件有油污、有振动、有温度漂移。样本不具代表性阈值过拟合。解决采集至少覆盖一个班次的连续图像做验证把 OK 品的灰度分布统计出来阈值定在分布边缘而不是拍脑袋。振动大的工位要加固相机支架别小看机械稳定性。4.4 现象光源用几个月后检测效果变差原因LED 光源光衰或者光源散热不好导致亮度漂移。光源散热是常被忽略的点大功率环形光连续工作温度能到六七十度光衰加速。解决选带散热结构的光源或者加风扇主动散热定期用照度计测光源输出做亮度补偿光源控制器用恒流源而不是恒压源亮度更稳。4.5 现象深度学习模型训练集准确率 99%上线就崩原因训练集和产线实际分布不一致或者数据泄漏同一工件的不同帧同时进了训练集和验证集。类别不平衡也会让模型偏向多数类。解决按工件而不是按帧划分数据集NG 样本少就做数据增强但增强方式要符合实际缺陷形态别乱旋转上线前用一批从未参与训练的产线图做盲测盲测通过再上。5. 进阶技巧把检测节拍压到极致的一个习惯做工业缺陷检测算法精度只是及格线节拍才是决定项目能不能验收的硬指标。我见过太多方案精度没问题但单件检测耗时 800ms产线节拍要求 300ms直接废掉。压节拍的核心习惯是把耗时操作从每帧循环里挪出去。具体做法有这么几条。第一ROI 裁剪。整幅图 500 万像素但缺陷只可能出现在工件区域先把 ROI 裁出来后续所有操作的数据量直接降一个数量级。ROI 坐标在相机固定后就是常量标定一次写死。第二查表代替计算。阈值分割、形态学这些操作的参数如果固定可以预先算好查找表LUT用cv2.LUT做灰度映射比逐像素计算快得多。第三多线程流水线。取图、处理、通信分三个线程用队列串起来。取图线程只管拿图处理线程只管算通信线程只管发结果。这样相机曝光的时间和处理时间重叠整体节拍取决于最慢的那一环而不是三者之和。import threading import queue img_queue queue.Queue(maxsize2) # 缓冲两帧防止内存涨 result_queue queue.Queue(maxsize2) def grab_thread(camera): while running: frame camera.grab() # 阻塞取图 if img_queue.full(): img_queue.get() # 丢旧帧保实时 img_queue.put(frame) def process_thread(): while running: frame img_queue.get() result detect(frame) # 你的检测函数 result_queue.put(result) def comm_thread(plc): while running: result result_queue.get() plc.send(result) # 发结果给 PLC逻辑说明maxsize2是经验值缓冲太大延迟高太小容易丢帧img_queue.full()时丢旧帧而不是阻塞保证处理的是最新图这在高速产线上比“不丢帧”更重要。三个线程用running标志统一控制退出实际项目里还要加异常捕获防止某个线程挂了整个系统卡死。第四能硬件做的别用软件做。触发用硬触发剔除用 PLC 直接控制吹气相机自带的一些预处理比如二值化输出能用就用。软件只做必须软件做的判定逻辑。最后一个习惯每次改完算法用同一批图跑一遍计时。别凭感觉说“应该够快”拿time.perf_counter()卡每个环节的耗时找出瓶颈再优化。我一般会在代码里留一个PROFILE开关打开就打印各阶段耗时关掉就不影响性能。这个习惯帮我省了无数次返工。做这行久了会发现机器视觉工业缺陷检测的难点从来不在某一个算法而在光源、相机、机械、算法、通信这一整条链路的配合。哪一环掉链子最后都表现为“检测不准”。所以遇到问题别一头扎进算法里调参先回头看成像再看机械稳定性最后才动算法。希望帮到你。本文还有配套的精品资源点击获取