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

基于OpenCV与Python的瓶口缺陷检测:从Hough圆检测到极坐标展开

发布时间:2026/9/27 1:30:46

资讯中心
01
ARTICLE

基于OpenCV与Python的瓶口缺陷检测:从Hough圆检测到极坐标展开

基于OpenCV与Python的瓶口缺陷检测:从Hough圆检测到极坐标展开
简介一套基于OpenCV与Python的瓶口缺陷检测系统实现方案面向高校毕业设计及计算机视觉课程实践可解决瓶口瑕疵自动识别问题。压缩包共53个文件大小约5.59MB内含Python源码、40张瓶口及瓶箱图像数据集、备份文件、readme说明文档及Git配置文件等代码与数据划分清晰。已有65人学习下载项目采用模块化设计涵盖图像预处理、边缘检测、特征提取、多尺度滤波与自适应阈值分割等标准流程支持实时采集与批量处理两种模式输出缺陷定位坐标与分类置信度。项目难度贴合本科生认知水平教学内容经助教团队审核可直接支撑课程教学。数据集覆盖多种光照条件下的瓶口样本标注完整便于复现实验同时配套readme环境配置指引适合本科生快速部署运行。1. 一条产线工位上的3毫秒决策瓶口缺陷检测到底在解决什么在旋盖之前瓶口是整条灌装线最容易被忽视又最不能出错的区域。玻璃瓶、PET瓶经过洗瓶、灌装、传输瓶口可能出现崩边、裂纹、缺口、毛刺、压伤这些缺陷一旦带着密封面进入旋盖工序轻则漏气、重则整批次召回。人工目检在每分钟三百瓶的节拍下根本盯不住而机械限位只能挡掉明显变形的瓶子挡不住细裂纹。用OpenCV与Python搭一套瓶口缺陷检测系统本质就是用一个普通工业相机、一个环形光源和一台工控机把“瓶口区域圆不圆、边缘连不连续、环带里有没有异常灰度”变成可量化的判定规则在几十毫秒内输出NG信号。这篇文章会从成像特征讲到极坐标展开再到模板差影与边缘梯度合并判定最后把参数和踩坑点按工序拆给你适合设备工程师、视觉集成商和想用Python在产线上做第一个视觉工位的朋友。2. 为什么瓶口检测首选OpenCV而不是直接上深度学习从成像特征到算法选型2.1 瓶口缺陷的类型与成像特征瓶口缺陷检测难在“缺陷小、类型杂、材质反光”。按产线上常见的缺陷形态可以分成四类第一类是轮廓型缺陷比如崩边、缺口、压伤表现为瓶口圆形边缘在某一段不连续或者圆弧半径发生突变第二类是裂纹型缺陷玻璃瓶和部分PET瓶在瓶口密封面会出现细线状裂纹成像后是一条暗线或亮线宽度往往只有两三个像素第三类是异物与污渍瓶口内壁残留瓶盖碎屑、润滑油或清洗残留表现为局部灰度块第四类是毛边与飞边注塑瓶口脱模不干净在圆周方向形成高频毛刺和正常纹路的区别在于灰度变化速率异常。这四类缺陷在二维图像里的共同特征是它们都落在以瓶口圆心为中心的环形区域内。这意味着检测任务可以拆成两步先找到瓶口的圆心和半径再把环形区域展开成矩形后续所有算法都在这块矩形上做。这个“先定位、再展开、后判定”的路线是OpenCV方案比深度学习方案更适合产线落地的核心原因——缺陷位置没有随机分布在整幅图里而是被约束在一个几何结构明确的圆环带上。正因为高光、反光、透明材质这些干扰在瓶口成像里非常常见选型时不能只看算法精度还要看成像系统能不能把真实缺陷和伪边缘区分开。比如玻璃瓶口的裂纹在低角度光下是暗线在垂直光下可能被高光淹没PET瓶口的毛边在明场照明下几乎看不见但换到暗场照明就非常清晰。所以算法选型的结论是先用传统视觉把几何定位和环形展开做扎实再用灰度、梯度、差影这类可解释特征做判定。深度学习不是不能用而是当缺陷样本每个批次只有几十张时训练成本远高于传统方案且模型参数对换线换瓶型的适配过程不透明。2.2 模板匹配与深度学习的边界OpenCV方案的性价比有一个常见讨论是既然瓶口位置相对固定能不能直接对原图做模板匹配或者直接训练一个分类网络两个方案都有明显边界。模板匹配的问题是瓶口在图像里的位置即使固定也会有亚像素抖动光照变化让模板的灰度分布发生整体偏移固定阈值就失效。深度学习的问题不是精度不够而是数据瓶口缺陷是小概率事件一条线跑一天可能只有二三十个真实缺陷要凑齐几百张崩边、裂纹、污渍样本再加上需要覆盖不同瓶型、不同批次的光照差异样本收集周期可能长达两个月而且标注本身就会出错。OpenCV方案的优势在于参数可见、逻辑可回溯。当现场反馈“某个工位上误检变多了”工程师能做的是打开参数配置看是模板需要重新标定还是光照变了而不是去重新训练一轮模型。这在产线调试阶段非常重要。另外OpenCV的图像处理管线在CPU上跑一个640×480的ROI圆检测加极坐标展开加阈值判定单帧处理时间在30到60毫秒之间完全跟得上常规灌装线的节拍。即便是旋盖前的视觉工位要求每秒钟检测3到5个瓶子也可以用多线程流水线把采集和判定拆开让算法处理时间和相机曝光时间重叠。2.3 成像系统的三个硬参数照明、相机、安装算法做得再好成像不行就是事倍功半。瓶口检测的成像系统有三个硬参数必须在项目启动阶段定下来。第一个是照明方式。瓶口是反光材质推荐用低角度环形光源让光线以接近水平的角度照射瓶口端面这样崩边和缺口处会形成明显的暗区或亮线而瓶口正常弧面保持均匀灰度。如果现场瓶口带内塞或铝盖光源角度需要再压低必要时加偏振片滤掉镜面反射。第二个是相机分辨率。瓶口缺陷的最小可接受检出尺寸一般是0.3毫米按图像上至少覆盖5个像素来算一个像素对应的物理尺寸要优于0.06毫米。常见做法是让瓶口直径在图像中占200到300像素对25毫米口径的瓶子用500万像素相机配合定焦镜头工作距离控制在150毫米左右。分辨率不是越高越好像素太高会导致处理时间上升而且噪声也会更明显。第三个是安装与光轴。瓶口平面必须尽量与相机光轴垂直否则圆形投影变成椭圆圆检测的圆心误差会直接传导到后续极坐标展开。产线上如果瓶子定位不准至少要在工位上加装导向机构让瓶子在检测位停稳并保证瓶口高度一致。下面是项目启动时常用的成像参数参考表参数项推荐范围说明相机分辨率500万像素2448×2048瓶口区域裁出来后仍有足够像素镜头焦距12mm或16mm工作距离150250mm时覆盖瓶口光源类型低角度环形光白色或红外玻璃材质避免使用蓝色强光光源角度1530度低于15度容易照到瓶口内壁曝光时间0.52ms产线有振动时尽量短触发方式光电传感器硬触发避免软件轮询带来的位置抖动这张表不是死参数换产线时最先动的就是光源角度和曝光时间。记住一个原则先让合格瓶口的图像“看起来均匀”再去调算法阈值而不是反过来用算法硬扛差的成像。3. 把瓶口从图像里抠出来Hough圆检测与极坐标展开的实现与参数3.1 先做图像预处理再让HoughCircles干活拿到一张瓶口图像第一步不是直接跑HoughCircles而是先做预处理把瓶口从背景里分离出来。常见做法是截取ROI把图像中心区域以外的部分裁掉这样能减少背景文字、传送带边缘对圆检测的干扰。然后转灰度、做高斯模糊再用HoughCircles找圆。这里的关键点是HoughCircles内部使用的是Canny边缘和梯度信息所以不需要先做二值化也尽量不要用自适应阈值因为自适应阈值会把瓶口上的正常纹理也变成边缘导致圆检测结果跳动。下面是最小可运行的圆检测代码import cv2 import numpy as np def detect_bottle_circle(image): # image: 彩色BGR图这里假设已经裁好ROI gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5, 5), 0) # 限制检测半径范围避免把瓶身边缘当成瓶口 h, w blurred.shape min_r int(w * 0.28) max_r int(w * 0.38) circles cv2.HoughCircles( blurred, cv2.HOUGH_GRADIENT, dp1.2, minDist50, param1120, param245, minRadiusmin_r, maxRadiusmax_r ) if circles is None: return None, blurred # HoughCircles返回的shape是(1, N, 3)先squeeze circles np.round(circles[0]).astype(int) # 多圆时按半径取最靠近图像中心的一个 cx, cy w / 2, h / 2 circles sorted(circles, keylambda c: abs(c[0] - cx) abs(c[1] - cy)) x, y, r circles[0] return (x, y, r), blurred这段代码的意图很直接先算出瓶口候选圆的圆心和半径再按“离图像中心最近”排序取第一个作为瓶口圆。为什么要排序因为瓶口ROI里有时会出现瓶身肩部的圆弧、传送带金属边框的圆角它们也可能被HoughCircles识别成圆但离图像中心更远排到后面就不会干扰结果。几个参数需要按实际图像调param2是累加器阈值值越小越容易找到圆但误检也越多一般先从40到50试minDist控制两个圆心之间的最小距离设为50是为了避免同一个瓶口被检测出多个重叠圆半径范围按ROI宽度比例计算而不是写死像素值这样换相机分辨率时不用改代码。如果检测出的圆半径总是比真实瓶口小一到两个像素通常是param1设得偏高Canny边缘被过滤得太狠导致圆被内缩了。3.2 用极坐标展开把圆环变矩形后续判定就变成一维信号找到圆心和半径之后不要直接在原图上抠圆环做模板匹配因为瓶口在圆周方向上会有微小的旋转和灰度不均匀。常见做法是用cv2.warpPolar把环形区域展开成矩形横轴是角度方向纵轴是半径方向。展开之后瓶口崩边会变成矩形图像中一个垂直方向的缺口裂纹会变成一条斜线或横线污渍会变成一个局部亮块。后续无论是做模板差影还是边缘检测都是在规则矩形上做处理逻辑简单很多。展开代码需要用到HoughCircles输出的圆心和半径同时要控制展开的半径范围只保留瓶口密封面这一段def unfold_bottle_ring(image, center, radius, inner_gap5, outer_gap15): x, y center r radius # 展开半径范围从瓶口内壁到外沿留出内缩和外扩量 r_in max(0, r - inner_gap) r_out r outer_gap # 输出尺寸高度等于半径范围宽度对应圆周角度 # 希望展开后每1度约对应1个像素宽度 width int(2 * np.pi * r) height r_out - r_in # WARP_INVERSE_MAP 表示从极坐标空间映射回直角坐标得到展开图 polar cv2.warpPolar( image, (width, height), center, r_out, cv2.WARP_POLAR_LINEAR | cv2.WARP_INVERSE_MAP ) # 展开结果的第一行对应半径最小处最后一行对应r_out # 为了保留从r_in到r_out这一段裁剪掉内圈不需要的行 # 因为warpPolar的半径从0开始所以需要偏移 offset r_in return polar, offset这里有一个容易绕晕的点cv2.warpPolar的maxRadius如果直接传r_out展开图的原点半径是0而不是r_in所以展开结果里包含了从0到r_out的全部环形带。瓶口中心附近是瓶子的空腔这部分灰度很低且没有纹理不仅没用还会干扰模板统计。因此展开后要沿着半径方向做裁剪把r_in以下的行去掉。上面代码里返回的offset就是这个裁剪偏移量实际使用时用polar[offset:, :]截取有效区域。为什么推荐做极坐标展开而不是直接在原图上取环带做边缘检测因为瓶口缺陷的严重程度在圆周方向上比在直角坐标里更容易量化。一个崩口在直角坐标里是一个不规则多边形在极坐标展开图里就是一个横向宽度固定的缺口缺口的宽度直接对应崩口的圆周角度尺寸这对判定标准非常友好。展开之后还可以对每一列做灰度均值投影把二维问题降维成一维信号再用一维阈值判定稳定性会比二维形态学好很多。3.3 圆心不准才是最大的坑HoughCircles检测出的圆心和半径不一定精确到亚像素。圆心偏移一到两个像素在极坐标展开里会造成圆周方向的拉伸变形表现是整个展开图出现斜向条纹灰度明明正常的瓶口被判定出大量缺陷。这个现象在玻璃瓶口上尤其明显因为透明材质在高光边缘的灰度梯度很大圆心偏一点边缘位置在展开图里就跟着偏。处理办法是做一个半径细化在展开图上沿半径方向做Sobel梯度然后对每一列找梯度最强点的位置把这个位置的平均值作为真实边缘半径再反推圆半径。这样可以把半径误差从两三个像素缩小到亚像素级别。圆心偏移的补救相对麻烦可以先在圆心周围一个5×5邻域里搜索对每个候选圆心都做一次展开计算展开图在半径方向的灰度方差方差最小的候选圆心就是更接近真实中心的位置。def refine_radius(polar_band, expected_radius): # polar_band: 极坐标展开后的有效区域行对应半径列对应角度 if polar_band.ndim 3: polar_band cv2.cvtColor(polar_band, cv2.COLOR_BGR2GRAY) # 沿半径方向求梯度梯度最强的位置对应边缘 sobel_y cv2.Sobel(polar_band, cv2.CV_32F, 0, 1, ksize3) sobel_y np.abs(sobel_y) # 对每一列找梯度最大值的行号 edge_rows np.argmax(sobel_y, axis0) median_row float(np.median(edge_rows)) # 行号偏差即半径偏差这里假设展开图的行间距是1像素 delta median_row - expected_radius return expected_radius delta这段代码的逻辑是展开图的行方向就是原图半径方向瓶口边缘在展开图里是一条接近水平的高梯度线取每一列梯度最强的行号再取中位数就能得到稳定的边缘位置。之所以用中位数而不是均值是因为缺口和崩边会让部分列的最强梯度出现在错误位置中位数能把这些离群列的影响压下去。半径细化之后再回到原图重新做一次展开展开图的斜纹会明显减少。4. 缺陷判定从阈值到规则合理利用模板差影和边缘梯度4.1 用合格样本做极坐标模板而不是直接对原图做差影瓶口检测最稳的基线方法是模板差影但模板不能直接在原图上做。原图上瓶口位置即使有零点几像素的偏差差影结果就会出现整体边缘带导致大量假阳性。正确做法是对一批合格瓶口图像做第一次圆检测并展开成极坐标图然后把所有合格展开图对齐后取中值或均值生成一个极坐标空间的标准模板。以后每一帧新图都做相同的圆检测和展开在极坐标空间与模板做差影这时微小位置偏差只表现为局部的灰度偏移而不是整条边缘差异。模板生成代码通常长这样def build_template(good_images, center_func, unfold_func, sample_count15): # good_images: 合格瓶口的BGR图像列表 # center_func: 返回圆心和半径的函数 # unfold_func: 展开函数返回(极坐标图, 偏移量) unfolded_list [] for img in good_images[:sample_count]: circle center_func(img) if circle is None: continue polar, offset unfold_func(img, circle[:2], circle[2]) # 统一尺寸warpPolar输出尺寸由半径决定这里做一次缩放 target_h, target_w 128, 512 polar cv2.resize(polar, (target_w, target_h)) if len(polar.shape) 3: polar cv2.cvtColor(polar, cv2.COLOR_BGR2GRAY) unfolded_list.append(polar.astype(np.float32)) if len(unfolded_list) 5: raise ValueError(合格样本数量不足至少需要5张可用展开图) template np.median(np.stack(unfolded_list, axis0), axis0) return template.astype(np.uint8)这里有一个容易被忽略的细节cv2.warpPolar的输出尺寸会随着检测到的半径变化而HoughCircles在不同帧之间检测出的半径可能偏差几个像素所以展开图必须先做尺寸归一化。统一缩放到128×512是常见做法高度128对应半径方向宽度512对应圆周方向。分辨率不用太高瓶口缺陷本来就是几个像素宽的信号缩放不会把它抹掉反而能吸收半径抖动带来的尺寸差异。模板为什么要用中值而不是均值因为合格样本里偶尔会混进一张带细微灰尘的图均值会把灰尘的灰度痕迹平移到模板里中值能把这一个离群样本直接忽略掉。当合格样本数量在10到20张时中值模板的稳定性非常好。4.2 差影加梯度合并判定把误检压下去有了模板之后判定逻辑就是差影。但这个差影不能只做一个绝对差值阈值因为瓶口高光区域的灰度波动本身就很大单纯用阈值会把正常高光波动当成缺陷。常见做法是差影之后再叠加梯度响应两个条件同时满足才判NG。具体流程当前展开图与模板做绝对差影高斯模糊去除细噪声二值化得到可疑区域同时对当前展开图做Sobel梯度找到强边缘区域最后把两组掩膜做按位与再进行形态学闭运算把近邻的缺陷像素连成块。def inspect_bottle(polar_img, template, thresh40, grad_thresh80): # polar_img: 当前瓶口的极坐标展开灰度图 if polar_img.shape ! template.shape: polar_img cv2.resize(polar_img, (template.shape[1], template.shape[0])) diff cv2.absdiff(polar_img, template) diff_blur cv2.GaussianBlur(diff, (5, 5), 0) _, diff_mask cv2.threshold(diff_blur, thresh, 255, cv2.THRESH_BINARY) # 梯度掩膜捕捉裂纹和崩边的强边缘 grad_x cv2.Sobel(polar_img, cv2.CV_32F, 1, 0, ksize3) grad_y cv2.Sobel(polar_img, cv2.CV_32F, 0, 1, ksize3) grad_mag cv2.magnitude(grad_x, grad_y) grad_mag cv2.normalize(grad_mag, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) _, grad_mask cv2.threshold(grad_mag, grad_thresh, 255, cv2.THRESH_BINARY) # 合并缺陷区域既要灰度偏离模板又要有明显边缘 combined cv2.bitwise_and(diff_mask, grad_mask) # 闭运算连接邻近碎块 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) combined cv2.morphologyEx(combined, cv2.MORPH_CLOSE, kernel) contours, _ cv2.findContours(combined, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按轮廓面积排序返回最大缺陷面积和轮廓 areas [cv2.contourArea(c) for c in contours] if not areas: return 0, None max_idx int(np.argmax(areas)) return areas[max_idx], contours[max_idx]这段代码的关键在bitwise_and这一步。为什么要同时要差影掩膜和梯度掩膜因为瓶口高光区域的灰度也会与模板有偏差但高光区域的梯度通常比较平缓不会触发grad_thresh而真实崩边是强边缘差影和梯度都会响应。反过来如果只做梯度瓶口正常的密封面纹路也有梯度会误检如果只做差影光源抖动会让整圈灰度发生偏移误检更爆炸。两个条件叠加之后误检率能降下来一个数量级。关于cv2.findContours需要注意OpenCV版本差异在OpenCV 3.x里它返回两个值在OpenCV 4.x里也是两个值但有些旧教程会写三个返回值。如果在调用时出现contourArea()未定义或“not enough values to unpack”错误先检查是不是把轮廓列表取错了位置。这个坑在从旧项目迁移到新版OpenCV时非常常见。4.3 判定规则与参数怎么落到具体数值差影和梯度合并之后得到的是一堆轮廓和面积。这些数值最终要变成“NG”和“OK”的判定结果就需要定规则。纯按最大缺陷面积阈值判定是最粗糙的做法会出现一个问题瓶口直径大的瓶子正常边缘灰度的抖动面积会比小瓶子大固定面积阈值在换瓶型时就失效。所以更合适的做法是把面积映射成比例也就是用缺陷面积除以展开图总面积得到一个归一化的缺陷占比再对不同瓶型设置同一个比例阈值。判定规则可以做成三级第一级最大缺陷面积超过绝对像素阈值比如80像素用于挡住明显的崩边和污渍第二级缺陷面积占展开图总面积的比例超过0.5%用于跨分辨率场景第三级如果缺陷是细长型也就是轮廓的宽高比大于5且缺陷区域经历形态学闭运算后仍然呈现线状直接判为裂纹。下面是一个可落地的判定函数def judge_bottle(area, contour, total_area, abs_thresh80, ratio_thresh0.005, line_ratio5.0): if area abs_thresh: return OK, ratio area / max(1, total_area) if ratio ratio_thresh: return NG, defect_area # 细长型判定对应裂纹 if contour is not None: rect cv2.minAreaRect(contour) w, h rect[1] if min(w, h) 0: aspect max(w, h) / min(w, h) if aspect line_ratio: return NG, crack_like return OK, 这里有一个重要认知任何阈值都不是一次调出来的。第一次上线时把abs_thresh设在80、ratio_thresh设在0.005然后跑至少200张已知合格样本和50张缺陷样本统计误检情况。如果合格样本被误判优先看差影图找到误检区域的灰度特征再决定是调阈值还是调光照如果缺陷样本漏检优先放大梯度阈值或减小差影阈值。原则是先让“NG”具有一定的容差宁可多抓几个可疑缺陷进入人工复核区也不要把缺陷放过。人工复核可以用一张目录表记录照片文件名后续再用人工标记结果回灌阈值参数。5. 从打样到上线的五个常见翻车现场现象、原因、对策5.1 高光反光被当成瓶口缺陷现象是合格瓶口在环形光照射下密封面边缘有一道白色亮环差影图里这圈亮环被判定成大面积缺陷区域整线误检率超过30%。原因是光源角度太高光线在瓶口边缘形成镜面反射反射区域灰度接近255与模板的正常灰度差达到上百差影阈值压不住。解决办法不是调阈值而是调光学把环形光源角度压低到20度以下或者在镜头前加偏振片。代码层面的补救只能做到抑制局部高光也就是对展开图做灰度归一化把每一行的灰度拉伸到一个统一范围但这是治标不治本。5.2 HoughCircles在瓶口一边亮一边暗时圆检测跳变现象是同一只瓶子放在工位上连续触发10次图像检测出的圆心和半径偏差达到三四个像素展开图随之抖动。原因是现场光源没装正或者瓶子本身有透光不均匀导致瓶口一边是强边缘、一边是弱边缘HoughCircles对弱边缘的敏感度不够圆心被强边缘一侧“拉”过去。解决方法是先固定光源安装位置然后检查ROI里是否包含瓶身肩部的高光带如果仍然跳动把param2值调高到50以上减少边缘噪声带来的假圆同时把param1从120降到100让Canny检测在弱边缘一侧也能输出响应。圆检测稳定后再去调后续判定参数顺序不能反过来。5.3 极坐标展开图出现斜向条纹正常瓶口被判缺陷现象是所有合格瓶口的展开图上都有一组平行的斜条纹宽度1到2像素位置固定差影后形成一条连续的NG区域。原因是圆心或半径与真实值有偏差展开时瓶口边缘在半径方向上被压缩或拉伸本来应该水平的边缘变成斜线。解决思路分两步先用refine_radius把半径误差减到亚像素级再检查圆心位置。如果斜条纹依然存在需要在圆心邻域内做搜索用展开图的灰度方差最小的点作为最终圆心。这种方法本质上是在已知瓶口是圆环的前提下把“展开图是否平整”当作圆拟合质量的评判标准比单纯看HoughCircles的置信度更可靠。5.4 模板差影把小灰尘全部判成缺陷现象是合格样本只有5张生成的模板里混进了细微灰尘结果新来的合格瓶口上的灰尘因为与模板中的灰尘位置不同被差影放大成两个缺陷。原因是样本数量太少模板没有把灰尘这类偶然灰度偏差统计掉。解决方法是把合格样本扩大到至少20张覆盖不同时段、不同光照条件下的图像模板改用中值而不是均值。如果现场灰尘问题本身严重还要在检测工位前增加吹气清洁工序而不是让视觉算法去区分“灰尘缺陷”和“瓶口缺陷”这是光学工程师和算法工程师最常见的分歧点。5.5 工控机上部署后单帧处理时间太长跟不上产线节拍现象是在开发机上跑得好好的部署到工控机上之后单帧处理时间从40毫秒涨到200毫秒产线直接罢工。原因通常是工控机CPU性能低于开发机而且代码里没有做ROI裁剪整幅500万像素的图从头到尾参与了高斯模糊和HoughCircles计算。解决方法是在管线最前面加一个固定的矩形ROI把瓶口可能出现的区域裁成640×480甚至更小只对ROI做圆检测和展开选小尺寸的Gaussian核。瓶口在图像中的位置在生产线上是固定的因为瓶子被机械结构限位了ROI固定是安全的。如果还想压缩时间可以把模板差影和圆检测放到两个线程里采集下一帧图像的同时处理上一帧。6. 把判定结果用起来批量回放、误检率统计与下线前验证算法在上线前要回答一个问题它到底会把多少合格瓶口误判成NG又会漏掉多少真实缺陷这两个数字不能靠感觉需要批量回放历史图像来算。我一般会在项目目录里保留三个文件夹good/放合格样本defect/放各类缺陷样本reject/放算法输出的可疑样本。每次调完参数就把整批样本重新跑一遍统计出四个数真阳性、假阳性、真阴性、假阴性。误检率用假阳性除以合格样本总数漏检率用假阴性除以缺陷样本总数。import os from collections import Counter def batch_evaluate(good_dir, defect_dir, inspect_func): stats Counter() for name in os.listdir(good_dir): img cv2.imread(os.path.join(good_dir, name)) polar, circle preprocess(img) area, contour inspect_func(polar, template) label judge_bottle(area, contour) stats[TN if label OK else FP] 1 for name in os.listdir(defect_dir): img cv2.imread(os.path.join(defect_dir, name)) polar, circle preprocess(img) area, contour inspect_func(polar, template) label judge_bottle(area, contour) stats[TP if label ! OK else FN] 1 precision stats[TP] / max(1, stats[TP] stats[FP]) recall stats[TP] / max(1, stats[TP] stats[FN]) return stats, precision, recall真实项目里合格样本和缺陷样本的比例不能是1比1因为产线上合格品占绝大多数算法要优先保证低误检率。我一般会要求合格样本至少500张缺陷样本尽量覆盖每个类型实在不够就用人工制造缺陷的方式补。缺陷样本不足的另一个用途是反推阈值先用合格样本确定差影阈值下限再逐步降低阈值看缺陷样本的检出率变化找到“合格不漏、缺陷多抓”的平衡点。回放验证过了还不算结束现场测试阶段要把每一次NG的原因截图保存并定期回看这些截图的误判情况。这是我一直保留的工作习惯把误检图留全让参数调整有据可查而不是调完一轮就丢在角落。瓶口检测这类视觉工位的核心难点从来不是算法本身而是你能不能稳定地回答“为什么这瓶被判定为NG”。当你手里有成百上千张带有判定结果的图像时回答这个问题就只是翻目录和统计的事。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

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

03
WHY YAOTU

想打造同款高转化官网?

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

◈

场景化定制

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

◐

营销型架构

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

▲

全周期服务

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

免费获取你的建站方案

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