当前位置: 首页 > 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 …...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...