当前位置: 首页 > news >正文

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

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

一、背景知识

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项目源码地址

相关文章:

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

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

【JavaEE精炼宝库】文件操作(1)——基本知识 | 操作文件——打开实用性编程的大门

目录 一、文件的基本知识1.1 文件的基本概念&#xff1a;1.2 树型结构组织和目录&#xff1a;1.3 文件路径&#xff08;Path&#xff09;&#xff1a;1.4 二进制文件 VS 文本文件&#xff1a;1.5 其它&#xff1a; 二、Java 操作文件2.1 方法说明&#xff1a;2.2 使用演示&…...

常用排序算法_06_归并排序

1、基本思想 归并排序采用分治法 (Divide and Conquer) 的一个非常典型的应。归并排序的思想就是先递归分解数组&#xff0c;再合并数组。归并排序是一种稳定的排序方法。 将数组分解最小之后&#xff08;数组中只有一个元素&#xff0c;数组有序&#xff09;&#xff1b;然后…...

14-8 小型语言模型的兴起

过去几年&#xff0c;我们看到人工智能能力呈爆炸式增长&#xff0c;其中很大一部分是由大型语言模型 (LLM) 的进步推动的。GPT-3 等模型包含 1750 亿个参数&#xff0c;已经展示了生成类似人类的文本、回答问题、总结文档等能力。然而&#xff0c;虽然 LLM 的能力令人印象深刻…...

【Linux】:进程创建与终止

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux程序地址空间的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从…...

横截面交易策略:概念与示例

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…...

4.2 投影

一、投影和投影矩阵 我们以下面两个问题开始&#xff0c;问题一是为了展示投影是很容易视觉化的&#xff0c;问题二是关于 “投影矩阵”&#xff08;projection matrices&#xff09;—— 对称矩阵且 P 2 P P^2P P2P。 b \boldsymbol b b 的投影是 P b P\boldsymbol b Pb。…...

23种设计模式之装饰者模式

深入理解装饰者模式 一、装饰者模式简介1.1 定义1.2 模式类型1.3 主要作用1.4 优点1.5 缺点 二、模式动机三、模式结构四、 装饰者模式的实现4.1 组件接口4.2 具体组件4.3 装饰者抽象类4.4 具体装饰者4.5 使用装饰者模式4.6 输出结果&#xff1a; 五、 应用场景5.1 图形用户界面…...

数据结构--单链表实现

欢迎光顾我的homepage 前言 链表和顺序表都是线性表的一种&#xff0c;但是顺序表在物理结构和逻辑结构上都是连续的&#xff0c;但链表在逻辑结构上是连续的&#xff0c;而在物理结构上不一定连续&#xff1b;来看以下图片来认识链表与顺序表的差别 这里以动态顺序表…...

2024攻防演练:亚信安全推出MSS/SaaS短期定制服务

随着2024年攻防演练周期延长的消息不断传出&#xff0c;各参与方将面临前所未有的挑战。面对强大的攻击队伍和日益严格的监管压力&#xff0c;防守单位必须提前进行全面而周密的准备和部署。为应对这一形势&#xff0c;亚信安全特别推出了为期三个月的MSS/SaaS短期订阅方案。该…...

基于java+springboot+vue实现的在线课程管理系统(文末源码+Lw)236

摘要 本文首先介绍了在线课程管理系统的现状及开发背景&#xff0c;然后论述了系统的设计目标、系统需求、总体设计方案以及系统的详细设计和实现&#xff0c;最后对在线课程管理系统进行了系统检测并提出了还需要改进的问题。本系统能够实现教师管理&#xff0c;科目管理&…...

每日一更 EFK日志分析系统

需要docker和docker-compose环境 下面时docker-compose.yaml文件 [rootnode1 docker-EFK]# cat docker-compose.yaml version: 3.3services:elasticsearch:image: "docker.elastic.co/elasticsearch/elasticsearch:7.17.5"container_name: elasticsearchrestart: …...

python类继承和类变量

Python一些类继承和实例变量的使用 定义基类 class APIException:code 500msg "Sorry, error"error_code 999def __init__(self, msgNone):print("APIException init ...")def error_400(self):pass复用基类的属性值 class ClientTypeError(APIExcept…...

js 随机生成整数

随机生成一个唯一的整数 id export const randomId () > { return Date.now() Math.floor(Math.random() * 10000) } 生成随机ID的方法 // 随机生成0 - 9999 export const randomId ()> { return Math.floor(Math.random() * 10000).toString() } // 随机生成0-999之…...

深入Django(七)

Django的数据库迁移系统 引言 在前六天的教程中&#xff0c;我们介绍了Django的基本概念、模型、视图、模板、URL路由和表单系统。今天&#xff0c;我们将讨论Django的数据库迁移系统&#xff0c;它是管理和跟踪数据库变化的关键组件。 Django数据库迁移概述 Django的数据库…...

【区分vue2和vue3下的element UI Steps 步骤条组件,分别详细介绍属性,事件,方法如何使用,并举例】

在 Vue 2 和 Vue 3 中&#xff0c;Element UI&#xff08;针对 Vue 2&#xff09;和 Element Plus&#xff08;针对 Vue 3&#xff09;提供了 Steps 步骤条组件&#xff0c;用于展示当前操作的进度步骤。虽然这两个库都提供了步骤条组件&#xff0c;但它们在属性、事件和方法的…...

uni-app x 跨平台开发框架

目录 uni-app x 是什么 和Flutter对比 uts语言 uvue渲染引擎 组合式API的写法 选项式API写法 页面生命周期 API pages.json全局配置文件 总结 uni-app x 是什么 uni-app x&#xff0c;是下一代 uni-app&#xff0c;是一个跨平台应用开发引擎。 uni-app x 是一个庞…...

YOLOv8模型调参---数据增强

目录 1.数据预处理 2.数据增强 2.1 数据增强的作用 2.2 数据增强方式与适用场景 2.2.1离线增强&#xff08;Offline Augmentation&#xff09; 2.2.2 在线增强&#xff08;Online Augmentation&#xff09; 3. 数据增强的具体方法 4. YOLOv8的数据增强 4.1 YOLOv8默认…...

【Nginx】docker运行Nginx及配置

Nginx镜像的获取 直接从Docker Hub拉取Nginx镜像通过Dockerfile构建Nginx镜像后拉取 二者区别 主要区别在于定制化程度和构建过程的控制&#xff1a; 直接拉取Nginx镜像&#xff1a; 简便性&#xff1a;直接使用docker pull nginx命令可以快速拉取官方的Nginx镜像。这个过程…...

tensorflow和numpy的版本

查看cuda版本 dpkg -l | grep cuda i libcudart11.0:amd64 11.5.117~11.5.1-1ubuntu1 amd64 NVIDIA CUDA Runtime Library ii nvidia-cuda-dev:amd64 11.5.1-1ubuntu1 …...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...