基于图像处理的滑块验证码匹配技术

滑块验证码是一种常见的验证码形式,通过拖动滑块与背景图像中的缺口进行匹配,验证用户是否为真人。本文将详细介绍基于图像处理的滑块验证码匹配技术,并提供优化代码以提高滑块位置偏移量的准确度,尤其是在背景图滑块阴影较浅的情况下。

一、背景知识

1.1 图像处理概述

图像处理是指对图像进行分析和操作,以达到增强图像、提取特征、识别模式等目的。常用的图像处理技术包括高斯模糊、Canny 边缘检测、轮廓提取等。

1.2 滑块验证码的原理

滑块验证码通过用户拖动滑块,使滑块图像与背景图像中的缺口对齐,从而验证用户的操作。实现滑块验证码匹配的关键在于精确检测背景图像中缺口的位置。

二、技术实现

2.1 代码实现

import base64
import os
from datetime import datetime
from typing import Union, Optionalimport cv2
import numpy as npclass SliderCaptchaMatch:def __init__(self,gaussian_blur_kernel_size=(5, 5),gaussian_blur_sigma_x=0,canny_threshold1=200,canny_threshold2=450,save_images=False,output_path=""):"""初始化SlideMatch类:param gaussian_blur_kernel_size: 高斯模糊核大小,默认(5, 5):param gaussian_blur_sigma_x: 高斯模糊SigmaX,默认0:param canny_threshold1: Canny边缘检测阈值1,默认200:param canny_threshold2: Canny边缘检测阈值2,默认450:param save_images: 是否保存过程图片,默认False:param output_path: 生成图片保存路径,默认当前目录"""self.GAUSSIAN_BLUR_KERNEL_SIZE = gaussian_blur_kernel_sizeself.GAUSSIAN_BLUR_SIGMA_X = gaussian_blur_sigma_xself.CANNY_THRESHOLD1 = canny_threshold1self.CANNY_THRESHOLD2 = canny_threshold2self.save_images = save_imagesself.output_path = output_pathdef _remove_alpha_channel(self, image):"""移除图像的alpha通道:param image: 输入图像:return: 移除alpha通道后的图像"""if image.shape[2] == 4:  # 如果图像有alpha通道alpha_channel = image[:, :, 3]rgb_channels = image[:, :, :3]# 创建一个白色背景white_background = np.ones_like(rgb_channels, dtype=np.uint8) * 255# 使用alpha混合图像与白色背景alpha_factor = alpha_channel[:, :, np.newaxis] / 255.0image_no_alpha = rgb_channels * alpha_factor + white_background * (1 - alpha_factor)return image_no_alpha.astype(np.uint8)else:return imagedef _get_gaussian_blur_image(self, image):"""对图像进行高斯模糊处理:param image: 输入图像:return: 高斯模糊处理后的图像"""return cv2.GaussianBlur(image, self.GAUSSIAN_BLUR_KERNEL_SIZE, self.GAUSSIAN_BLUR_SIGMA_X)def _get_canny_image(self, image):"""对图像进行Canny边缘检测:param image: 输入图像:return: Canny边缘检测后的图像"""return cv2.Canny(image, self.CANNY_THRESHOLD1, self.CANNY_THRESHOLD2)def _get_contours(self, image):"""获取图像的轮廓:param image: 输入图像:return: 轮廓列表"""contours, _ = cv2.findContours(image, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)return contoursdef _get_contour_area_threshold(self, image_width, image_height):"""计算轮廓面积阈值:param image_width: 图像宽度:param image_height: 图像高度:return: 最小和最大轮廓面积阈值"""contour_area_min = (image_width * 0.15) * (image_height * 0.25) * 0.8contour_area_max = (image_width * 0.15) * (image_height * 0.25) * 1.2return contour_area_min, contour_area_maxdef _get_arc_length_threshold(self, image_width, image_height):"""计算轮廓弧长阈值:param image_width: 图像宽度:param image_height: 图像高度:return: 最小和最大弧长阈值"""arc_length_min = ((image_width * 0.15) + (image_height * 0.25)) * 2 * 0.8arc_length_max = ((image_width * 0.15) + (image_height * 0.25)) * 2 * 1.2return arc_length_min, arc_length_maxdef _get_offset_threshold(self, image_width):"""计算偏移量阈值:param image_width: 图像宽度:return: 最小和最大偏移量阈值"""offset_min = 0.2 * image_widthoffset_max = 0.85 * image_widthreturn offset_min, offset_maxdef _is_image_file(self, file_path: str) -> bool:"""检查字符串是否是有效的图像文件路径"""valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff')return os.path.isfile(file_path) and file_path.lower().endswith(valid_extensions)def _is_base64(self, s: str) -> bool:"""检查字符串是否是有效的 base64 编码"""try:if isinstance(s, str):# Strip out data URI scheme if presentif "data:" in s and ";" in s:s = s.split(",")[1]base64.b64decode(s)return Truereturn Falseexcept Exception:return Falsedef _read_image(self, image_source: Union[str, bytes], imread_flag: Optional[int] = None) -> np.ndarray:"""读取图像:param image_source: 图像路径或base64编码:param imread_flag: cv2.imread 和 cv2.imdecode 的标志参数 (默认: None):return: 读取的图像"""if isinstance(image_source, str):if self._is_image_file(image_source):  # 如果是文件路径if imread_flag is not None:return cv2.imread(image_source, imread_flag)else:return cv2.imread(image_source)elif self._is_base64(image_source):  # 如果是 base64 编码# 剥离数据URI方案(如果存在)if "data:" in image_source and ";" in image_source:image_source = image_source.split(",")[1]img_data = base64.b64decode(image_source)img_array = np.frombuffer(img_data, np.uint8)if imread_flag is not None:image = cv2.imdecode(img_array, imread_flag)else:image = cv2.imdecode(img_array, cv2.IMREAD_UNCHANGED)if image is None:raise ValueError("Failed to decode base64 image")return imageelse:raise ValueError("The provided string is neither a valid file path nor a valid base64 string")else:raise ValueError("image_source must be a file path or base64 encoded string")def get_slider_offset(self, background_source: Union[str, bytes], slider_source: Union[str, bytes],out_file_name: str = None) -> int:"""获取滑块的偏移量:param background_source: 背景图像路径或base64编码:param slider_source: 滑块图像路径或base64编码:param out_file_name: 输出图片的文件名: 默认为当前时间戳:return: 滑块的偏移量"""background_image = self._read_image(background_source)slider_image = self._read_image(slider_source, cv2.IMREAD_UNCHANGED)out_file_name = out_file_name if out_file_name else datetime.now().strftime('%Y%m%d%H%M%S.%f')[:-3]if background_image is None:raise ValueError("Failed to read background image")if slider_image is None:raise ValueError("Failed to read slider image")slider_image_no_alpha = self._remove_alpha_channel(slider_image)image_height, image_width, _ = background_image.shapeimage_gaussian_blur = self._get_gaussian_blur_image(background_image)image_canny = self._get_canny_image(image_gaussian_blur)contours = self._get_contours(image_canny)if self.save_images:# 创建输出目录if not os.path.exists(self.output_path):os.makedirs(self.output_path)cv2.imwrite(os.path.join(self.output_path, f'{out_file_name}_image_canny.png'), image_canny)cv2.imwrite(os.path.join(self.output_path, f'{out_file_name}_image_gaussian_blur.png'), image_gaussian_blur)contour_area_min, contour_area_max = self._get_contour_area_threshold(image_width, image_height)arc_length_min, arc_length_max = self._get_arc_length_threshold(image_width, image_height)offset_min, offset_max = self._get_offset_threshold(image_width)offset = Nonefor contour in contours:x, y, w, h = cv2.boundingRect(contour)if contour_area_min < cv2.contourArea(contour) < contour_area_max and \arc_length_min < cv2.arcLength(contour, True) < arc_length_max and \offset_min < x < offset_max:cv2.rectangle(background_image, (x, y), (x + w, y + h), (0, 0, 255), 2)offset = x# 匹配滑块模板在背景中的位置result = cv2.matchTemplate(background_image, slider_image_no_alpha, cv2.TM_CCOEFF_NORMED)_, _, _, max_loc = cv2.minMaxLoc(result)slider_x, slider_y = max_locoffset = slider_xcv2.rectangle(background_image, (slider_x, slider_y),(slider_x + slider_image_no_alpha.shape[1], slider_y + slider_image_no_alpha.shape[0]),(255, 0, 0), 2)if self.save_images:cv2.imwrite(os.path.join(self.output_path, f'{out_file_name}_image_label.png'), background_image)return offset

