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

news/2024/5/21 5:01:55

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

目标网站: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, tailgroup_id = shape["group_id"]  # 0, 1, 2, ...points = shape["points"]  # x,y coordinatesshape_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"]# 如果匹配到了对应的keypointif 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:continuelabel_id = class_list.index(rectangle["label"])# x1,y1,x2,y2x1, y1, x2, y2 = rectangle["rect"]# center_x, center_y, width, heightcenter_x = (x1 + x2) / 2center_y = (y1 + y2) / 2width = abs(x1 - x2)height = abs(y1 - y2)# normalizecenter_x /= wcenter_y /= hwidth /= wheight /= 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, heightresult_list = [label_id, center_x, center_y, width, height]# 添加 p1_x, p1_y, p1_v, p2_x, p2_y, p2_vfor point in rectangle["keypoints_list"]:x, y = pointx, y = int(x), int(y)x /= wy /= 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_listimport 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 imgdef 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 outputsboxes = boxes.cpu().numpy()  # convert to numpy array# 遍历每个框for box in boxes.data:l, t, r, b = box[:4].astype(np.int32)  # left, top, right, bottomconf, id = box[4:]  # confidence, classid = 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)# 遍历keypointskeypoints = result.keypoints  # Keypoints object for pose outputskeypoints = keypoints.cpu().numpy()  # convert to numpy arraypose_point = []# draw keypoints, set first keypoint is red, second is bluefor 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 tailx0, 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 imagecv2.imwrite("result.jpg", frame)# print("save result.jpg")return pose_pointif __name__ == '__main__':img = './img.png'res = pose_ocr(img)print(res)

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

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

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

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

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

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

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

wx:scorpio_a_j

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


http://www.mrgr.cn/p/03828378

相关文章

django显示网页步骤

显示网页步骤 小白的django学习笔记 2024/5/6 8:30 文章目录 显示网页步骤创建输入框(文本、单选、多选)效果如何在django中显示网页写函数配置地址运行,要选择这个工程名的,使用socket复制ip,后面在加上名字,成功&…

linux安装python3.8

一、卸载损坏的yum并安装 本来想直接下载安装python3.8,结果过程中损坏了yum,导致yum无法使用。 参考了【故障】6、yum不可用_yum命令无法使用-CSDN博客 1、删除python #删除现有的python rpm -qa|grep python|sudo xargs rpm -ev --allmatches --nodeps #强制删除已安装程…

2024好用的网页客服系统推荐?

2024好用的网页客服系统推荐?Zoho SalesIQ是一款强大的实时聊天工具,专为网站和在线商店设计。它提供了一套全面的功能,帮助企业实时解决客户问题,提高转化率和客户满意度。 实时监控 Zoho SalesIQ能够实时监控网站的访问者活动&…

Spring添加注解读取和存储对象

5大注解 Controller 控制器 Service 服务 Repository 仓库 Componet 组件 Configuration 配置 五大类注解的使用 //他们都是放在同一个目录下,不同的类中 只不过这里粘贴到一起//控制器 Controller public class UserController {public void SayHello(){System.ou…

智启蒸汽时代:数字孪生锅炉的革新之旅

数字孪生,就是通过数字技术为物理世界中的物体创建一个数字化的“双胞胎”。对于蒸汽工厂锅炉来说,数字孪生系统能够实时模拟锅炉的运行状态,预测可能出现的问题,并通过数据分析和智能决策为工人提供精准的操作建议。在飞速发展的工业4.0时代,数字孪生技术已经深入到我们生…

python数据分析——数据预处理

数据预处理 前言一、查看数据数据表的基本信息查看info()示例 查看数据表的大小shape()示例 数据格式的查看type()dtype()dtypes()示例一示例二 查看具体的数据分布describe()示例 二…

35岁自学编程有必要吗

在当今这个快速发展的数字化时代,学习编程已经不再局限于特定年龄层。对于35岁的人来说,自学编程不仅有必要,而且可能开启职业生涯的全新篇章。首先,编程技能是通往高科技行业的一把钥匙,能够为个人职业发展拓宽道路&a…

服务器(Linux系统)清除缓存

echo 1> /proc/sys/vm/drop_caches -- 清空系统缓存; cat /proc/29127/status -- 查看指定进程的状态信息;

