尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

OpenCV瓶口缺陷检测实战:从ROI定位到评分判定

发布时间:2026/9/27 21:02:00

资讯中心
01
ARTICLE

OpenCV瓶口缺陷检测实战:从ROI定位到评分判定

OpenCV瓶口缺陷检测实战:从ROI定位到评分判定
简介一套基于 OpenCV 与 Python 实现的瓶口缺陷检测系统源码及配套数据面向高校计算机视觉类毕业设计、课程设计与工业质检入门学习者。系统采用模块化架构覆盖图像预处理、边缘检测、特征提取、多尺度滤波与自适应阈值分割等流程支持实时采集与批量处理能输出缺陷定位坐标和分类置信度整套程序已通过多轮验证运行表现稳定数据集包含多种光照条件下的瓶口样本图像标注信息完整可直接用于算法验证。资源共 53 个文件总体积 5.59MB其中 40 张 PNG 样本图与 2 个 Python 程序文件构成主体另有 8 个 zbak 备份文件、readme 说明文档及 .gitignore 配置环境配置步骤已整理成文档上手门槛较低。已有 65 人学习下载适合作为数字图像处理课程的实践案例帮助学习者掌握工业视觉检测的基本实现方法。1. 瓶口缺陷检测为什么值得用OpenCV硬扛先想清楚方案边界一条饮料产线每小时过两万多个瓶子瓶口的裂纹、缺角、毛刺如果不挑出来后面灌装、压盖环节会连环出问题。人工目检最多撑二十分钟就得眨眼漏检率随风涨。用OpenCV加Python做瓶口缺陷检测不一定非要上深度学习纯图像规则就能把常见的缺口、裂纹、变形挑出来一套脚本改改路径就能换产线复跑。这也是这个方向最适合中小型自动化团队切入的原因没有训练数据也能启动有几百张样图就能调参数逻辑透明、出问题能改代码不会像黑匣子一样不知道它为什么误检。本文把这套系统的拆法、判定逻辑、源码数据的组织方式和现场踩过的坑完整过一遍照着做你也能在本地把检测流程跑通。2. 从相机图像到瓶口圆环ROI定位与目标提取的实现细节2.1 为什么先做ROI而不是整帧检测算力与误检的双重考量拿到一张瓶子照片就直接跑Canny边缘检测和轮廓分析是新手最容易翻车的做法。现场图片里包含瓶身、标签、传送带背景、灯箱反光边缘检测会把标签上的文字、瓶身的划痕、背景里的其他物件全算进来。整帧处理的后果有两个一是特征维度被污染瓶口边缘断裂会被背景边缘淹没二是计算量成倍上涨产线上每秒要处理好几帧时CPU直接吃满。所以第一步永远是做ROI定位把瓶口区域从整帧里切出来。常见做法是先用霍夫圆检测找瓶口所在的大致圆再以这个圆为中心裁一块固定尺寸的图后续所有处理都只在这块图上做。ROI带来的收益很直接检测耗时从几百毫秒降到几十毫秒误检来源少了一大半。定位瓶口用霍夫圆是首选因为瓶口的物理结构决定了它在图像上就是一个椭圆或正圆反光时外沿会形成一条清晰的弧形亮边。先灰度化再高斯滤波去噪然后用HoughCircles找圆。关键是HoughCircles的参数不能照抄网上例程dp、minDist、param2这三个值与图像分辨率强相关。import cv2 import numpy as np def find_bottle_mouth(gray, min_radius80, max_radius220): # 高斯滤波核大小取奇数sigma用0表示由核自动计算 blurred cv2.GaussianBlur(gray, (5, 5), 0) # 注意HoughCircles输入必须是灰度图 circles cv2.HoughCircles( blurred, cv2.HOUGH_GRADIENT, dp1.2, # 分辨率与累加器分辨率的比值1.2兼顾速度与精度 minDistgray.shape[0] // 4, # 圆心最小距离避免同一个圆被多次检出 param1120, # Canny高阈值边缘越锐利越容易通过 param245, # 累加器阈值越小越容易找到候选圆但也越容易误检 minRadiusmin_radius, maxRadiusmax_radius ) if circles is None: return None # 选半径最接近物理尺寸的圆拒绝多目标干扰 circle circles[0][0] return (int(circle[0]), int(circle[1]), int(circle[2]))这段代码里dp1.2表示累加器分辨率是原图的1/1.2dp越大找圆越快但定位漂移越明显。minDist设成图像高度的四分之一是因为产线上每帧只允许一个瓶子进视场太小的minDist会在瓶口螺纹处找出多个同心圆。param2要反复调设小了把瓶身纹理当圆设大了真缺陷的瓶口变形后反而不成圆。我的习惯是先对二十张正常瓶口图像跑一遍统计圆心坐标和半径标准差再往两边放宽。2.2 从霍夫圆到环形检测带形态学处理稳定提取霍夫圆给出的圆心和半径只能保证大概在这不能直接用来做缺陷判定因为裂纹和缺口往往发生在圆上的一小段弧里。如果把圆周上的点直接拿来算距离一个0.5毫米的缺口在图像上只占三五个像素边缘检测的抖动就能把它淹没。这时候要做的不是加强边缘而是把检测区域变成一条有一定宽度的环形带让特征区域在空间上稳定下来。环形带的内径是半径减去8像素外径是半径加上12像素为什么不是对称的因为瓶口外沿的缺陷缺角、毛刺在图像上通常向外侧膨胀内侧则是螺纹阴影真正要保留判别信息的是外侧一圈。用这个环形区域生成mask把原图以外的部分全部置零再做一次形态学开运算去掉细线噪点就得到一个干净的瓶口特征图。def extract_ring(gray, cx, cy, r, inner_offset-8, outer_offset12): mask np.zeros_like(gray) cv2.circle(mask, (cx, cy), r outer_offset, 255, -1) cv2.circle(mask, (cx, cy), r inner_offset, 0, -1) # 内圈置零 ring cv2.bitwise_and(gray, mask) # 开运算消除细小的螺纹阴影干扰 kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) ring cv2.morphologyEx(ring, cv2.MORPH_OPEN, kernel, iterations1) return ring这里的mask画圆时注意顺序先画外圈实心圆再画内圈空心圆用置零的方式挖出环形。bitwise_and保留原图在环带内的灰度值环带外的背景全部变黑后续Canny边缘检测只会看到瓶口外侧一跳边缘线。开运算的核大小3x3足够滤掉螺纹形成的点状阴影太大会把缺口边缘也抹平。如果瓶子边缘有规律性的反光带可以再加一次闭运算把断裂的小段连续起来这个取舍后面避坑章节细说。形态学处理完之后再做Canny边缘检测并用cv2.findContours提取轮廓环带内就应该只剩下一条或两条与外沿对应的弧线。这一步是后续所有特征计算的数据基础建议在调试时把中间结果cv2.imwrite存成调试图后面分析误检能省很多事。2.3 相机、光源与停位采集端的三个硬条件算法做得再漂亮前端图像垃圾后面全是白费。瓶口检测对成像的三个要求分辨率、光源与停位精度。普通USB摄像头不是不能用但瓶口外径在图像上至少要占100像素以上否则0.3毫米的裂纹只对应一个像素边缘抖动就把它吞了。500万像素工业相机加变焦镜头是保险的选择视野缩到只比瓶口直径大三倍分辨率自然上去了。光源是最容易返工的一项。点光源或条形光照射瓶口会形成强烈镜面反射合格瓶口在图像上变成一圈高光亮弧缺陷被亮光淹没。正确做法是环形漫射光源光源平面与瓶口平面平行发光面朝向瓶口配合偏振片消除瓶口塑料或玻璃的定向反射。参数上光源亮度调到灰度直方图峰值落在120到180之间太暗则边缘断裂太亮则高光区溢出。停位精度决定了ROI定位的稳定性。传送带上的瓶子如果前后左右漂移超过5毫米霍夫圆定位圆心会有跳动同一只瓶子的检测评分也在合格线上反复横跳。现场一般用夹爪或挡块把瓶子推到固定位置如果机械改不动就在图像里加一个边缘模板匹配做二次定位把ROI的中心修正到目标位上。这个方案我在后面进阶章展开。3. 缺陷判定不靠玄学边缘特征、周长偏差与评分阈值的组合拳3.1 缺陷类型与图像特征的映射关系先给瓶口缺陷做画像。产线上最常见的缺陷有四类缺口、裂纹、毛刺和塌边。缺口在图像上表现为外沿弧线的突变断裂断裂处的灰度值比邻域低或者高视打光方向而定裂纹是细线状灰度突变宽度只有一到两个像素但穿过瓶口边缘时会形成一条向瓶身延伸的暗线毛刺是边缘向外突出的尖刺状凸起在外沿曲率上表现为局部异常外扩塌边则是整个局部边缘的曲率半径发生变化弧变得比正常平缓或更陡。这四种缺陷的症状不同所以单一特征一定压不住。只数边缘断裂次数会漏掉毛刺只看轮廓周长会把光照变化算进去只看灰度方差又把瓶口螺纹阴影当缺陷。我的做法是提取一组正交化的特征轮廓周长、面积、圆形度、凸缺陷数量、边缘断裂点数量、环带灰度突变强度。这些特征从不同维度描述同一个物体任意两个都不共用同一个计算管道相关性低才适合做加权。特征的物理含义要落到瓶口真实尺寸上。图像面积与像素的换算系数在部署前用标准瓶口标定一次把一张直径已知的瓶口图拍好量出像素半径除以真实半径就得到毫米每像素。之后所有特征阈值都换算成mm和mm²这样同一套参数换到不同分辨率的相机上只需要改标定系数不用重调每一个魔法数。3.2 用轮廓特征算缺陷评分圆形度、周长偏差与凸包轮廓分析是这套检测系统的核心。在环带图上得到边缘点集后cv2.findContours返回的是所有连通边缘的外轮廓我们只保留面积最大的那一个轮廓它就是瓶口外沿的主体。接下来对这唯一轮廓计算四个特征第一是圆形度也就是轮廓面积除以最小外接圆面积的比值。标准瓶口的外沿近似完整圆圆形度接近1缺口和塌边会让外沿内缩圆形度明显下降。第二是周长偏差率用轮廓实际周长与拟合圆的周长做差再除以拟合圆周长毛刺和波纹会让这个值正向偏大。第三是凸缺陷的最大深度用cv2.convexityDefects找轮廓凸包上的凹点缺口处会形成深度超过设定值的凹陷。第四是边缘断裂点把轮廓点按角度排序后相邻点之间距离超过平均间距1.5倍的点就记为断裂点。def contour_features(gray_ring, cx, cy, r): # 对环带图再做Canny只提取瓶口外沿 edges cv2.Canny(gray_ring, 40, 100) contours, _ cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) if not contours: return None cnt max(contours, keycv2.contourArea) area cv2.contourArea(cnt) perimeter cv2.arcLength(cnt, True) # 最小外接圆用闭合轮廓点拟合 (x, y), radius cv2.minEnclosingCircle(cnt) circularity area / (np.pi * radius * radius) if radius 0 else 0 # 周长偏差率与理论周长做对比 theo_perimeter 2 * np.pi * r perimeter_dev (perimeter - theo_perimeter) / theo_perimeter # 凸缺陷返回距离最大的缺口深度 hull cv2.convexHull(cnt, returnPointsFalse) defects cv2.convexityDefects(cnt, hull) max_defect_depth 0 if defects is not None: for i in range(defects.shape[0]): s, e, f, disturb defects[i][0] max_defect_depth max(max_defect_depth, disturb / 256.0) return { circularity: circularity, perimeter_dev: perimeter_dev, max_defect_depth: max_defect_depth, edge_points: len(cnt) }注意convexityDefects返回的disturb是16进制定点数要除以256才是像素深度。这个细节我见过好几个人栽过算出来的凸缺陷深度动辄几千还以为瓶子碎成了渣。Canny阈值40/100对应的是边缘梯度强度环带图里背景是纯黑梯度来自瓶口外沿所以阈值可以比整帧处理时定得更敏感。这些特征提取完成后别急着算分数先把每张调试图的特征值打印出来和真实缺陷对应上。我曾经在一条线上发现凹底瓶的瓶口内侧有一条模缝线凸缺陷深度比真实缺口还大后来通过限制缺陷角度范围才把它排除掉。数据要观察不要靠想象。3.3 把多维特征压成一个分数加权评分与动态阈值四个特征各自的范围不同直接相加没有意义。先把每个特征映射到0到1的损伤系数再按权重相加。映射函数用分段线性或Sigmoid都行核心是让正常瓶子的特征分布落在0.2以下明显缺陷的特征分布落在0.6以上。中间地带留给边缘划伤、轻微毛刺这类可以放行的轻微瑕疵。权重分配我一般按产线的容忍度来调。如果客户最不能接受缺口和裂纹那么凸缺陷深度和断裂点权重各占0.35毛刺和塌边相对轻微圆形度与周长偏差权重各占0.15。总分数score超过0.45判为缺陷。这个阈值不是拍脑袋定的而是用正常样本和缺陷样本各一百张做过分布统计之后取的P99分位。也就是正常的瓶子算出来的分数99%都低于这个阈值剩下那1%是光照波动的尾部留给现场稳定后再收紧。def defect_score(features, weights(0.15, 0.15, 0.35, 0.35)): circularity_loss np.clip(1.0 - features[circularity], 0, 1) ** 0.7 perimeter_dev_norm np.clip(features[perimeter_dev] / 0.08, 0, 1) defect_depth_norm np.clip(features[max_defect_depth] / 12.0, 0, 1) # 边缘断裂点数量归一化少于3个基本是噪声 break_count estimate_break_count(features[edge_points]) break_norm np.clip((break_count - 2) / 5.0, 0, 1) score (weights[0] * circularity_loss weights[1] * perimeter_dev_norm weights[2] * defect_depth_norm weights[3] * break_norm) return score指数取0.7是为了让轻度塌边不至于一下就顶破阈值毕竟圆形度对噪声很敏感正常瓶子的圆形度也可能波动五个百分点。周长偏差率除以0.08表示允许8%以内的膨胀超过就线性拉满。这些归一化参数都来自对同一批次样品的统计而不是网上抄来的通用值。你接手时一定要用自己现场的图片重新标定这一步省了后面查误检会花十倍时间。评分阈值设完还要做一件事挑五十张正常瓶和五十张缺陷瓶跑一遍混淆矩阵记录漏检和误检的数字之后每次改参数都用同一组测试图回归防止修了一个缺陷又放走了另一个。4. 拿到源码数据后怎么跑起来项目结构、核心代码与参数清单4.1 项目目录与模块划分采集、检测、报告三分离标题里说的源码数据落地到工程里应该是一套能直接改的Python脚本和一批带标签的瓶子图像。代码结构我习惯拆成四个文件不是把每个函数堆在一个py里。config.py放所有阈值和权重capture.py负责对接相机或读取本地图片detect.py放ROI定位、特征提取和评分逻辑batch_test.py做批量测试并输出结果用于调参时回归。这样现场调试时只需要改config.py几乎不需要动其他文件。project/ ├── config.py # 所有可调参数阈值、权重、路径 ├── capture.py # 相机采集或本地图片读取 ├── detect.py # 检测主流程ROI、特征、评分 ├── batch_test.py # 批量测试脚本输出每张图的判定和特征值 ├── data/ │ ├── normal/ # 正常瓶口图像 │ └── defect/ # 各类缺陷瓶口图像 └── output/ ├── debug/ # 中间过程图ROI、边缘、环形图 └── result.csv # 批量测试记录为什么要把正负样本分目录放因为batch_test.py可以直接遍历两个目录分别统计准确率不用维护复杂的标签文件。缺陷类型如果多就在文件名前缀里标记比如crack_001.jpg、chip_002.jpg、burr_003.jpg。这样读文件名就能知道当前测的是哪类缺陷调参时能快速定位是哪种缺陷没有拦住。4.2 跑通最小检测流程三条命令加上核心主流程环境准备不需要折腾。Windows和Linux都能跑Python版本3.8以上依赖只有两个。安装OpenCV时注意核对Python版本和操作系统位数装了不匹配的wheel包会报ModulenotfoundError这个坑后面避坑章节专门说。# 安装基础依赖numpy最好在opencv之前装 pip install numpy pip install opencv-python # 跑单张图检测输出判定结果和特征值 python detect.py --image data/defect/chip_001.jpg # 跑整个目录的批量测试输出csv python batch_test.py --dir data/defect --output output/result.csvdetect.py的主流程就是读图、找瓶口、提取环带、算特征、出分数。下面的pipeline函数把所有步骤串起来并且把中间结果写到debug目录这样一个函数跑完就能看到每个环节的图像状态。import cv2 import numpy as np from config import THRESHOLD_SCORE, DEBUG_SAVE def run_detection(image_path): img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 第一步定位瓶口圆心与半径 circle find_bottle_mouth(gray) if circle is None: return {error: bottle_mouth_not_found} cx, cy, r circle # 第二步提取环形检测带 ring extract_ring(gray, cx, cy, r) # 第三步轮廓特征计算 features contour_features(ring, cx, cy, r) if features is None: return {error: no_edge_found} # 第四步评分与判定 score defect_score(features) is_defect score THRESHOLD_SCORE if DEBUG_SAVE: debug img.copy() cv2.circle(debug, (cx, cy), r, (0, 255, 0), 2) cv2.putText(debug, defect if is_defect else ok, (cx - 60, cy - 40), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255) if is_defect else (0, 255, 0), 2) cv2.imwrite(output/debug/ image_path.split(/)[-1], debug) return {score: round(score, 3), defect: is_defect, features: features}圈出来的绿色圆就是霍夫找到的瓶口位置缺陷判定的红色标签来自评分结果。这段代码的核心在于把整条链路串成纯函数结构输入一张图输出一个字典方便批量回归。THRESHOLD_SCORE在config.py里默认给0.45经过样本校准后才改。如果你发现正常瓶子的分都压在0.3附近缺陷瓶的分能到0.7以上那这个阈值留了充足余量如果正常和缺陷的分只差0.1说明前方特征没区分度调阈值没用得回头改特征提取。4.3 数据集怎么组织样本采集、命名与扩充策略测试集和训练集的概念在规则检测里同样存在。我维护数据目录时每个瓶子只放一张图文件名以瓶号_缺陷类型命名正常瓶直接写normal。标注信息我通常单独存到一个csv里列分别是image_name、defect_type、score_label、pixel_radius。这样想在本地复现作者的检测结果或者自己换数据再测都只需要符合这四列格式。缺陷样本的收集最难。产线废品率低的话一天也攒不出几张真实缺陷图。我会用两种补充手段一是从退货的破瓶里挑典型缺陷重新摆拍二是用图像处理凭空造缺陷样本把正常瓶口图上随机挖掉一小段弧叠加一个噪声毛刺再存成defect类型。合成样本测算法逻辑完全够用毕竟规则特征吃的是几何变化不是纹理学习。扩充时把正常图旋转5度、加高斯噪声、调亮度每张图变出十张变体特征提取的稳定性就能测出来。数据样本的数量不需要多但覆盖要全。正常瓶至少要覆盖瓶口正放、略微倾斜、光照强弱三类情况缺陷样本要把四种缺陷类型各准备二十张以上总计一百张左右就能完成调参回归。样本总量再大意义不大规则检测没有训练收敛一说关键是特征分布的真实性。5. 现场部署避坑光照、停位与误检的五个高频问题排查5.1 反光把瓶口拍成完整亮环裂纹反而被掩盖现象刚装好相机时合格瓶的边缘检测结果非常规整但有明显裂纹的缺陷瓶却被判成合格。把中间过程图打开看发现瓶口外侧被光源照成一段刺眼的白弧裂纹正好落在高光带里灰度值整体抬升边缘梯度消失。原因点光源或条形光从侧面直射瓶口玻璃和塑料的镜面反射形成大面积饱和区Canny在高光区域检测不到灰度突变因为高光内部的梯度几乎为0裂纹信号被淹没。解决把光源换成环形漫射LED光源尽量贴近瓶口平面、从四周均匀照射。如果反光仍然明显在镜头前加偏振片并调整偏振角度消除定向反射。同时把相机增益调低让瓶口高光的灰度峰值不要超过220保证高光区内部还有梯度信息。改完光源后同一裂纹样本的edge_points从个位数回升到正常水平。5.2 瓶子停位偏差导致ROI漂移特征全部失真现象产线转盘速度起来后同一只缺陷瓶有时检出有时漏掉调试时把瓶子停正了又一切正常。检查保存的评分发现正常瓶的score在0.2到0.7之间大幅跳动而真实缺陷瓶的分反而平稳偏低。原因夹爪把瓶子送到相机下方时前后位置误差在5到10毫米瓶口在图像里偏移几十像素。霍夫圆检测虽然重新定位了圆心但瓶口外侧边缘在斜视状态下被拉成椭圆轮廓周长和圆形度全部失真。解决先在机械上做硬限位最简单的是在相机正下方加一个V型定位槽。机械改不了时在图像上做二次策略对整帧跑模板匹配用正常瓶口的圆环模板在图像里找到匹配度最高的位置再以这个位置为中心把ROI半径缩小到原来的80%让检测带只贴着瓶口最外沿。模板匹配的定位精度能到亚像素级别圆心不再跟随边缘缺陷漂移。5.3 生产电脑跑不起来ModulenotFoundError与OpenCV安装翻车现象开发机上跑得好好的检测脚本拷到工控机上执行时报No module named cv2。在工控机上重新pip install opencv-python后又报版本冲突或者提示找不到对应Python版本。原因工控机Python环境与开发机不一致常见于离线环境没有缓存wheel包或Python是32位但系统是64位也可能工控机是ARM架构而默认源里没有对应wheel。解决确认工控机的Python位数和架构后在联网机器上用pip download opencv-python numpy把whl文件下全再拷进内网安装。最简单可靠的方式是在开发机上用conda pack把整个环境打包成压缩包到工控机解压即用天然避免依赖冲突。这套方案我过去在项目收尾时经常用比逐条pip install少花一下午。5.4 把瓶口内部模缝线当成裂纹陷入误检泥潭现象换了一个新瓶型后正品率突然掉到80%大量正常瓶被标记为裂纹。逐张看debug图发现被拦下的大多都有共同特征瓶口内壁上有一条竖向的接缝线宽度和灰度变化与裂纹极像。原因检测带穿过瓶口内外沿之间而某些瓶型的瓶口内侧有模具合模线或焊接线形成稳定的灰度突变评分规则被这条结构性线条欺骗。解决把环形检测带改窄内半径向外多缩进几像素让模缝线退出检测区域。如果模缝线延伸到外沿仍然存在则增加角度过滤记录每个缺陷点的角度如果所有断裂点都落在瓶口同一固定角度的窄区间内判定为结构线而不是随机裂纹。真实裂纹的位置是随机分布的结构线位置是固定的这是最本质的区分。5.5 处理速度跟不上产线节拍CPU被打满现象单帧检测耗时平均300毫秒产线节拍要求每瓶250毫秒内出结果导致检测结果总是在瓶子离开剔除工位后才出来。原因全帧图像1024x1024做了HoughCircles加Canny加全轮廓提取多个环节叠加就超时了。最耗时的往往不是计算而是Canny在整幅图上的高阈值扫描和findContours在大量噪声边缘上的遍历。解决把图像先resize到512x512再定位瓶口定位后再用原始尺寸提取环形带限制HoughCircles的minRadius和maxRadius缩小候选圆搜索区间ORB模板匹配定位后再只对ROI做后续处理。三步做完单帧耗时降到80毫秒以内。如果还不够把Python的逐像素循环改成numpy向量化运算能再省30%。6. 进阶验证模板匹配与多角度复检把误检率再降一个量级前面五章讲的是让系统先跑起来最后这一步解决的是能不能放心交给它的问题。误检和漏检总是此消彼长压住漏检会让误检抬头现场往往优先保漏检为零但误检太多又会增加人工复检负担。一个有效做法是用模板匹配做二次验证第一遍评分把可疑品从所有瓶子里捞出来第二遍用合格瓶口的平均模板和可疑品的图像做逐像素比较排除评分波动造成的误杀。模板的构造方法是对正常样本做平均取二十张合格瓶的环形图按圆心对齐后逐像素取灰度均值和中值形成一张标准瓶口模板。检测时把当前瓶口的环形图与模板做归一化差分统计灰度偏差超过阈值的像素数量。正常瓶口的偏差像素来自光照噪声分布零散缺陷瓶口的偏差像素集中在局部区域面积和连通性都比噪声高一个量级。这样第一轮的高敏感阈值用来捞漏检第二轮差分用来过滤误检。def template_diff(ring, template, diff_thresh22): # 两张图必须同分辨率和同圆心 diff cv2.absdiff(ring, template) _, bin cv2.threshold(diff, diff_thresh, 255, cv2.THRESH_BINARY) # 形态学闭运算把邻近缺陷像素连成区域 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) bin cv2.morphologyEx(bin, cv2.MORPH_CLOSE, kernel) num cv2.countNonZero(bin) # 用最大连通域面积衡量缺陷显著性而不是只看像素总数 n, labels, stats, _ cv2.connectedComponentsWithStats(bin) max_area max(stats[1:, cv2.CC_STAT_AREA], default0) return num, max_area如果产线现场有转盘或分度机构做多角度复检效果更好。同一只瓶子转到两个角度拍两张图分别算分数取较大的那个作为最终结果。理论上用两个视角可以消除单视角下灯光盲区的漏检代价是检测时间翻倍适合节拍余量大的产线。验证这套流程是否真的把漏检率降下来我习惯的做法是准备一百张正样本和一百张缺陷样本先写死第一轮的分数阈值让召回率做到95%再开启模板差分的过滤通道观察误检从多少降到多少。改参数时的每次变更都对照这批数据跑一遍回归指标只允许变好不允许变坏。我自己的收尾习惯是把保存调试图的功能永远开着哪怕现场觉得碍事也只是保留最近一百张循环覆盖。宁可占一点硬盘也别在缺陷批次流走之后对着空空的输出目录后悔。这套方案的定位从来不是替代昂贵的专业视觉系统而是给中小产线一个能自己掌控、能改参数、能看清楚每一步在做什么的落地选项。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。