2.2 代码说明

  • 图像预处理:通过高斯模糊和Canny边缘检测增强图像的对比度和亮度,提高滑块识别率。
  • 多图像融合:通过多次处理图像并融合结果,以减小噪声对检测结果的影响。
  • 动态调整阈值:根据图像的直方图动态调整Canny边缘检测的阈值,提高对不同图像的适应性。
  • 轮廓检测:通过 _get_contours 函数获取图像的轮廓,并根据轮廓面积和弧长进行筛选。
  • 滑块匹配:通过模板匹配方法 cv2.matchTemplate 匹配滑块在背景图中的位置。

2.3 优化策略

  • 对比度和亮度增强:通过提高图像的对比度和亮度,使得滑块和背景的区别更加明显,增强滑块匹配的准确度。
  • 多图像融合:融合多张处理后的图像,减小单张图像中的噪声对结果的影响。
  • 动态调整参数:根据图像内容动态调整Canny边缘检测的阈值,使得算法对不同类型的图像都有较好的适应性。

2.4 安装依赖

要运行上述代码,需要安装以下 Python 库:

pip install numpy opencv-python slider_captcha_match

2.5 使用方法

在安装完所需库后,您可以按照以下步骤使用滑块验证码匹配功能:

  1. 初始化SliderCaptchaMatch类:配置高斯模糊、Canny边缘检测等参数。
  2. 读取背景图像和滑块图像:可以是文件路径或base64编码。
  3. 获取滑块偏移量:调用get_slider_offset函数,返回滑块的准确偏移量。
