京东手势验证码-YOLO姿态识别+Bézier curve轨迹拟合

news2024/11/26 0:16:50

这次给老铁们带来的是京东手势验证码的识别。

目标网站:https://plogin.m.jd.com/mreg/index

验证码如下图:

图片

当第一眼看到这个验证码的时候,就头大了,这玩意咋识别???

静下心来细想后的一个方案,就是直接用yolo的目标检测去硬刚,方案如下:

根据曲线的特征,提取较特殊的

  • 起末点(1)
  • 转折点(2)
  • 相较点(3)

进行打标提取几个点的位置,然后根据曲线斜率和长度的关系进行连接,得到曲线的轨迹,但是这种我感觉成功率可能不会很高,就没有试了,不过肯定也是可行的,感兴趣的可以自行尝试哈。

图片

图片

于是我便寻找下一种方案,辗转反侧,夜不能寐,终于看到一篇文章介绍了

yolo8-pose姿态检测模型

图片

可以通过目标图关键点实现骨架连接,那么同理我们的手势曲线,也可利用关键点检测实现轨迹连接。

图片

话不多说直接开干

yolo8仓库地址:https://github.com/ultralytics/ultralytics

然后下载labelme标注软件,图片可存放在ultralytics目录下新建的imgs文件夹。

yolo8-pose 需要进行目标框选和关键点匹配,进行如下形式的标注,

这里一开始的关键点我只用了4个,训练出来的效果极差,后面加到了10个相对好很多。

图片

打标完成后会生成json文件,我们要转换成yolo可以识别txt文件

