机器视觉工业缺陷检测实战:从成像选型到算法部署
简介机器视觉工业缺陷检测的那些事是一份面向机器视觉工程师、自动化测试人员及工业检测入门者的PDF资料围绕工件尺寸测量、表面缺陷检测和Logo标识检测识别等典型场景系统梳理了视觉检测系统的完整构成。内容从基础的光源选型讲起对比LED、萤光灯、卤素灯等常见光源的寿命与适用场景并介绍了背向照明、前向照明、结构光、同轴光等照明方式在划痕、轮廓、字符检测中的实际取舍随后给出工业相机分辨率、帧率、色彩深度等关键参数的选择思路以及镜头、图像采集卡的配套要点。图像处理部分覆盖预处理中的去噪、增强、校正以及边缘检测、模板匹配、灰度变换等检测识别算法并补充了常用算法库信息可直接用于项目方案梳理或部门内部分享。资源包共1个PDF文件大小约1.26MB内容以图文形式呈现便于查阅和打印。该资料至今已有1188人学习适合在工业视觉选型、算法选型或缺陷检测项目启动前快速建立整体认知。1. 机器视觉工业缺陷检测算法只占三成剩下七成在成像与现场工程做机器视觉工业缺陷检测的人迟早会承认一件事算法只占项目成败的三成剩下的七成在成像、光源和现场工程。表面划痕、脏污、缺料、尺寸超差这些原本靠老师傅目检的活儿换成人眼替代方案后真正的难点不是“能不能检测”而是“换一个光照、换一个角度、换一条产线节拍后还稳不稳定”。这篇文章写给正在选型、准备上手第一个检测项目、或者已经被过杀率折磨到想砸设备的工程师。我会按照从需求拆解、硬件选型、算法实现到现场部署的路径把可复现的代码、参数和踩坑记录一次讲清楚。2. 拆解检测需求成像方案、相机选型与算法边界2.1 光源和相机先于算法四种常用光源的适用场景做缺陷检测项目现场最常被问的一句话是“用什么算法”但实际项目里最先定的是“用什么光”。算法看到的图像质量在图像采集那一刻就已经被决定了。同一个划痕用低角度环形光能打出高对比度的暗场效果换成正光可能完全隐没在纹理里。光源选型很多时候靠玄学但基础规律是可以用一套经验框架的。环形光安装在镜头周围光线从四周打向工件。高角度环形光适合表面字符、定位标记的照明低角度环形光专门做金属表面划伤检测划痕会在暗背景下形成亮线对比度极高。同轴光适合高反光平面光路经过半反半透镜垂直打在物体上再原路返回能看清玻璃、晶圆、手机屏表面的细微色差缺点是对倾斜表面几乎没有效果。条形光适合大视野和倾斜照射经常两三根组合使用用来检出塑料件表面的凹凸和褶皱。穹顶光也叫球积分光源光线经过球面内壁多次漫反射再均匀落在物体上专门对付曲面和高反光物体避免镜面反射造成的亮斑。光源颜色不是随便选的。白光最通用但红光打在蓝色或绿色材料上会形成强烈反差蓝光能增强金色表面的氧化痕迹。更讲究的做法是加偏振片把工件表面的镜面反光滤掉只保留漫反射信息这一步在检测拉丝金属和覆膜材料时几乎是必须的。下面这张表是我的常用选型参考光源类型适用缺陷典型场景主要注意点低角度环形光划伤、压伤、凹凸金属、轴承、螺钉端面对安装高度敏感要调同轴光色差、污点、玻璃裂纹屏幕、晶圆、镜面曲面表面会发暗条形光组合褶皱、纹理异常、缺料塑料件、木材、纸张角度不固定需支架穹顶光曲面反光、整体均匀照明药瓶盖、曲面外壳亮度偏低曝光要拉长光源的亮度稳定性和寿命往往决定一个检测系统能平稳跑多久。我一般会选带恒流驱动的光源控制器而不是让光源直接接开关电源否则LED一发热电流漂移图像灰度跟着飘算法的阈值就得天天改。2.2 相机选型与分辨率计算面阵、线阵和镜头的搭配逻辑光源定完第二件事是选相机。大多数工件检测用面阵相机拍一张图就能覆盖整个视野。如果检测对象是大幅面卷材比如布匹、薄膜、钢板或者产线运动速度很高、一次只能拍一条窄带就要用线阵相机连续扫行拼接。判断依据很简单工件能停住或低速通过用面阵工件高速不停、画面宽度又有几十厘米以上用线阵。分辨率的计算是每次都要跟客户确认的核心环节。假设视野是 100mm × 80mm要求检测精度 0.1mm那么宽度方向至少需要 100 / 0.1 1000 像素高度方向 80 / 0.1 800 像素。这只是理论下限实际选型要留边缘余量和亚像素定位空间我习惯按 1.52 倍余量来选也就是至少 200 万像素直接上 500 万像素更省心。分辨率越高图像数据量越大算法耗时越长所以不要无脑买高像素够用就行。镜头这块焦距由工作距离、传感器靶面尺寸和视野共同决定公式是 焦距 工作距离 × 传感器宽度 / 视野宽度。如果做的是尺寸测量类项目比如测零件外径、内孔位置强烈建议用远心镜头它只接收平行光物体前后移动时影像大小不变能消除视差误差。普通镜头在物体高度方向有起伏时测量结果会漂这在缺陷检测里也会导致同一个缺陷在不同高度的表现不一致。2.3 算法选型边界传统视觉和深度学习的适用分界线选算法的第一原则是能用传统视觉解决就不要上深度学习。传统视觉是 Blob 分析、边缘提取、模板匹配这一路毫秒级出结果参数透明出了问题能一行一行查逻辑。深度学习的检测模型表现更鲁棒但它是黑匣子样本要求高、推理要算力、误判原因难追溯。具体可以按下面这张表来判断对比维度传统视觉深度学习样本需求少量样本即可调参每类缺陷建议 300 张以上推理速度15 毫秒1050 毫秒视模型和硬件可解释性阈值、面积、位置都清楚特征图可看但决策路径说不清光照敏感度高固定阈值会漂中前提是训练数据覆盖充分适合场景尺寸超差、固定位置毛刺、定位纹理复杂、缺陷形态多变、背景杂乱我的判断逻辑一般是三步。第一步缺陷能不能用面积、长度、灰度差这类数字描述清楚能就用传统视觉比如药瓶盖缺料、螺丝端面划痕、继电器引脚弯曲。第二步缺陷形态变化大、背景纹理复杂比如布匹上的脏污、注塑件的流痕这就要用深度学习的目标检测或分割模型。第三步如果你连缺陷长什么样都说不全那就直接考虑无监督异常检测只拿正常样本训模型让模型自己发现“不正常”这个思路我放在最后一章展开。2.4 最小检测方案的工作流程一套最小可落地的缺陷检测流程通常分七个环节。产品进入检测工位光电传感器触发相机曝光相机把图像传给工控机检测程序先做 ROI 裁剪再滤波增强算法完成缺陷判定系统向 PLC 输出 OK/NG 信号NG 品在后续工位被剔除机构吹掉图像和结果写进本地数据库备查。节拍是这里面算得最细的指标。检测节拍 曝光时间 图像传输时间 算法耗时 IO 延迟实际设计要在这基础上留 20%30% 余量。举个例子产线节拍要求每秒检 2 件即 500 毫秒一件曝光 5 毫秒传输 30 毫秒算法占 300 毫秒IO 加 PLC 响应 30 毫秒总耗时约 365 毫秒还有 135 毫秒余量这个方案才敢上线。算出来如果超过节拍反馈给前面的相机选型要么降低分辨率要么裁剪 ROI而不是等到现场跑不动了再想办法。3. 跑通第一个检测程序OpenCV 骨架与合成缺陷扩展样本3.1 OpenCV 实现表面缺陷检测的最小骨架如果工件表面和背景灰度差异明显用 OpenCV 就能搭出第一个可用的检测程序。以药瓶盖划痕检测为例常见的做法是读取图像、转灰度、裁剪 ROI、滤波、阈值分割、形态学处理、按面积筛选缺陷。import cv2 import numpy as np # 读取图像先裁剪ROI缩小后续计算范围 img cv2.imread(cap_001.png) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) roi gray[100:600, 150:700] # 高斯滤波去噪避免把CMOS传感器噪声当成缺陷 blur cv2.GaussianBlur(roi, (5, 5), 0) # 固定阈值分割缺陷区域与背景灰度差异明显时最有效 _, thresh cv2.threshold(blur, 120, 255, cv2.THRESH_BINARY) # 形态学闭运算把断裂的划痕连接成完整区域 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) closed cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) # 找轮廓并按面积过滤min_area相当于忽略噪点 contours, _ cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) min_area 50 defects [c for c in contours if cv2.contourArea(c) min_area] print(fdefect count: {len(defects)})这里有几个参数要解释清楚。threshold 的 120 是灰度阈值像素灰度低于 120 的被认为是缺陷区域这个值依赖光源亮度光源稍有变化就要重新标定。min_area 等于 50意思是面积小于 50 像素的连通域当作灰尘或噪点忽略这就是商业视觉软件里“忽略点数”参数的同一个思路点掉了反而更干净。高斯滤波核 (5, 5) 对高斯噪声抑制效果好如果用中值滤波应对椒盐噪声更合适但会稍微抹掉细小划痕的对比度我一般默认高斯滤波。闭运算的核大小也要调核太大两个相邻缺陷会被连成一个核太小断裂划痕接不上。固定阈值最大的问题是扛不住光照变化。如果现场曝光偶尔波动改用 Otsu 自适应阈值会稳很多# OTSU阈值自动计算光照变化时比固定阈值更稳 _, thresh cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU)OTSU 的原理是自动寻找一个让前景和背景类内方差最小的灰度值不需要人工设定。代价是如果图像里缺陷面积占比太小比如小于 5%OTSU 会偏向背景。这时候可以给 ROI 加一个高亮背景垫片强制缺陷占比变大再用 OTSU 就能稳定分割。3.2 样本不够时用合成缺陷撑起训练集深度学习不是天生比传统视觉强它比传统视觉更“吃”样本。产线上的缺陷率往往在千分之一以下收集几百张真实缺陷图像可能要跑一两个星期。常见做法是用大量正常样本加上人工合成的缺陷把训练集撑起来。合成缺陷不是随便画几条线而是要模拟真实成像结果。import numpy as np import cv2 import random def add_scratch(img, max_len80, max_width4): 在正常图像上随机画一道划痕模拟表面划伤缺陷 h, w img.shape[:2] mask np.zeros((h, w), dtypenp.uint8) x1, y1 random.randint(0, w), random.randint(0, h) angle random.uniform(0, np.pi) length random.randint(20, max_len) x2 int(x1 length * np.cos(angle)) y2 int(y1 length * np.sin(angle)) cv2.line(mask, (x1, y1), (x2, y2), 255, random.randint(1, max_width)) # 模糊让划痕边缘更接近真实成像效果 mask cv2.GaussianBlur(mask, (5, 5), 0) # 与图像叠加并加入传感器高斯噪声 noise np.random.normal(0, 25, img.shape).astype(np.float32) result img.astype(np.float32) mask[..., None] * random.uniform(0.5, 1.0) noise return np.clip(result, 0, 255).astype(np.uint8)画一条线再高斯模糊这一步很关键。真实划痕在成像中是边缘柔和的亮带或暗带如果直接用硬边线条叠加模型会学到“有硬边就是缺陷”这个假规律到了现场边缘锐利的纹理都会触发误报。叠加高斯噪声是为了模拟相机暗光下的噪声特性防止模型只认无噪声的干净图像。扰动幅度 random.uniform(0.5, 1.0) 控制划痕的灰度对比度值是 1.0 时划痕最明显0.5 时接近真实弱缺陷。建议真实缺陷和合成缺陷的比例控制在 1:3 以内全用合成样本训出来的模型一到现场就会被真实成像差异打回原形。数据增强还可以继续加随机翻转、90 度旋转、亮度对比度扰动、弹性形变。亮度和对比度扰动在缺陷检测里尤其重要它让模型对光源波动不敏感。OpenCV 里可以直接用 cv2.convertScaleAbs 实现def random_brightness_contrast(img, brightness_delta40, contrast_alpha1.2): 随机亮度对比度扰动模拟光源波动下的成像变化 brightness random.randint(-brightness_delta, brightness_delta) contrast random.uniform(1.0, contrast_alpha) return cv2.convertScaleAbs(img, alphacontrast, betabrightness)这类增强不能做过头否则会改变缺陷本身的可辨识度。我一般把亮度偏移控制在 ±40 灰度以内对比度倍数不超过 1.2保证增强后的图像还属于“同一现场”的分布范围。3.3 转向 YOLO 检测标注格式与训练命令当缺陷形态复杂、背景纹理杂乱传统视觉撑不住就该上 YOLO 这类目标检测模型了。YOLO 的标注格式是每张图对应一个 txt 文件每行代表一个缺陷框格式为“类别 class x_center y_center width height”所有坐标都归一化到 01。这个归一化是最容易翻车的点很多初学者直接把像素坐标喂进去loss 不收敛也找不到原因。def voc_to_yolo(xml_path, img_w, img_h): 把VOC xml标注转为YOLO格式坐标归一化到0-1 import xml.etree.ElementTree as ET tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): cls obj.find(name).text box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) x_c (x1 x2) / 2 / img_w y_c (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) return \n.join(lines)width 和 height 用的是缺陷框的真实像素宽度除以图像宽度不是左上右下坐标差的一半这一点看代码容易混淆。归一化后无论训练图像是 640×640 还是 1280×1280框坐标都在同一个尺度下模型才能做多尺度训练。数据准备好后用一个 defects.yaml 描述数据集路径和类别然后启动训练# defects.yaml path: ./datasets/defects train: images/train val: images/val nc: 2 names: [scratch, dent]# YOLOv5 系列训练命令s模型在速度与精度之间平衡最好 python train.py --data defects.yaml --img 640 --batch 16 --epochs 200 \ --weights yolov5s.pt --device 0 --patience 50训练参数有几个值得说明。img 640 意味着图像会缩放到 640×640如果缺陷很小建议先用原图 ROI 裁剪再训练而不是盲目加大训练尺寸因为分辨率翻倍显存和时间也翻倍。batch 16 在显存允许范围内尽量大大 batch 让梯度更稳定。patience 50 表示验证集指标连续 50 个 epoch 不提升就提前停止这比硬跑满 200 个 epoch 更实际能避免后期过拟合。yolov5s 是轻量模型工业检测以毫秒级节拍为目标时s 模型通常是性价比最高的起点跑不动再考虑更小更快的 n 版本或做剪枝。4. 现场避坑笔记五个让检测系统翻车的常见问题4.1 现象训练集准确率 99%产线上一测就崩模型在验证集上 mAP 很高一装到产线误报率暴增OK 品被大量判成 NG。原因是训练集和现场分布不一致。实验室里用固定光源、固定角度、固定背景拍出来的数据到了现场换了日光灯、换传送带颜色、工件位置稍有偏移模型见过的“正常”就不再是现场的正常。解决思路分三层。第一层现场至少采集 1000 张正常样本加进训练集重新划分训练集和验证集让模型真正见过现场的正常形态。第二层训练时把亮度扰动范围调大用前面提到的 random_brightness_contrast 让模型对光照变化脱敏。第三层上线前先跑影子模式程序照常检测并记录结果但不实际触发剔除统计一天的误报率用数据决定要不要正式启用。这个步骤能避免一次灾难性的质量事故。4.2 现象光源一换检测结果集体漂移同一套程序上午检得好好的下午换了一根同型号的光源棒过杀率从 1% 跳到 15%。即使同型号 LED 光源批次不同发光强度和色温也有差异再加上 LED 本身会衰减光源亮度随时间缓慢下降。所有写了固定灰度阈值的地方比如第 3 章那个 threshold120都会在这一刻集中爆发。解决的办法有三个。硬件上光源控制器必须带恒流驱动别直接接开关电源。算法上把固定阈值全部改成 OTSU 自适应阈值或者基于背景灰度相对值计算阈值。管理上每次开机用标准板拍照计算整图的平均灰度并记录到日志灰度值偏离初始基线超过设定值系统直接报警提示光源需要更换。这就是让“光源衰减”尽早暴露而不是等检测结果先崩。4.3 现象过杀率居高不下老师傅拒绝用系统算法把很多看起来像缺陷、但实际不影响使用的纹理、油污、水渍全标成 NG产线频繁停线操作工只能绕过系统手动放行。本质原因是缺陷定义没有和生产标准对齐。质量部门认可的是“功能性缺陷”算法学到的是“视觉异常”。比如塑料件上的模流纹老师傅知道这是正常工艺纹理算法却当成划痕。我的做法是把判定结果分成三级NG、NG-Low 和 OK。NG 是明确的功能性缺陷NG-Low 是疑似缺陷需要人工复检。给每个缺陷区域算一个综合评分特征是面积、长宽比、灰度对比度和位置评分超过高阈值才判 NG在高低阈值之间判为 NG-Low。同时和质检团队一起收集被误杀的样本单独建一个“可接受纹理”的类别加入训练集模型下一次更新时就会把这些正常纹理学进去。4.4 现象缺陷类别不平衡模型忽略少数类训练集里 OK 样本和划痕占了 95%凹坑只有 2%训练出来的模型对凹坑几乎不报即使报了置信度也低。原因是目标检测的损失在类别极度不平衡时被多数类主导模型策略性把所有难分样本都推给多数类。解决办法是给少数类加权重YOLOv5 里可以用 cls_pw 参数调整类别损失权重或者对少数类做过采样每个 epoch 重复使用让凹坑样本数量达到多数类的 30% 以上。另外一个更实用的手段是专门为少数类合成样本比如凹坑可以用高斯斑点模拟在正常图像上随机画圆斑点乘以高斯衰减再模糊叠加做法和 3.2 节画划痕完全一致。血泪经验是合成样本必须和真实样本混合训练纯合成模型到了现场会比预想中更早翻车。4.5 现象检测速度跟不上产线节拍产线要求每秒检测 2 个工件程序算完一个要 1 秒传送带已经过去了只能降速生产。原因通常是图像分辨率过大、ROI 没裁剪、模型太重或者相机传输没有开硬件加速。很多项目到这一步才反过来说硬件选型有问题但大多数情况还有优化空间。优化顺序按性价比排列先裁剪 ROI把计算量缩到一半以上深度学习输入尺寸从 1280 降到 640精度损失往往很小速度提升明显模型导出为 TensorRT 或 ONNX Runtime推理通常可以提速 1.52 倍最后把采集和计算流水线化相机在采集第 N1 帧时算法正在处理第 N 帧。大部分项目靠前两步就能把 1 秒压到 300 毫秒以内真正需要换 GPU 的是极少数。5. 部署到产线结果输出、触发控制与模型迭代闭环5.1 检测结果如何落到现场系统JSON、TCP 与数据库三选一算法跑出结果后下一步是把“这个工件是 NG”这件事告诉现场设备。常见做法有三种通过 TCP 把 JSON 发给上位机直接写数据库或者把信号通过 IO 模块送给 PLC。如果现场有 MES 或 SCADA首选 TCP JSON因为 MES 侧可以反序列化直接入库不需要约定二进制协议。import json import socket def send_result(ip, port, result_dict): 将检测结果打包成JSON通过TCP发送给上位机 data json.dumps(result_dict, ensure_asciiFalse).encode(utf-8) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((ip, port)) s.sendall(data) # 等上位机ACK确认结果已送达 ack s.recv(16) return ack bOK result { camera_id: C001, product_id: SN-20210817-001, result: NG, defect_type: scratch, score: 0.87, image_path: /data/cap_001.jpg } send_result(192.168.1.50, 9000, result)这里必须等上位机回 ACK。现场网络偶尔抖动发完就忘会造成 NG 结果丢失那是漏检事故不是性能问题。image_path 字段要存原始图像路径否则后续追溯缺陷时找不回当时的画面。如果对接的是 PLC通常不用 TCP而是让工控机通过 IO 网关把结果映射成数字量输出NG 信号直接参与剔除机构的控制逻辑PLC 再记录事件。5.2 相机触发与节拍匹配硬触发为什么更稳相机触发方式分成软触发和硬触发两种。软触发由软件通过 SDK 命令让相机曝光流程简单适合实验室和单工位。但软件调用有毫秒级抖动一旦操作系统卡顿还会漏拍。硬触发是光电传感器或编码器信号直接连到相机的硬件触发引脚工件到位瞬间就给相机一个电平信号曝光在微秒级延迟内完成完全不依赖工控机负载。对比维度软触发硬触发延迟毫秒级抖动明显微秒级稳定可靠性程序卡顿会漏拍不依赖软件成本无需额外线缆需要传感器和接线适用场景实验、节拍要求低高速产线、运动物体除了触发方式还要算曝光时间是否会产生运动模糊。工件移动速度 v 100 mm/s检测精度要求 0.1 mm那么曝光时间必须小于 0.1 / 100 1 毫秒否则拍出来的图像是拖影的算法再强都救不回来。如果算出来曝光时间不够那就得换更强的光源来缩短曝光或者加快门相机。5.3 现场样本回流与模型迭代避开“越改越差”的陷阱上线不是终点模型迭代才是长期工作。现场每天都在产生新的正常样本和少量缺陷样本正确的做法是把这些样本收集起来每周或每月合并进旧训练集整体重训一次。模型文件命名要带上版本号和训练日期部署时保留上一个版本的备份这样新模型出问题时可以一键切回。这就是给自己留后悔药我在一线项目里吃过不止一次没有回滚机制的亏。不要在线用现场数据直接继续训模型。数据分布一旦突变增量训练会触发灾难性遗忘模型会突然丢失已经学过的缺陷类型。我一般的做法是新数据合入旧训练集整体重训虽然慢但结果可控。模型迭代前还要做一次回归测试拿一批覆盖所有缺陷类型的固定样件跑一遍确认新模型没有让任何一类缺陷的召回率下降否则不上线。6. 进阶用无监督异常检测兜住“没见过”的缺陷很多缺陷检测项目的真正难点根本不是某一种缺陷检不出而是缺陷类别永远说不全。换了批次材料、模具磨损、工艺参数调整随时可能出现一种从未见过的缺陷形态。监督学习需要每类几百张样本迭代速度永远追不上现场变化。这个问题的解法是换成无监督异常检测的思路只用正常样本训练一个重建模型模型没见过“缺陷长什么样”但它知道“正常长什么样”当输入偏离正常分布时重建误差就会变大误差大的像素区域就是缺陷位置。具体实现可以用一个轻量的卷积自编码器输入 128×128 灰度图输出重建图像用重建图和原图的像素差定位缺陷。import torch import torch.nn as nn class ConvAE(nn.Module): def __init__(self): super().__init__() self.encoder nn.Sequential( nn.Conv2d(1, 16, 3, stride2, padding1), nn.ReLU(), nn.Conv2d(16, 32, 3, stride2, padding1), nn.ReLU(), nn.Conv2d(32, 64, 3, stride2, padding1), nn.ReLU(), ) self.decoder nn.Sequential( nn.ConvTranspose2d(64, 32, 4, stride2, padding1), nn.ReLU(), nn.ConvTranspose2d(32, 16, 4, stride2, padding1), nn.ReLU(), nn.ConvTranspose2d(16, 1, 4, stride2, padding1), nn.Sigmoid(), ) def forward(self, x): return self.decoder(self.encoder(x))训练时只用 OK 样本损失函数用均方误差目标是让重建图像尽量接近输入。推理时把重建误差图做阈值分割误差超过阈值的连续区域就是异常位置。这个方案的优点是没有标注成本新缺陷也能被兜住缺点是正常样本里如果混入了瑕疵模型会把瑕疵也当正常学进去所以训练数据必须人工筛选干净。当前沿技术路线走到这里时你会发现缺陷检测的规模化能力其实不取决于标注了多少缺陷而取决于你对“正常”建模得有多准。我自己的习惯是无论选哪条路线先挑产线上最痛的那一种缺陷把方案跑通、跑稳、跑到被老师傅认可再横向复制到其他缺陷类型。每个项目保留一份现场参数备忘光源型号、曝光时间、阈值、节拍、误报率变化全部记下来因为这类项目的坑大部分不是算法写不出来而是环境变了你不知道。希望帮到你。本文还有配套的精品资源点击获取