from slider_captcha_match import SliderCaptchaMatchfrom datetime import datetimeimport cv2# 初始化 SliderCaptchaMatch 类slider_captcha_match = SliderCaptchaMatch(save_images=True,output_path="output")# 读取背景图像和滑块图像background_source = "path_to_background_image.jpg"slider_source = "path_to_slider_image.png"# 获取滑块偏移量offset = slider_captcha_match.get_slider_offset(background_source, slider_source)print(f"滑块偏移量: {offset}")# 输出结果保存路径out_file_name = datetime.now().strftime('%Y%m%d%H%M%S.%f')[:-3]print(f"结果图像保存路径: output/{out_file_name}_image_label.png")

三、测试与验证

为了验证优化后的滑块验证码匹配技术,进行多次测试,比较不同情况下的滑块偏移量检测结果,并记录背景图、滑块图、中间预处理图和代码标注的滑块位置的图,以及缺口坐标位置偏移量计算。

Response for row 1: offset(手动标注)=155;缺口坐标(代码计算)=155.0

 

Response for row 2: offset(手动标注)=119;缺口坐标(代码计算)=118.5


Response for row 2: offset(手动标注)=223;缺口坐标(代码计算)=224.0

四、总结

本文介绍了基于图像处理的滑块验证码匹配技术,并通过多种优化策略提高了滑块位置偏移量的检测准确度。通过对图像进行预处理、融合多张图像、动态调整阈值等方法,可以有效提高滑块验证码在不同背景下的识别率。希望这篇文章能够对从事图像处理和验证码研究的读者有所帮助。

参考资料

  1. OpenCV 官方文档
  2. NumPy 官方文档
  3. 本Github项目源码地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上海市计算机学会竞赛平台2023年2月月赛丙组平分数字(一)