这里需要注意这些参数

  • class_list 是你框选的名称
  • keypoint_list 是关键点名称,要按顺序来,不然连接的时候会乱
  • img_list = glob.glob(“imgs/*.png”) 图片加载路径

# -*-coding:utf-8 -*-

"""
# File       : labelme_to_yolo.py
# Time       : 2024/5/8 16:40
# Author     : 阿J
# version    : 2024
# Description: 
"""
# 将labelme标注的json文件转为yolo格式
import cv2
import glob
import json
import tqdm

# 物体类别

class_list = ["box"]
# 关键点的顺序
keypoint_list = ["1",'11','22', "2",'33','44', "3",'55','66', "4"]


def json_to_yolo(img_data, json_data):
    h, w = img_data.shape[:2]
    # 步骤:
    # 1. 找出所有的矩形,记录下矩形的坐标,以及对应group_id
    # 2. 遍历所有的head和tail,记下点的坐标,以及对应group_id,加入到对应的矩形中
    # 3. 转为yolo格式
    rectangles = {}
    # 遍历初始化
    for shape in json_data["shapes"]:
        label = shape["label"]  # pen, head, tail
        group_id = shape["group_id"]  # 0, 1, 2, ...
        points = shape["points"]  # x,y coordinates
        shape_type = shape["shape_type"]

        # 只处理矩形,读矩形
        if shape_type == "rectangle":
            if group_id not in rectangles:
                rectangles[group_id] = {
                    "label": label,
                    "rect": points[0] + points[1],  # Rectangle [x1, y1, x2, y2]
                    "keypoints_list": []
                }
    # 遍历更新,将点加入对应group_id的矩形中,读关键点,根据group_id匹配
    for keypoint in keypoint_list:
        for shape in json_data["shapes"]:
            label = shape["label"]
            group_id = shape["group_id"]
            points = shape["points"]
            # 如果匹配到了对应的keypoint
            if label == keypoint:
                rectangles[group_id]["keypoints_list"].append(points[0])
            # else:
            #   rectangles[group_id]["keypoints_list"].append([0,0])

    # 转为yolo格式
    yolo_list = []
    for id, rectangle in rectangles.items():
        result_list = []
        if rectangle['label'] not in class_list:
            continue
        label_id = class_list.index(rectangle["label"])
        # x1,y1,x2,y2
        x1, y1, x2, y2 = rectangle["rect"]
        # center_x, center_y, width, height
        center_x = (x1 + x2) / 2
        center_y = (y1 + y2) / 2
        width = abs(x1 - x2)
        height = abs(y1 - y2)
        # normalize
        center_x /= w
        center_y /= h
        width /= w
        height /= h

        # 保留6位小数
        center_x = round(center_x, 6)
        center_y = round(center_y, 6)
        width = round(width, 6)
        height = round(height, 6)

        # 添加 label_id, center_x, center_y, width, height
        result_list = [label_id, center_x, center_y, width, height]

        # 添加 p1_x, p1_y, p1_v, p2_x, p2_y, p2_v
        for point in rectangle["keypoints_list"]:
            x, y = point
            x, y = int(x), int(y)
            x /= w
            y /= h
            # 保留2位小数
            x = round(x, 2)
            y = round(y, 2)
            result_list.extend([x, y, 2])
        # if len(rectangle["keypoints_list"]) == 4:
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #
        # if len(rectangle["keypoints_list"]) == 2:
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])
        #     result_list.extend([0, 0, 0])

        yolo_list.append(result_list)
    return yolo_list

import os
print(os.getcwd())
# 获取所有的图片
img_list = glob.glob("imgs/*.png")
for img_path in tqdm.tqdm(img_list):
    img = cv2.imread(img_path)
    print(img_path)
    json_file = img_path.replace('png', 'json')
    with open(json_file) as json_file:
        json_data = json.load(json_file)

    yolo_list = json_to_yolo(img, json_data)
    yolo_txt_path = img_path.replace('png', 'txt')

    with open(yolo_txt_path, "w") as f:
        for yolo in yolo_list:
            for i in range(len(yolo)):
                if i == 0:
                    f.write(str(yolo[i]))
                else:
                    f.write(" " + str(yolo[i]))
            f.write("\n")

执行上面的代码后就会生成txt文件
在这里插入图片描述
然后我们在ultralytics目录下的ultralytics/data新建images、labels文件夹,目录格式如下,然后对imges图片和labels标签(txt)进行分类即可
在这里插入图片描述
接着是修改yaml文件,如下图所示

在这里插入图片描述
当然还需要下载预训练模型yolov8s-pose.pt,在官网的这个位置

在这里插入图片描述
最后新建一个my_train.py文件,对应填入yaml、model的路径即可开始训练

# -*-coding:utf-8 -*-

"""
# File       : my_train.py
# Time       : 2024/5/8 16:55
# Author     : 阿J
# version    : 2024
# Description: 
"""
#训练代码
from ultralytics import YOLO

# Load a model
model = YOLO(r'E:\ultralytics-main\ultralytics\weight\yolov8s-pose.pt')

# Train the model
results = model.train(data=r'E:\ultralytics-main\ultralytics\cfg\datasets\coco-pose.yaml', epochs=300, imgsz=320)


# # 验证代码
# from ultralytics import YOLO
#
# # Load a model
# model = YOLO(r'E:\ultralytics-main\runs\pose\train4\weights\last.pt')
#
# # Val the model
# results = model.val(data=r'E:\ultralytics-main\ultralytics\cfg\datasets\coco-pose.yaml',imgsz=320,batch=6,workers=8)

左边是目标检测,右边是关键点检测(map50会慢慢上去)

在这里插入图片描述
训练好后,可以用上面的的验证代码进行验证一下,模型路径在runs\pose\train

打标图片

在这里插入图片描述
验证图片

在这里插入图片描述

也可用以下代码进行推理


# -*-coding:utf-8 -*-

"""
# File       : 推理.py
# Time       : 2024/5/8 17:59
# Author     : 阿J
# version    : 2024
# Description: 
"""
import io

# 测试图片
from ultralytics import YOLO
import cv2
import numpy as np
import time

# 读取命令行参数
# weight_path = r'E:\ultralytics-main\runs\pose\train4\weights\last.pt'
weight_path = 'best.pt'
# media_path = "img/1715153883102.png"
# media_path = "xxx.png"
media_path = "img.png"

time1 = time.time()
# 加载模型
model = YOLO(weight_path)
print("模型加载时间:", time.time() - time1)
# 获取类别
objs_labels = model.names  # get class labels
# print(objs_labels)

# 类别的颜色
class_color = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0),(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0),(255, 0, 0), (0, 255, 0)]
# 关键点的顺序
class_list = ["box"]

# 关键点的颜色
keypoint_color = [(255, 0, 0), (0, 255, 0),(255, 0, 0), (0, 255, 0),(255, 0, 0), (0, 255, 0),(255, 0, 0), (0, 255, 0),(255, 0, 0), (0, 255, 0)]


def cv2_imread_buffer(buffer):
    # 假设buffer是一个字节流对象
    buffer = io.BytesIO(buffer)

    # 将buffer转换为numpy数组
    arr = np.frombuffer(buffer.getvalue(), np.uint8)

    # 使用cv2.imdecode函数将numpy数组解码为图像
    img = cv2.imdecode(arr, cv2.IMREAD_COLOR)

    return img

def pose_ocr(img):
    # 读取图片
    if isinstance(img,str):
        frame = cv2.imread(img)
    else:
        frame = cv2_imread_buffer(img)
    # frame = cv2.resize(frame, (280, 280))
    # 检测
    result = list(model(frame, conf=0.5, stream=True))[0]  # inference,如果stream=False,返回的是一个列表,如果stream=True,返回的是一个生成器
    boxes = result.boxes  # Boxes object for bbox outputs
    boxes = boxes.cpu().numpy()  # convert to numpy array

    # 遍历每个框
    for box in boxes.data:
        l, t, r, b = box[:4].astype(np.int32)  # left, top, right, bottom
        conf, id = box[4:]  # confidence, class
        id = int(id)
        # 绘制框
        cv2.rectangle(frame, (l, t), (r, b), (0, 0, 255), 1)
        # 绘制类别+置信度(格式:98.1%)
        cv2.putText(frame, f"{objs_labels[id]} {conf * 100:.1f}", (l, t - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                    (0, 0, 255), 2)

    # 遍历keypoints
    keypoints = result.keypoints  # Keypoints object for pose outputs
    keypoints = keypoints.cpu().numpy()  # convert to numpy array

    pose_point = []
    # draw keypoints, set first keypoint is red, second is blue
    for keypoint in keypoints.data:
        pose_point = [[round(x),round(y)] for x,y,c in keypoint]
        for i in range(len(keypoint)):
            x, y ,_ = keypoint[i]
            x, y = int(x), int(y)
            cv2.circle(frame, (x, y), 3, (0, 255, 0), -1)
            #cv2.putText(frame, f"{keypoint_list[i]}", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, keypoint_color[i], 2)
        if len(keypoint) >= 2:
            # draw arrow line from tail to half between head and tail
            x0, y0 ,_= keypoint[0]
            x1, y1 ,_= keypoint[1]
            x2, y2 ,_= keypoint[2]
            x3, y3 ,_= keypoint[3]
            x4, y4 ,_= keypoint[4]
            x5, y5 ,_= keypoint[5]
            x6, y6 ,_= keypoint[6]
            x7, y7 ,_= keypoint[7]
            x8, y8 ,_= keypoint[8]
            x9, y9 ,_= keypoint[9]


            cv2.line(frame, (int(x0), int(y0)), (int(x1), int(y1)), (255, 0, 255), 5)
            cv2.line(frame, (int(x1), int(y1)), (int(x2), int(y2)), (255, 0, 255), 5)
            cv2.line(frame, (int(x2), int(y2)), (int(x3), int(y3)), (255, 0, 255), 5)
            cv2.line(frame, (int(x3), int(y3)), (int(x4), int(y4)), (255, 0, 255), 5)
            cv2.line(frame, (int(x4), int(y4)), (int(x5), int(y5)), (255, 0, 255), 5)
            cv2.line(frame, (int(x5), int(y5)), (int(x6), int(y6)), (255, 0, 255), 5)
            cv2.line(frame, (int(x6), int(y6)), (int(x7), int(y7)), (255, 0, 255), 5)
            cv2.line(frame, (int(x7), int(y7)), (int(x8), int(y8)), (255, 0, 255), 5)
            cv2.line(frame, (int(x8), int(y8)), (int(x9), int(y9)), (255, 0, 255), 5)


            #center_x, center_y = (x1 + x2) / 2, (y1 + y2) / 2
           # cv2.arrowedLine(frame, (int(x2), int(y2)), (int(center_x), int(center_y)), (255, 0, 255), 4,
            #                line_type=cv2.LINE_AA, tipLength=0.1)

    # save image
    cv2.imwrite("result.jpg", frame)
    # print("save result.jpg")
    return pose_point

if __name__ == '__main__':
    img = './img.png'
    res = pose_ocr(img)
    print(res)


效果如下,输出的是关键点坐标

在这里插入图片描述
在这里插入图片描述
后面就是代入到验证码的识别验证接口,具体参数加密这里就不叙述,主要就是调wasm即可。

接下来讲的是如何实现这个曲线的轨迹,众所周知京东的轨迹是一向比较恶心的。

我用的方法是贝塞尔曲线的方式,通过对输入的坐标,实现一个轨迹的拟合效果。

在这里插入图片描述
经过一系列的参数调整,终于得到一个成功率相对可以的(60-80%)轨迹生成函数,弄的时候发现在转折点时,停留时间需长一点!

在这里插入图片描述
轨迹代码已上传星球,感兴趣的可以加一下哦!vx私聊我有优惠~

同时已建群,在外流浪的老铁私信我进群了(星球付费群),每天都会讨论各种技术问题(ali、tx、dx)等各种热门验证码~

wx:scorpio_a_j

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

使用apache和htaccess对目录访问设置密码保护配置教程

对目录设置密码保护配置说明 我们有时候访问某些网站的时候,要求输入用户名和密码才能访问。这是为了保护隐私,只让经过许可的人访问。 在本教程中主要介绍两种方法,一种是通过apache httpd.conf配置文件对管理后台目录设置密码保护&#xff…

ESP32引脚入门指南(四):从理论到实践(PWM)

引言 ESP32 作为物联网领域的明星微控制器,除了强大的Wi-Fi和蓝牙功能,还内置了丰富的外设资源,其中就包括高级的PWM(脉冲宽度调制)功能。本文将深入探讨ESP32的PWM引脚,解析其工作原理,并通过…

分布式与一致性协议之Quorum NWR算法

Quorum NWR算法 概述 不知道你在工作中有没有遇到过这样的事情:你开发实现了一套AP型分布式系统,实现了最终一致性,且业务接入后运行正常,一切看起来都那么美好。 可是突然有同事说,我们要拉这几个业务的数据做实时分析&#xf…

进口原装二手 Keysight86142B 是德86142A 高性能光谱分析仪

进口原装二手 Keysight86142B 是德86142A 高性能光谱分析仪 内置测试应用程序 • 10 pm 波长精度 • 快速双扫法 • 覆盖 S、C 和 L 波段 Keysight 86142B是一款台式光谱分析仪(OSA),最适于对功率和波长精度、动态范围和低偏振敏感性都要…

asp.net论坛指南系统

说明文档 运行前附加数据库.mdf(或sql生成数据库) 主要技术: 基于asp.net架构和sql server数据库 登陆可查看 浏览记录 TA的发布 TA的回复 TA的收藏 TA的点赞 管理员登陆可以查看举报管理 编辑管理 认证审核 帖子置顶申请审核 运行环境…

【数据处理系列】深入理解递归特征消除法(RFE):基于Python的应用

目录 一、递归特征消除法介绍 二、方法介绍 三、导入数据并选择模型 (一)导入数据 (二) 递归特征消除需要选择模型吗 四、RFE方法进行递归特征消除法 五、RFECV方法进行递归特征消除法(建议使用这种方法) 即交叉验证递归特征消除法 (一)参数介绍 (二)python使用RFECV…

我们真的需要5G吗?再读《5G将是一个彻底的失败通信技术》

目录 投入与产出不成正比 《5G将是一个彻底的失败通信技术》 无线通信技术体制 无线通信技术演进 5G需求 移动通信与WiFi 5G之局 未来之路 参考 投入与产出不成正比 2018年开始大规模装备5G设备,因此2018年被称为5G元年。一般5G基站的寿命为8年左右&#…

GeoServer 任意文件上传漏洞分析研究 CVE-2023-51444

目录 前言 漏洞信息 代码审计 漏洞复现 前言 时隔半月,我又再一次地审起了这个漏洞。第一次看到这个漏洞信息时,尝试复现了一下,结果却很不近人意。从官方公布的漏洞信息来看细节还是太少,poc不是一次就能利用成功的。也是当时…

工器具管理(基于若依)

文章目录 前言一、工器具管理项目总览 二、入库功能1. 前端1.1 界面展示1.2 具体操作实现1.3 js文件 2. 后端2.1 工器具信息回显2.2 工器具入库 三、领用功能1. 前端1.1 界面展示1.2 具体实现操作1.3 js文件 2. 后端2.1 工器具信息回显2.2 工器具领用 遇到的问题1. 同一页面展示…

2024最新版守约者二级域名分发系统源码,提供全面的二级域名管理服务

主要功能 二级域名管理:我们的系统提供全面的二级域名管理服务,让您轻松管理和配置二级域名。 下 载 地 址 : runruncode.com/php/19756.html 域名分发:利用我们先进的域名分发技术,您可以自动化地分配和管理域名&…

【教程向】从零开始创建浏览器插件(二)深入理解 Chrome 扩展的 manifest.json 配置文件

第二步:深入理解 Chrome 扩展的 manifest.json 配置文件 上一次我们已经着手完成了一个自己的浏览器插件,链接在这里:我是链接 在本篇博客中,我们将更详细地探讨 Chrome 扩展中的 manifest.json 文件。这个文件是每个浏览器扩展…

keep健身小程序源码搭建/部署/上线/运营/售后/更新

基于FastAdminThinkPHPUniApp(目前仅支持微信小程序和公众号)开发的健身相关行业微信小程序,程序适用于健身房、瑜伽馆、游泳馆、篮球馆等健身培训场所。平台拥有课程售卖、课程预约、多门店管理、私教预约、教练端、会员卡办理、在线商城、分…

超分辨率专题 | 3 种方法、4 个教程、10 个数据集,一文 Get 核心知识点

2010 年 12 月,清华大学电子工程系教授苏光大接到一通不寻常的电话,内蒙古自治区准格尔刑警队的警员拿着一张模糊不清的犯罪嫌疑人人脸图像,向苏光大寻求帮助。 「这张图像是由路边的监控摄像头拍摄的,像素非常低,肉眼…

一文搞懂什么是外贸企业邮箱?

一文搞懂什么是外贸企业邮箱?外贸企业邮箱,也就是外贸行业使用的企业邮箱系统,一般需要具备海外抵达率高、安全稳定等特点,通过外贸企业邮箱,企业可以和国内国外的客户或者同事进行业务的沟通交流。 一、什么是外贸企…

接口自动化框架篇:使用python连接数据库 - PySQL介绍!

PySQL介绍:使用Python连接数据库的接口自动化框架 在接口自动化测试中,经常需要使用数据库来操作测试数据,验证接口返回的数据是否正确。Python是一种功能强大的编程语言,可以轻松地连接数据库,并进行各种数据库操作。…

林更新博士之路星途璀璨再启航

林更新:博士之路,星途璀璨再启航在这个充满机遇与挑战的时代,有一位演员以其出色的演技和不懈的努力,赢得了无数观众的喜爱。他,就是林更新。今日,一条消息如重磅炸弹般在娱乐圈炸开,让无数粉丝…

将AI融入项目开发工作中去吧

目录 1.提高编写开发日报的效率 2.提高编写代码注释的效率 3.提高代码重构的效率 4.编写测试用例及测试报告 5. 协助进行代码走查与工作量分析 在AI元年后,作为一名程序员,相信各位友友已经深切地感受到了它带来的变革。作为一个从小白到资深码农的…

【c++线程】condition_variable的简单使用

尝试用两个线程交替打印1-100的数字&#xff0c;要求一个线程打印奇数&#xff0c;另一个线程打印偶数&#xff0c;并且打印数字从小到大依次递增。 #include <iostream> using namespace std; #include <thread> #include <mutex> #include <condition_…

海外邮件群发工具的使用方法?有哪些限制?

海外邮件群发工具怎么选择&#xff1f;使用邮件群发工具的优势&#xff1f; 海外邮件群发工具成为了企业开展海外推广、联系客户、推广产品和服务的重要工具。但如何有效地使用这一工具&#xff0c;成为了众多营销人员关注的问题。接下来&#xff0c;AokSend将详细探讨海外邮件…

文件批量重命名技巧:文本内容即文件名,打造个性化文件命名新体验

在日常工作和学习中&#xff0c;我们经常需要处理大量的文件&#xff0c;而给这些文件命名则成为了一个既繁琐又重要的任务。传统的文件命名方式&#xff0c;如使用数字、字母或简单的描述性词汇&#xff0c;往往难以体现出文件的实际内容和特点。那么&#xff0c;有没有一种方…