Oracle Linux环境执行脚本

executeOracleSql.sh #!bin/bash# system:oracle的用户名;xxx:oracle的密码 # 后面追加要执行的sql脚本路径即可 sqlplus -s system/oracle@127.0.0.1:1521/xxx <<EOF @/home/mjtabu/basedb_init.sql exit; EOFecho "Please double check!!!";I have a dream…

js实现复制功能

/*** 复制* param {*} val 要复制的内容* returns*/ export const copyToClipboard async val > {try {// 使用现代 API 尝试复制if (navigator.clipboard && navigator.permissions) {await navigator.clipboard.writeText(val)return // 如果成功&#xff0c;直接…

kafka的名词解释

1.Replica(副本):在 Kafka 中,每个分区都有多个副本,用于提供数据的冗余备份和高可用性。副本可以分为两种类型:领导者副本(leader replica)和追随者副本(follower replica)。 领导者副本:每个分区都有一个领导者副本,它负责处理与客户端的所有读写请求,是分区的主…

vue3打开页面后文本框自动获得焦点

字符串写法 <script setup> import { ref, onMounted } from vue import ./index.cssconst input ref(null)onMounted(() > {input.value.focus() }) </script><template><div class"m-home-wrap"><input ref"input" />…

FPGA+炬力ARM实现VR视频播放器方案,3D眼镜显示

3D眼镜显示&#xff1a; FPGA炬力ARM方案&#xff0c;单个视频源信号&#xff0c;同时驱动两个LCD屏显示&#xff0c;实现3D 沉浸式播放 客户应用&#xff1a;VR视频播放器 主要功能&#xff1a; 1.支持多种格式视频文件播放 2.支持2D/3D 效果实时切换播放 3.支持TF卡/U盘文…

亚信安慧AntDB:解锁数智化的新时代

亚信安慧AntDB的融合实时的特性使得它在数据库领域独树一帜。传统的数据库系统往往只能追求数据的准确性和一致性&#xff0c;但在实际的业务场景中&#xff0c;这些特性并不能满足企业的需求。AntDB的出现打破了传统束缚&#xff0c;为企业带来了全新的数据处理方式&#xff0…

计算机基础-网络

一、网络设备 a.网卡(无线、有线) 物理层:提供物理地址,也叫MAC地址 b.网线(双绞线)、光缆 c.交换机、集线器 arp链路层:提供局域网内计算机与路由器之间建立端口映射,mac与IP的链路绑定 d.路由器 网络层:为局域网内计算机分配IP地址、防火墙、上网限制、网速控制登录 …

压力测试

压力测试压力测试 本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/18184743

预约咨询小程序源码搭建/部署/上线/运营/售后/更新

包含在线咨询、视频咨询、电话咨询、面询多种咨询方式&#xff0c;适用于心理、法律、宠物等预约咨询问诊场景 分类预览&#xff1a;小程序提供清晰的分类选项&#xff0c;使用户能够迅速找到所需的咨询服务类型&#xff0c;如法律咨询、心理咨询、医疗咨询等。预约时间选择&a…

实验四

一、实验题目 :代码审查 二、实验目的 1、熟悉编码风格,利用开发环境所提供的平台工具对代码进行自动格式审查; 2、根据代码规范制定代码走查表,并按所制定的审查规范互审代码。 三、实验内容 1、IDEA环境和PyCharm环境二选一; IDEA环境 (1)预先准备在IDEA环境下实现对输…

【redis学习】Redis-IO多路复用

为什么要有IO多路复用 大家印象中的redis都是单线程的,没有加锁的操作,因此才会是redis这么快的原因其中之一。先暂且不说redis究竟是不是单线程,即便是单线程的,作为服务提供方,面对成百上千的客户端连接请求,读写操作,单线程是怎么做到高效的处理这些请求?单线程处理…

h5使用js拉起微信支付

近期,业务需求对接了微信支付,做个总结。web网页想要拉起微信支付,有两种方法: H5下单支付 , JSAPI支付 。首先纯前端做不了微信支付,必须配合后端才能通过微信的下单请求。接下来说说这两种方法的区别。 H5微信下单支付 这种支付方式是用户在浏览器端打开网页,通过下单等…