题目描述 给定 &#x1d45b;n 个整数&#xff1a;&#x1d44e;1,&#x1d44e;2,⋯ ,&#x1d44e;&#x1d45b;a1​,a2​,⋯,an​&#xff0c;请判定能否将它们分成两个部分&#xff08;不得丢弃任何数字&#xff09;&#xff0c;每部分的数字之和一样大。 输入格式 第…

模拟,CF 570C - Replacement

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 570C - Replacement 二、解题报告 1、思路分析 1、长为cnt的连续串的最小操作次数为cnt - 1 2、每次将一个非. 替换为. f要么增加1要么增加2 只有前后都是 . 的时候会增加2 同理&#xff0c;当我们将一…

STM32外扩SRAM及用法

一.概述 一般单片机有片内的RAM&#xff0c;但都不多&#xff0c;比如&#xff1a;STM32F407ZGT6 自带了 192K 字节的 RAM&#xff0c;对一般应用来说&#xff0c;已经足够了&#xff0c;不过在一些对内存要求高的场合&#xff0c;比如做华丽效果的 GUI&#xff0c;处理大量数据…

swagger的接口文档导入到yapi上

一、访问swagger接口 swagger集成到项目后&#xff0c;通过http:\\ip:port/swagger-ui.html 访问。 说明&#xff1a;这里的路径是基于swagger2。如果用swagger3&#xff0c;需要用swagger3的路径进行访问。 访问如图&#xff1a; 这就是swagger接口首页。如果想导入到yapi上…

module_param_named 内核启动时模块参数实现原理

基于上节内核启动参数实现原理内容, 其中对early_param的实现流程做了分析, 已基本清晰. 但有不少的参数是在内核模块中声明的, 具体赋值流程也值得一探究竟. nomodeset 装过Linux系统的同学可能多少有看到过nomodeset这个参数, 解决一些显卡点不亮Linux的问题. 那么这个nomo…

AI绘画Stable Diffusion 新手入门教程:万字长文解析Lora模型的使用,快速上手Lora模型!

大家好&#xff0c;我是设计师阿威 今天给大家讲解一下AI绘画Stable Diffusion 中的一个重要模型—Lora模型&#xff0c;如果还有小伙伴没有SD安装包的&#xff0c;可以看我往期入门教程2024最新超强AI绘画Stable Diffusion整合包安装教程&#xff0c;零基础入门必备&#xff…

React Hooks --- 分享自己开发中常用的自定义的Hooks (1)

为什么要使用自定义 Hooks 自定义 Hooks 是 React 中一种复用逻辑的机制&#xff0c;通过它们可以抽离组件中的逻辑&#xff0c;使代码更加简洁、易读、易维护。它们可以在多个组件中复用相同的逻辑&#xff0c;减少重复代码。 1、useThrottle 代码 import React,{ useRef,…

三叶青图像识别研究简概

三叶青图像识别研究总概 文章目录 前言一、整体目录介绍二、前期安排三、构建图像分类数据集四、模型训练准备五、迁移学习模型六、在测试集上评估模型精度七、可解释性分析、显著性分析八、图像分类部署九、树莓派部署十、相关补充总结 前言 本系列文章为近期所做项目研究而作…

工作助手VB开发笔记(2)

今天继续讲功能 2.功能 2.9开机自启 设置程序随windows系统启动&#xff0c;其实就是就是将程序加载到注册表 Public Sub StartRunRegHKLM()REM HKEY_LOCAL_MACHINE \ SOFTWARE \ WOW6432Node \ Microsoft \ Windows \ CurrentVersion \ RunDim strName As String Applicat…

教师商调函流程详解

作为一名教师&#xff0c;您是否曾面临过工作调动的困惑&#xff1f;当您决定迈向新的教育环境&#xff0c;是否清楚整个商调函流程的每一个细节&#xff1f;今天&#xff0c;就让我们一起来探讨这一过程&#xff0c;确保您能够顺利地完成工作调动。 首先需要确定新调入的学校已…

