缺口距离识别本质是图像匹配问题,需用cv2.matchTemplate在灰度对齐的背景图与滑块图间计算像素级偏移,max_loc[0]即缺口左边缘横坐标;直接差分易受渲染干扰而失效。

缺口距离识别本质是图像匹配问题,不是OCR
滑动验证码的缺口距离识别,核心不是文字识别,而是两张图(背景图和带缺口的滑块图)之间的像素级偏移量计算。多数人误用 pytesseract 去“读数字”,结果精度差、泛化弱——因为缺口位置从不以文字形式存在,它是一个视觉错位区域。
真正稳定的做法是:对齐两张图,定位差异区域的左边界横坐标。关键前提是两张图必须严格对齐(尺寸、缩放、灰度预处理一致)。
- 背景图通常为完整拼图底图,缺口图是同一底图但缺失一块(即滑块被抠走后的图)
- 缺口宽度一般在 40–60px,高度约 120px,位置多在图中上部,但每次随机
- 直接用
cv2.matchTemplate搜索滑块图在背景图中的最佳匹配位置,再计算偏移,比“找差异图”更鲁棒
用 cv2.matchTemplate 找滑块图在背景图中的匹配位置
这是最常用且效果可靠的方案。原理是将滑块图作为模板,在背景图上做滑动窗口匹配,取归一化相关系数(cv2.TM_CCOEFF_NORMED)最大值的位置。
注意:必须保证两张图都是灰度图、无压缩失真、尺寸未被浏览器缩放干扰(常见坑:网页返回的 base64 图是缩略图,需按原始尺寸重采样)。
立即学习“Python免费学习笔记(深入)”;
- 先用
cv2.imread(..., cv2.IMREAD_GRAYSCALE)读取并转灰度 - 对滑块图做简单二值化(
cv2.threshold)可提升边缘响应,但别过度锐化,否则模板失真 - 调用
cv2.matchTemplate(bg_img, slider_img, cv2.TM_CCOEFF_NORMED),返回匹配得分矩阵 - 用
cv2.minMaxLoc取最大值坐标,该max_loc的 x 值就是缺口左边缘在背景图中的横坐标(单位:像素)
# 示例关键片段
bg = cv2.imread('bg.png', cv2.IMREAD_GRAYSCALE)
slider = cv2.imread('slider.png', cv2.IMREAD_GRAYSCALE)
res = cv2.matchTemplate(bg, slider, cv2.TM_CCOEFF_NORMED)
_, _, _, max_loc = cv2.minMaxLoc(res)
gap_x = max_loc[0] # 缺口左边缘x坐标,即需滑动的距离(像素)
为什么不能直接用像素差分(cv2.absdiff)?
看似直观:背景图减缺口图,剩下白色区域就是缺口——但实际极易失效。原因很实在:
- 网页截图常含抗锯齿、阴影、轻微色偏,导致非缺口区域也出现残差噪声
- 缺口边缘有半透明过渡或描边,差分后边缘发虚,
cv2.findContours定位不准 - 部分验证码会加入干扰线、噪点、低对比度背景,差分图几乎不可用
- 滑块图和背景图若存在 1px 对齐偏差(比如下载时自动裁切),整张差分图就全乱
所以,除非你已人工确认两图完全对齐、无任何渲染干扰,否则不建议依赖 cv2.absdiff + 轮廓检测这条路。
真实场景中必须处理的三个干扰项
算法写对只是第一步;线上环境里,以下三点不处理,90% 的识别会失败:
-
缩放适配:网页返回的 base64 图常是设备像素比(dpr)缩放后的图(如 dpr=2 时宽高翻倍),但缺口距离要的是 CSS 像素。需用页面返回的原始尺寸(
background-image的 width/height)反推缩放系数,对max_loc[0]做除法校正 -
滑块图偏移:有些验证码的滑块图本身带 padding 或居中偏移(比如图宽 120px,但有效滑块只占中间 60px),此时应先裁剪出纯滑块区域再匹配,否则
matchTemplate会受黑边干扰 - 动态干扰元素:部分新版验证码在背景图上叠加了浮动小图标、渐变蒙版,这些在每次请求中位置固定但内容变化。建议截取背景图时避开顶部 20px 和左右各 10px 边框,专注中部区域匹配
缺口距离识别的难点不在算法本身,而在把算法嵌进真实 HTTP 请求 + 浏览器渲染的链路里——图没拿对,后面全白忙。


















