【项目】基于YOLOv8和RotNet实现圆形滑块验证码(拼图)自动识别(通过识别中间圆形的角度实现)

@TOC

一、引言

1.1 实现目标

要达到的效果是使用算法预测中间圆形的角度,返回给服务器,实现自动完成验证码的问题。要实现的内容如下图所示。
在这里插入图片描述

在这里插入图片描述

1.2 实现思路

思路1(效果较差):以RotNet要实现的验证码识别为灵感,先利用YOLO算法检测出中间圆,再把圆形图像输入给RotNet,让其预测角度,进而返回给服务器。

但是实际应用的过程中,笔者发现这种算法逻辑执行效果较差。
因为RotNet要完成的是独立的圆预测角度,实现的是如下图所示的圆的角度预测,单独的圆就已经是独立出来的一张图像,因此直接输入进网络,预测效果会很好
在这里插入图片描述
但是我们要实现的相当于中间圆和外部图形的拼图操作,而不仅仅是简单的预测角度,所以直接把中间的圆拿出来进行角度预测,显然脱离了背景,而且有些题把中间独立的圆抠出来之后,很难对其角度进行定义,所以效果很差
在这里插入图片描述

思路2:有了思路1的教训,我们要做的第一步就是把外部的背景图像引入进来进行训练

二、数据集制备

网络上没有此类开源的数据集,因此笔者自行进行了制备,具体分为以下两种:

  1. 一种是以下这种圆完全归位的一整张图,都是用美工P图的方法进行制备的在这里插入图片描述
  2. 第二种是直接截取的这种没有P图过的没有修正过的图像
    在这里插入图片描述
    此类数据集制备完成之后再用笔者编写的脚本使其归位,部分代码如下
    大致思路为:
  • 先使用YOLO算法检测出图像中的圆
  • 再利用算法使用a、d两个按键进行角度偏转,使用z、c两个按键进行切图
  • 观察到图像回正之后,按s键保存到指定文件夹下

效果如下:

3eb50dabc910b6

import math
import numpy as np
import cv2
from ultralytics import YOLO
import os

yolo_model = YOLO(r"D:\kb\rotate-captcha-crack-master_my\yolo.pt")