裁员风波中的项目经理,如何自洽?

最近都在担心企业裁员&#xff0c;那么项目经理会不会也有被优化的风险呢&#xff1f; 答案是&#xff0c;一定会&#xff01; 今天从3个方面给大家阐述一下项目经理岗位的发展现状以及未来的趋势 01 项目经理被优化的可能性大吗&#xff1f; 02 哪一类项目经理会被最先裁员…

CSDN导入本地md文件图片不能正常回显问题

标题 搭建图像仓库获取图片URL 路径替换 因为服务器读取不到本地图片&#xff0c;故不能正常回显&#xff0c;因此想要正常回显图片&#xff0c;我们首先要做的就是搭建一个可以存放图片的服务器&#xff0c;像你可以选择购买一个云服务器、FastDFS图片服务器、Minio多云对象存…

信息收集-arping

信息收集-arping 简介 arping 是一个用于发送 ARP 请求和接收 ARP 回复的工具。它通常用于检查网络中的 IP 地址是否被使用&#xff0c;或发现网络中的重复 IP 地址。arping 工具类似于 ping 命令&#xff0c;但它使用的是 ARP 协议而不是 ICMP 协议。在 Kali Linux 中&#…

娱乐圈惊爆已婚男星刘端端深夜幽会

【娱乐圈惊爆&#xff01;已婚男星刘端端深夜幽会&#xff0c;竟是《庆余年》二皇子“戏外风云”】在这个信息爆炸的时代&#xff0c;娱乐圈的每一次风吹草动都能瞬间点燃公众的热情。今日&#xff0c;知名娱乐博主刘大锤的一则预告如同投入湖中的巨石&#xff0c;激起了层层涟…

纸电混合阶段,如何在线上实现纸电会档案的协同管理?

随着国家政策的出台和引导&#xff0c;电子会计档案的管理越来越规范&#xff0c;电子会计档案建设成为打通财务数字化最后一公里的重要一环。但是&#xff0c;当前很多企业的财务管理仍处于电子档案和纸质档案并行的阶段&#xff0c;如何能将其建立合理清晰关联&#xff0c;统…

《数字图像处理-OpenCV/Python》第17章:图像的特征描述

《数字图像处理-OpenCV/Python》第17章&#xff1a;图像的特征描述 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第17章&#xff1a;图像的特征描述 特征检测与匹配是计算机视觉的…

javascript v8编译器的使用记录

我的机器是MacOS Mx系列。 一、v8源码下载构建 1.1 下载并更新depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH/path/to/depot_tools:$PATH 失败的话可能是网络问题&#xff0c;可以试一下是否能ping通&#xff0c;连…

【代码随想录_Day25】452. 用最少数量的箭引爆气球 435. 无重叠区间 763. 划分字母区间

Day25 OK&#xff0c;今日份的打卡&#xff01;第二十五天 以下是今日份的总结用最少数量的箭引爆气球无重叠区间划分字母区间 以下是今日份的总结 用最少数量的箭引爆气球无重叠区间划分字母区间 今天的题目难度不低&#xff0c;而且非常的有意思&#xff0c;尽量还是写一些…

imx6ull/linux应用编程学习(11)CAN应用编程基础

关于裸机的can通信&#xff0c;会在其他文章发&#xff0c;这里主要讲讲linux上的can通信。 与I2C,SPI等同步通讯方式不同&#xff0c;CAN通讯是异步通讯&#xff0c;也就是没有时钟信号线来保持信号接收同步&#xff0c;也就是所说的半双工&#xff0c;无法同时发送与接收&…

python项目常见使用的传参调试方法

简介 你是否经常遇到下载的github开源知名项目&#xff0c;不知如何调试&#xff1f;只知道按说明的命令行运行&#xff1f;遇到异常或想改造也无从下手&#xff1f;这篇文档章将指导你如何入手调试别人的大型开源项目。 常见项目使用说明及代码如何调试 常见情况一 使用说…