深度学习识别滑动验证码缺口

发布时间:2025-03-29 21:38:07编辑:123阅读(90)

    目标检测

    识别滑动验证码的目标缺口问题,其实可以归结为目标检测问题。什么叫目标检测?顾名思义就是把想找的东西找出来,也就是找图片缺口位置。现在比较流行的目标检测算法有R-CNN,Fast R-CNN,Faster R-CNN,SSD,YOLO等。

    目前目标检测算法主要有两种实现方法,一阶段式和二阶段式。

    一阶段式(One stage):不需要产生候选框,直接将目标的定位和分类问题转化为回归问题,俗称“看一眼”,使用这种实现的算法有YOLO和SSD,这种方法虽然正确率不及Two Stage,但架构相对简单,检测速度更快。

    二阶段式(Two Stage):算法首先生成一系列目标所在位置的候选框,再对这些候选出来的结果进行样本分类,即先找出来在哪儿,再分出来是啥,俗称“看两眼”,使用这种实现的算法有R-CNN,Fast R-CNN,Faster R-CNN等,这种方法架构相对复杂,但正确率高。

    选用YOLO算法实现对滑动验证码缺口的识别。YOLO的英文全称是You Only Look Once,目前的最新版本是V5,应用比较广泛的版本是V3。


    数据准备

    训练深度学习模型需要准备训练数据。这里的数据也分两部分,一部分是验证码图片,另一部分是标注数据。这次的数据标注不再是单纯的验证码文本,而是缺口位置,缺口对应一个矩形框,要表示矩形框,至少需要4个数据,如矩形左上角的点的纵横坐标下x,y加上矩形的宽高w,h。

    明确了数据是什么,接下来就准备。第一步是收集验证码图片,第二步是标注图片中的缺口位置并转化为想要的4位数字。打开网站https://passport.jd.com/new/login.aspx,点击“登录”按钮就会弹出一个滑动验证码。

    image.png

    手工截图肯定不可靠,因为要收集的图片量非常大,这么做不仅费时费力,还不好准确地定位边界,会导致保存下来的图片有大有小。写一个脚本实现自动化裁切和保存。

    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.common.exceptions import WebDriverException
    from loguru import logger
    
    
    COUNT = 100
    
    for i in range(0, COUNT + 1):
        try:
            browser = webdriver.Chrome()
            browser.get('https://passport.jd.com/new/login.aspx')
            browser.implicitly_wait(30)
            # 账户
            browser.find_element(By.ID, 'loginname').send_keys('username')
            time.sleep(0.3)
            # 密码
            browser.find_element(By.ID, 'nloginpwd').send_keys('password')
            time.sleep(0.2)
            # 登录
            browser.find_element(By.ID, 'loginsubmit').click()
            time.sleep(0.5)
            # 下载图片
            img_dir_name = f'D:\PythonProject_deep_learning_slide_verification\images\captcha_{i}.png'
            captcha = browser.find_element(By.XPATH,'//div[@class="JDJRV-bigimg"]/img').screenshot(img_dir_name)
        except WebDriverException as e:
            logger.error(f'webdriver error occurred {e.msg}')
        finally:
            browser.close()

    代码逻辑先是一个for循环,循环次数为count,每次循环都使用selenium启动一个浏览器,然后打开目标网站,模拟点击登录按钮的操作触发验证码弹出,然后截取验证码对应的节点,再调用screenshot方法保存下来。

    运行完后,目录下会有非常多的图片。

    image.png

    第一步完成,接下来完成第二步,准备数据标注,这里推荐使用的工具是labelImg,使用pip直接可以安装

    pip install labelImg

    image.png

    安装完后在命令行直接运行 labelImg

    image.png

    点击左侧的Open Dir 按钮打开刚刚下载的images目录,然后点击左下角的Create RectBox创建一个标注框,可以将缺口所在的矩形框框起来,框完后labelImg会弹出填写保存名称的提示框,填写target,然后点击ok按钮

    image.png

    这时会发现本地保存了一个xml文件,内容如下:

    <annotation>
        <folder>images</folder>
        <filename>captcha_0.png</filename>
        <path>D:\PythonProject_deep_learning_slide_verification\images\captcha_0.png</path>
        <source>
           <database>Unknown</database>
        </source>
        <size>
           <width>343</width>
           <height>133</height>
           <depth>3</depth>
        </size>
        <segmented>0</segmented>
        <object>
           <name>target</name>
           <pose>Unspecified</pose>
           <truncated>0</truncated>
           <difficult>0</difficult>
           <bndbox>
              <xmin>172</xmin>
              <ymin>28</ymin>
              <xmax>220</xmax>
              <ymax>76</ymax>
           </bndbox>
        </object>
    </annotation>

    从中可以看到,size节点里有三个节点,分别是width,height,depth,代表原验证码图片的宽度,高度和通道数。object节点下的bndbox节点包含标注的缺口位置,通过观察对比可以直到xmin,ymin指的是左上角的坐标,xmax,ymax指的是右下角的坐标。

    使用下面的方法简单做一下数据处理:

    import xmltodict
    import json
    import os
    
    xml_path = os.path.join(os.getcwd(), 'annotation_images')
    txt_path = os.path.join(os.getcwd(), 'labels')
    
    def parse_xml(file):
        xml_str = open(file, mode='r', encoding='utf-8').read()
        data = xmltodict.parse(xml_str)
        data = json.loads(json.dumps(data))
        annotation = data.get('annotation')
        width = int(annotation.get('size').get('width'))
        height = int(annotation.get('size').get('height'))
        bndbox = annotation.get('object').get('bndbox')
        box_xmin = int(bndbox.get('xmin'))
        box_xmax = int(bndbox.get('xmax'))
        box_ymin = int(bndbox.get('ymin'))
        box_ymax = int(bndbox.get('ymax'))
    
        # 计算中心点坐标和宽高
        x_center = (box_xmin + box_xmax) / 2.0
        y_center = (box_ymin + box_ymax) / 2.0
        box_width = box_xmax - box_xmin
        box_height = box_ymax - box_ymin
    
        # 归一化处理
        x_center /= width
        y_center /= height
        box_width /= width
        box_height /= height
        print(x_center, y_center, box_width, box_height)
        return x_center, y_center, box_width, box_height
    
    def main():
        current_directory = xml_path
        files = []
        for root, dirs, filenames in os.walk(current_directory):
            for file in filenames:
                if os.path.isfile(os.path.join(root, file)):
                    files.append(os.path.join(root, file))
        return files
    
    files = main()
    for img_path in files:
        file_name = os.path.basename(img_path).split('.')[0]
        box_xmin, box_ymin, box_width, box_height = parse_xml(img_path)
        with open(os.path.join(txt_path, file_name + '.txt'), 'w', encoding='utf-8') as f:
            f.write(" ".join([str(0), str(box_xmin), str(box_ymin), str(box_width), str(box_height)]))

    运行上面代码,结果如下:

    image.png

    其中每一个txt文件各对应一张验证码图片的标注结果,文件内容类似这样:

    0 0.5714285714285714 0.39097744360902253 0.13994169096209913 0.3609022556390977


    第一位0代表标注目标的索引,由于这里只需要检测一个缺口,所以索引就是0;第二位和第三位代表缺口左上角的点在验证码图片中所处的位置,例如0.5714285714285714代表从横向看,缺口左上角的点大约位于验证码的57%处,至此数据准备阶段完成。

    为了达到更好的训练效果,还需要下载一些预训练模型,预训练的意思是已经有一个提前训练好的基础模型了。直接使用预训练模型中的权重文件,就不用从零开始训练模型了,只需要基于之前的模型进行微调即可,这样既节省训练时间,又能达到比较好的效果。


    使用YOLO5训练滑动验证缺口验证码

    环境安装(wsl环境安装,可参考https://www.py3study.com/Article/details/id/20089.html#   wsl安装):

    git clone https://github.com/ultralytics/yolov5

    cd yolov5

    pip install -r requirements.txt

    目录结构

    slide_ver/

    ├── images

    │   └── slide   # 带缺口的原图 

    └── labels

        └── slide    # 经过labelImg标注处理过的yolo数据集格式

    YOLO的数据集格式

    image.png

    cd /yolo/yolov5/data

    vim sliding.yaml

    path: ../datasets/slide_ver     # 目录
    train: images/slide             # 训练集
    val: images/slide               # 验证集
    nc: 1                           # 类别数量
    names: ['slideing']             # 类别名:避免用中文

    把对应的数据拷进对应的目录,修改train.py,如下:

    image.png

    保存,运行。

    python train.py

    image.png

    训练完成.

    信息中的参数是介绍:

    Epoch         训练轮数

    gpu_mem   gpu占用内存

    box      边界框损失 YOLO V5使用 GIOU Loss作为bounding box的损失,Box推测为GIoU损失函数均值,越小方框越准;

    obj     目标检测损失 推测为目标检测loss均值,越小目标检测越准;

    cls      分类损失 推测为分类loss均值,越小分类越准;(缺口只有一个类别所以为0没有浮动)

    img_size   图片尺寸默认为640

    Images    测试集图片个数849张

    Labels    测试集标签个数847张

    P    精度

    R    召回率

    一般训练结果主要观察精度和召回率波动情况

    看一下测试集的预测效果:

    cd /yolo/yolov5/runs/train/slideing

    打开val_batch0_labels.jpg

    image.png

    最重要的是在weights目录下有两个pt模型

    image.png

    最好的模型,和最后的模型,之后验证就可以用着模型进行验证.


    验证模型

    把需要测试的图片放到对应的目录

    image.png

    在detect.py文件中配置可以对模型进行检测

    image.png

    运行detect.py

    image.png

    到对应的目录查看效果,如下:

    image.png

    yolo有接口测试就在utils下的flask_rest_api文件中restapi.py是服务端,example_requset.py是客户端。

    pip install  flask

    python restapi.py --port 5000

    image.png

    客户端访问:

    import requests
    import os
    
    
    DETECTION_URL = "http://127.0.0.1:5000/v1/object-detection/yolov5s"
    IMAGE = os.path.join(os.getcwd(), 'verify_images/captcha_0.png')
    # Read image
    with open(IMAGE, "rb") as f:
        image_data = f.read()
    
    response = requests.post(DETECTION_URL, files={"image": image_data}).json()
    
    print(response)

    [{'xmin': 91.528755188, 'ymin': 4.3374404907, 'xmax': 140.5720062256, 'ymax': 45.5197601318, 'confidence': 0.6900528669, 'class': 14, 'name': 'bird'}]

关键字

上一篇: Ai之大模型-公开数据集-理论6.2

下一篇: 没有了