def code_dect(folder_path, output_path):
    files = []
    current_index = 0

    while True:
        if not files:
            print("文件夹中没有图像文件。")
            break

        img_path = os.path.join(folder_path, files[current_index])
        img = cv2.imread(img_path)
        imgDoub = img
        # 检测出的box
        center_box = []
        results = yolo_model.predict(img, stream=True)
        boxAll = []
        for r in results:
            boxes = r.boxes
            for box in boxes:
                x1, y1, x2, y2 = box.xyxy[0]  # 获取边界框的坐标
                x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
                w, h = x2 - x1, y2 - y1
                bbox = (x1, y1, w, h)
                boxAll.append(bbox)
        # 计算图像中心坐标
        width, height = img.shape[0], img.shape[1]
        image_center_x = width / 2
        image_center_y = height / 2
        # 找出距离图像中心最近的矩形框
        min_distance = float('inf')

        for rectangle in boxAll:
            center_x, center_y = calculate_center(rectangle)
            distance = math.sqrt((center_x - image_center_x) ** 2 + (center_y - image_center_y) ** 2)
            if distance < min_distance:
                min_distance = distance
                center_box = rectangle

        if center_box == []:
            print(f"没有检测到目标:{img_path}")
        else:
            # 创建与图像相同大小的黑色背景
            mask = np.zeros_like(imgDoub[:, :, 0])
            # 定义圆的外接矩形坐标
            x, y, w, h = center_box
            # 在掩码上绘制白色的圆形
            cv2.circle(mask, (x + w // 2, y + h // 2), min(w, h) // 2, (255, 255, 255), -1)
            # 将掩码应用到白色背景上,保留圆形区域
            onlyCircle = cv2.bitwise_and(imgDoub, imgDoub, mask=mask)
            mask2 = np.zeros_like(img, dtype=np.uint8)
            # 在掩码上绘制圆形区域
            cv2.circle(mask2, (x + w // 2, y + h // 2), min(w, h) // 2, (255, 255, 255), -1)

            rotate = True
            reverse = False
            angle = 0

            while rotate:
                # 获取图像的中心点坐标
                height, width = onlyCircle.shape[:2]
                center = (width // 2, height // 2)
                # 定义旋转矩阵
                rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
                # 进行旋转变换
                rotated_image = cv2.warpAffine(onlyCircle, rotation_matrix, (width, height))
                # 将圆形区域置为0
                imgDoub[mask2 != 0] = 0
                result = rotated_image + imgDoub
                cv2.imshow("result", result)

                # 添加按键监听
                key = cv2.waitKey(1)

                # z、c分别是切换上一张或者下一张图
                if key == ord('z'):
                    current_index = (current_index - 1) % len(files)
                    break
                # 按下 'c' 键逆时针旋转
                elif key == ord('c'):
                    current_index = (current_index + 1) % len(files)
                    break
                # 按下 's' 键保存图像
                elif key == ord('s'):
                    output_img_path = os.path.join(output_path, files[current_index])
                    cv2.imwrite(output_img_path, result)
                    print(f"图像已保存到:{output_img_path}")
                if key == ord('a'):
                    angle += 1
                    # 按下 'd' 键逆时针旋转
                elif key == ord('d'):
                    angle -= 1
                elif key == ord('q'):
                    angle += 10
                elif key == ord('e'):
                    angle -= 10


if __name__ == '__main__':
    folder_path = input("请输入文件夹路径:")
    output_path = input("请输入输出路径:")
    code_dect(folder_path, output_path)

三、算法逻辑

1、生成样本

使用RotNet作为本算法的预测核心预测算法,把我们上文中生成的回正数据首先利用编写的脚本给每张图像生成360张不同角度的图像,文件名的后缀代表这张图象真实的偏转角度。
,

2、训练算法

把生成的所有图像输入进改进的RotNet进行训练,由于这种类型的样本学习很容易出现过拟合的现象,因此笔者在网络中加了几个DropOut操作。

3、算法逻辑

我们并没有简单把单张图像输入进算法来进行角度预测,这样360个类别误差太大效果会比较差,在应用的时候我们也是先把中间的圆形图像抠出来,然后对其使用算法旋转360度,把360张图像都进行角度预测,最后取出0到3度和357到359度的图像返回它的序列值,即真实的角度值。如果没有这些范围之内的图像,那就返回-1,切下一张图像,防止错误次数太多。代码如下所示:

import math
import numpy as np
import torch
from PIL import Image
from rotate_captcha_crack.common import device
from rotate_captcha_crack.model import RotNetR
from rotate_captcha_crack.utils import process_captcha
import cv2
from ultralytics import YOLO

yolo_model = YOLO(r"D:\chenjie\rotate-captcha-crack-master_my\yolo.pt")

def calculate_center(rectangle):
    x, y, w, h = rectangle
    center_x = x + w / 2
    center_y = y + h / 2
    return center_x, center_y



model = RotNetR(train=False, cls_num=360)
model_path = r"D:\chenjie\rotate-captcha-crack-master_my\models\RotNetR\240316_17_14_23_006\best.pth"

model.load_state_dict(torch.load(str(model_path)))
model = model.to(device=device)
model.eval()
def predictAngle(img):
    img = Image.fromarray(img)
    img_ts = process_captcha(img)
    img_ts = img_ts.to(device=device)
    predict = model.predict(img_ts)
    return predict

def code_dect(img):
    imgDoub = img
    # 检测出的box
    center_box = []
    results = yolo_model.predict(img, stream=True)
    boxAll = []
    for r in results:
        boxes = r.boxes
        for box in boxes:
            x1, y1, x2, y2 = box.xyxy[0]  # Gives coordinates to draw bounding box
            x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
            w, h = x2 - x1, y2 - y1
            bbox = (x1, y1, w, h)
            boxAll.append(bbox)
    # 计算图像中心坐标
    width, height = img.shape[0], img.shape[1]
    image_center_x = width / 2
    image_center_y = height / 2
    # 找出距离图像中心最近的矩形框
    min_distance = float('inf')

    for rectangle in boxAll:
        center_x, center_y = calculate_center(rectangle)
        distance = math.sqrt((center_x - image_center_x) ** 2 + (center_y - image_center_y) ** 2)
        if distance < min_distance:
            min_distance = distance
            center_box = rectangle

    if center_box==[]:
        print("kong")
    else:
        # 把圆区域搞出来
        # 创建与图像相同大小的黑色背景
        mask = np.zeros_like(imgDoub[:, :, 0])
        # 定义圆的外接矩形坐标
        x, y, w, h = center_box
        # 在掩码上绘制白色的圆形
        cv2.circle(mask, (x + w // 2, y + h // 2), min(w, h) // 2, (255, 255, 255), -1)
        # 将掩码应用到白色背景上,保留圆形区域
        onlyCircle = cv2.bitwise_and(imgDoub, imgDoub, mask=mask)
        # 显示结果图像
        # cv2.imshow('Only Circle', onlyCircle)
        # cv2.imshow('imgDoub', imgDoub)
        # cv2.waitKey(0)
        mask2 = np.zeros_like(img, dtype=np.uint8)
        # 在掩码上绘制圆形区域
        cv2.circle(mask2, (x + w // 2, y + h // 2), min(w, h) // 2, (255, 255, 255), -1)
        angles = []
        for angle in range(0, 360):
            # 获取图像的中心点坐标
            height, width = onlyCircle.shape[:2]
            center = (width // 2, height // 2)
            # 定义旋转矩阵
            rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
            # 进行旋转变换
            rotated_image = cv2.warpAffine(onlyCircle, rotation_matrix, (width, height))
            # 将圆形区域置为0
            imgDoub[mask2 != 0] = 0
            result = rotated_image+imgDoub
            predict = predictAngle(result)
            # cv2.imshow("sdf",result)
            # print(predict)
            # cv2.waitKey(10)
            angles.append(predict)
        minAngle = min(angles)
        maxAngle = max(angles)
        minAngleIdx = angles.index(min(angles))
        maxAngleIdx = angles.index(max(angles))
        finalAngleIdx = -1

        if maxAngle>356:
            finalAngleIdx = maxAngleIdx
        elif minAngle<4:
            finalAngleIdx = minAngleIdx
        print(finalAngleIdx)
        return finalAngleIdx


if __name__ == '__main__':
    # 测试整体
    img = cv2.imread("D:\chenjie\\rotate-captcha-crack-master_my\images\e42c0939dc3bde88657a88ac07d59d6.png")
    code_dect(img)

最后可以达到80-90%的通过率,效果已经很不错了
演示效果如下:

ab7c1b94c3bc27b8

三、代码、数据集获取

q:1831255794(有偿)制备数据集和写算法耗费了大量时间精力,因此收取点小费希望理解!!!
可接项目,大作业,毕设等 
价格略贵,技术够硬,认真负责,保证质量

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序(五十九)使用鉴权组件时原页面js自动加载解决方法(24/3/14)

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.使用覆盖函数的方法阻止原页面的自动执行方法 2.使用判断实现只有当未登录时才进行方法覆盖 源码&#xff1a; app.json {"pages": ["pages/index/index","pages/logs/logs"],…

python中如何生成词云

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 今天给大家看看&#xff0c;如何使用python实现根据记录创建生成词云 首先我们看下效果图。 一个是生成了新闻的词云&#xff0c;另一个是生成了聊天记录的词云。下面是代码&#xff1a; …

Java学习笔记(19)

双列集合 键值对 一一对应 键值对对象 entry Map Put第一次给不存在的key&#xff0c;会把键值对添加到map中&#xff0c;返回null Put给同一个key是会覆盖value的&#xff0c;返回被覆盖的值value Remove根据key删除键值对&#xff0c;返回被删除的值value Map遍历 键找值 …

python语法踩坑 | list的append操作如何从in-place改为out-of-place

背景 博主写python遇到一个问题&#xff0c;需要把对list添加元素改为非原地操作&#xff0c;即不修改原list。 但是由于列表中的元素是字典类型&#xff0c;无法直接用运算符。 于是写出了下面这行代码 query_list message_list.copy().append(one_question) 其中message…

Anaconda安装 (windowsLinux)

文章目录 Anaconda简介设置国内源pip || conda 一、Anaconda &#xff08;Windows系统&#xff09;1.1 下载及安装1.2 虚拟环境创建1.3 在Pycharm中配置conda的环境 二、Anaconda&#xff08;Linux系统&#xff09; Anaconda简介 conda是一个开源的包、环境管理器&#xff0c;可…

探索 Atlassian 云平台:组织、站点、产品架构解析

我们通常访问的是 Atlassian 的某个云站点&#xff0c;比如填空题-中国站点为&#xff1a;cloze-cn.atlassian.net。当我们访问该站点内的具体产品时&#xff0c;只需在该站点的 URL 后添加相应产品的缩写&#xff0c;例如&#xff1a; Confluence: cloze-cn.atlassian.net/wi…

12.电子产品拆解分析-LED T8_16W灯管

12.电子产品拆解分析~LED_T8_16W家用灯管 一、功能介绍二、电路分析以及器件作用一、功能介绍 ①无需使用镇流器(启辉器),只需接到220V即可点亮使用;②节能省电 透光性强 无可视频闪;二、电路分析以及器件作用 220V交流电经过MB10F桥式整流出300V脉动直流电,然后经过6.8u…

某J 集成 cas5.3res api登录

在学习一个开源项目是时集成了cas&#xff0c;但文档过于简单&#xff0c;研究了两天这次记录做个补充 1.下载cas项目 GitHub - apereo/cas-overlay-template at 5.3 2.编译 解压zip&#xff0c;命令行进去&#xff0c;执行mvn clean package 结束之后会出现 target 文件夹&…

Android14 - Framework- Configuration的创建和更新

本文描述从启动一个新进程的Activity起&#xff0c;Framwork层Configuration的创建和传导过程。 首先&#xff0c;我们知道所有的Window容器都继承于WindowContainer&#xff0c;而WindowContainer本身是ConfigurationContainer的子类。于此同时&#xff0c;WindowProcessContr…

[NOIP1998 提高组] 拼数

[NOIP1998 提高组] 拼数 题目描述 设有 n n n 个正整数 a 1 … a n a_1 \dots a_n a1​…an​&#xff0c;将它们联接成一排&#xff0c;相邻数字首尾相接&#xff0c;组成一个最大的整数。 输入格式 第一行有一个整数&#xff0c;表示数字个数 n n n。 第二行有 n n …

【Vue3遇见的问题】创建vue3的项目使用vscode打开后项目的app.vue里面存在爆红

出现的问题 直接上上问题:问题的图片如下: 解决方法 解决效果 补充 因为vetur的插件禁用了 所以需要一个新插件来 这里发现的官网推荐的插件 也就是volar 他两是一样的

各位老板,你需要的工厂数字孪生可视化库在这

各位老板是不是很喜欢下面这种有逼格的大屏,下面介绍一下怎么实现的,保证有所收获。 Cesium是一个开源的WebGL JavaScript库&#xff0c;用于创建高性能的三维地球、地图和虚拟环境。它支持在浏览器中实现高质量的地球模拟&#xff0c;同时提供了丰富的功能特点&#xff0c;使得…

【Linux进程的状态】

目录 看Linux源码中的说法 如何查看进程状态&#xff1f; 各个状态的关系 僵尸进程 举个栗子 现象 僵尸进程的危害 孤儿进程 举个栗子 现象 进程的优先级 基本概念 为什么要有进程优先级&#xff1f; 查看系统进程 进程的大致属性 进程优先级vs进程的权限 Linu…

AI基础知识(4)--贝叶斯分类器

1.什么是贝叶斯判定准则&#xff08;Bayes decision rule&#xff09;&#xff1f;什么是贝叶斯最优分类器&#xff08;Bayes optimal classifier&#xff09;&#xff1f; 贝叶斯判定准则&#xff1a;为最小化总体风险&#xff0c;只需在每个样本上选择那个能使条件风险最小的…

用 Open-Sora 高效创作视频,让创意触手可及

近年来&#xff0c;视频内容以爆炸式增长席卷了我们的生活。从短视频平台到直播带货&#xff0c;视频正成为人们获取信息和娱乐的主要方式。然而&#xff0c;传统视频制作流程往往耗时费力&#xff0c;对于普通用户来说门槛较高。 为了降低视频创作门槛&#xff0c;让更多人享…

Git的 .gitignore文件及标签使用

Git的 .gitignore文件及标签使用 什么是.gitignoregit check-ignore -v 文件名 查看.gitignore里面什么内容忽略了该文件 git add -f [filename] 强制添加把指定文件排除在 .gitignore 规则外的写法给命令配置别名标签创建标签git tag [name] 创建标签git tag 列出所有标签git …

RESNET的复现pytorch版本

RESNET的复现pytorch版本 使用的数据为Object_102_CaDataset&#xff0c;可以在网上下载&#xff0c;也可以在评论区问。 RESNET模型的亮点 1.提出了残差模块。 2.使用Batch Normalization加速训练 3.残差网络&#xff1a;易于收敛&#xff0c;很好的解决了退化问题&#…

真实数据!一张切片实现101种蛋白的超多重空间单细胞原位成像

头颈鳞状细胞癌 (HNSCC) 是第七大常见癌症。免疫检查点抑制剂 (ICIs) 在治疗复发/转移病例方面显示出良好前景&#xff0c;约30%的患者可获得持久获益。但是目前反映HNSCC肿瘤微环境 (TME) 特征的生物标志物有限&#xff0c;需要更深入的组织表征分析。因此&#xff0c;需要新的…

linux查看cpu/内存/磁盘利用率

1、cpu 命令&#xff1a; top 2、内存 命令&#xff1a; free -h 3、磁盘 命令&#xff1a; df -h

《操作系统真相还原》读书笔记九:用c编写内核

用c语言先编写一个死循环 main.c int main(void) {while(1);return 0; }编译该文件 gcc -c -o main.o main.c-- Ttext参数表示起始虚拟地址为0xc0001500 -e参数表示程序入口地址 ld main.o -Ttext 0xc0001500 -e main -o kernel.bin-- 将kernel.bin写入第9个扇区 dd if/ho…
最新文章