最近碰到一个需求,需要自动化操作一个网站,第一步就遇到一个问题,滑块验证码登录。
核心逻辑是:
1. 获取两张图片,一张左侧的验证码图片,一张完整的图片
2. 比对两张图片,获取到验证码图片与完整图片重合区域在 X 轴上需要移动的举例
3. 通过 selenium 缓慢移动验证码图片到重合区域,完成登录
在网上找到一个类似的需求和实现方案,跟着写了下代码 https://blog.csdn.net/weixin_53300120/article/details/138068169
写了两个实现的方式:
采用 ddddocr:
with open('left.png', 'rb') as f:
target_bytes = f.read()
with open('full.png', 'rb') as f:
background_bytes = f.read()
ocr = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
res = ocr.slide_match(target_bytes, background_bytes, simple_target=True)
print(res, res['target'][0])
采用 cv2:
# 加载图片 A 和 B
image_a = cv2.imread('left.png', cv2.IMREAD_GRAYSCALE)
image_b = cv2.imread('full.png', cv2.IMREAD_GRAYSCALE)
# 使用模板匹配方法( Template Matching )寻找图片 A 在 B 中的位置
result = cv2.matchTemplate(image_b, image_a, cv2.TM_CCOEFF_NORMED)
# 获取最大匹配值及其位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 如果 TM_CCOEFF_NORMED 方法使用,可以通过以下方式找到匹配位置的左上角坐标
top_left = max_loc
# 获取图片 A 的宽度和高度
height, width = image_a.shape
print(height, ':', width)
height2, width2 = image_b.shape
print(height2, ':', width2)
# 获取最左侧的 x 坐标(左上角)
leftmost_x = max_loc[0]
print('leftmost_x:', leftmost_x)
现在的问题是,这两种方法的准确度都不高,而且我也不了解他们内部的实现方式,不知道如何提高识别的准确度。 现在用了一个比较笨的方法,死循环,重复 10 次以内大概率是可以成功一次。
想请教大家,这种场景有没有啥好的办法可以提高识别的准确度,或者有没有相关的开源库可以直接用?
感谢!
![]() |
1
deepall 45 天前
不知道你的 left.png 和 full.png 是啥样,我用 ddddocr 和 cv2 识别验证码的准确率很高
|
![]() |
3
deepall 45 天前
这个 ddddocr 感觉不太行,试试这个
def generate_distance(slice_url, bg_url): """ :param bg_url: 背景图地址 :param slice_url: 滑块图地址 :return: distance :rtype: Integer """ slice_image = np.asarray(bytearray(requests.get(slice_url).content), dtype=np.uint8) slice_image = cv2.imdecode(slice_image, 1) slice_image = cv2.Canny(slice_image, 255, 255) bg_image = np.asarray(bytearray(requests.get(bg_url).content), dtype=np.uint8) bg_image = cv2.imdecode(bg_image, 1) bg_image = cv2.pyrMeanShiftFiltering(bg_image, 5, 50) bg_image = cv2.Canny(bg_image, 255, 255) result = cv2.matchTemplate(bg_image, slice_image, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) return max_loc[0] |
5
naythefirst01 45 天前
这样的直接模板匹配就可以了 准确率很低是不是图片获取的有问题 比如没有下载原始图或者没有处理缩放之类的
|
![]() |
6
uTOmOuk3L6sb4MSI 44 天前 via iPhone
|
![]() |
7
uTOmOuk3L6sb4MSI 44 天前 via iPhone
我不明白为什么要很多次成功,cv2 这种模板匹配只有成功和不成功吧,执行再多次应该也是一种结果,不会出现一会失败一会成功的结果。
|
![]() |
9
uTOmOuk3L6sb4MSI 44 天前 via iPhone
@brianinzz 不对可能就是得加减 x ,y 透明部份?一般没这么严格。说得不清不楚。看线框很吻合了,比手动都吻合。
|
![]() |
11
uTOmOuk3L6sb4MSI 44 天前 via iPhone
@aizya full 和 left 不是配对的吗?怎么只有一张图?而且 y 轴可能都不一样,缺口可能也不一样
|
![]() |
13
uTOmOuk3L6sb4MSI 44 天前 via iPhone
@aizya 反正我可以,而且我测试过几家滑块,成功率蛮高的
|
![]() |
15
uTOmOuk3L6sb4MSI 44 天前
没什么特别的,我用的 js
```js const cv = require('@u4/opencv4nodejs'); // 加载图像 const originalMat = cv.imread(__dirname + '/tmp/' + 'full.png'); const templateMat = cv.imread(__dirname + '/tmp/' + 'left.png'); //识别图片边缘 bg_edge = originalMat.canny(100, 200); cut_edge = templateMat.canny(100, 200); // 转换图片格式 bg_pic = bg_edge.cvtColor(cv.COLOR_GRAY2RGB); cut_pic = cut_edge.cvtColor(cv.COLOR_GRAY2RGB); // 进行模板匹配 const matched = bg_pic.matchTemplate(cut_pic, cv.TM_CCOEFF_NORMED); // 归一化 const minMax = matched.minMaxLoc(); const { maxLoc: { x, y }, } = minMax; console.log(JSON.stringify(minMax)); // 绘制匹配区域的矩形框 const point = new cv.Point(x, y); const color = new cv.Vec(255, 0, 0); const thickness = 2; originalMat.drawRectangle( new cv.Rect(point.x, point.y, templateMat.cols, templateMat.rows), color, thickness, cv.LINE_8 ); // 显示结果 cv.imshow('Result', originalMat); cv.waitKey(); ``` |