深度学习训练滑动验证码(Yolov5)

您所在的位置:网站首页 python训练验证码 深度学习训练滑动验证码(Yolov5)

深度学习训练滑动验证码(Yolov5)

2024-07-11 11:58| 来源: 网络整理| 查看: 265

注:本文只用于学习,如有问题请联系作者。

场景介绍

对于现在网络的大多数滑动验证码如果想用一个通用的方法还是需要用深度学习,用图像处理的方式对于单一类型还是比较好用的,多类型还是难以适用的。例如如下多种类型:

请添加图片描述 请添加图片描述 请添加图片描述 请添加图片描述 请添加图片描述 这里展示了5种类型不同的滑块,我们要做的就是准确的找到缺口的位置通过。 我这里使用的yolov5

项目开始 https://github.com/ultralytics/yolov5 这里是yolov5 github可以了解更多 https://docs.ultralytics.com/ 这是yolov5的官方文档

YOLO 是“You only look once”的首字母缩写词,是一种将图像划分为网格系统的对象检测算法。网格中的每个单元都负责检测自身内部的对象。

由于其速度和准确性,YOLO 是最著名的目标检测算法之一。

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

打开项目 在这里插入图片描述

安装后配置环境然后启动train.py出现如下代表yolo配置成功 需要有cuda环境(需要用gpu训练) ,torch,torchvision,numpy等环境(自行解决) 在这里插入图片描述

yolov5超参数

train.py文件的454行parse_opt里面有很多启动脚本超参数,接受一下常用的: 在这里插入图片描述

weights 选择预训练模型,默认ROOT / ‘yolov5m.pt’cfg 模型配置和网络结构的yaml文件路径data 数据集配置的yaml文件路径,包括数据集的路径,类名等关键信息hyp 超参数配置的yaml文件路径epochs 训练总轮次batch-size 每个轮次下图片训练的批次大小imgsz 图片默认尺寸resume 从给定的path/last.pt恢复训练,如果为空,则从最近保存的path/last.pt恢复训练,持续训练device 显卡选择single-cls 将所有数据按照一个类别进行训练(例如滑块只有一个缺口,则表示一种类型)optimizer 优化器选择name 训练完的保存的文件夹名称exist-ok 训练完文件夹不递增

如果有感兴趣的自行查询。

滑动验证码数据集

yolo有自己数据集的格式 我已经整理好了有4100张上述滑块类型 在这里插入图片描述 这里目录下分文图片和标签两个目录 在这里插入图片描述 图片和标签一样下面为一个test和train测试集和训练集 在这里插入图片描述 在这里插入图片描述 这里是yolo的数据集格式必须这个样子 在这里插入图片描述 我已经整理好了数据集并标注,如果你想自己训练自己的图片也可以也行标注但是格式必须是这个样子。 推荐一个标注的网站可以直接导出yolo格式

make-sense 是一个被YOLOv5官方推荐使用的图像标注工具 https://www.makesense.ai/

这个标注工具,具体使用https://blog.csdn.net/to_chariver/article/details/119619515看这个博主,很详细

配置数据集和超参数

在data下面创建一个Sliding.yaml的配置文件 在这里插入图片描述 这里配置完改了几个超参数如下: 在这里插入图片描述 我训练模型选择yolov5s,这是不同yolo模型的对比图。 在这里插入图片描述

训练开始并查看结果

配置好了就可以开始训练了, 在这里插入图片描述

可以看到已经有训练信息在跑了,等待训练完50轮我们就可以看结果啦。 这里解释一下信息中的参数都是什么:

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 召回率

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

详细解读请看 https://blog.csdn.net/sinat_37322535/article/details/117260081 这个博主

在这里插入图片描述 可以看到这里精度和召回率表现都很不错 训练结束后在目录下的runs/train/Sliding下生成一些训练结果的文件(这个目录可以自己设置)

在这里插入图片描述 看一下我们测试集的预测结果,val_batch_pred.jpg 在这里插入图片描述 Gap就是我们需要找到的地方,还有置信度 results.csv文件是训练具体的详细信息 在这里插入图片描述 最重要的是在weights目录下有两个pt模型, 在这里插入图片描述 最好的模型,和最后的模型,我们之后验证就可以用着模型进行验证

PT模型转onnx模型

项目中的export.py文件中的521行weights超参数将pt模型路径写入列入: 在这里插入图片描述 需要有onnx模块不然会报错,如果报异常 Onnx: No module named ‘onnx’ 手动安装onnx模块然后在重试即可

在这里插入图片描述 在这个目录下可以看到last.onnx模型,接下来就是模型的单独调度。

验证模型

在detect.py文件中配置可以对模型进行检测 211行配置超参数 在这里插入图片描述

这里一定要配置成刚刚训练好的,模型路径 然后将想要测试的图片放入data/images下面,然后运行detect.py文件即可。 在这里插入图片描述 这里看到我保存在了runs/detect/Sliding目录下 在这里插入图片描述 这里的图片文件名称和data/images的文件名称一样可以看到, 在这里插入图片描述 成功看到返回缺口位置和置信度,这里已经预测成功,说明我们的模型已经训练成功了。 我将所有图片全部组合起来看起来方便。 图片合成代码

import os import PIL.Image as Image def resize_by_width(infile, image_size): """按照宽度进行所需比例缩放""" im = Image.open(infile) (x, y) = im.size lv = round(x / image_size, 2) + 0.01 x_s = int(x // lv) y_s = int(y // lv) print("x_s", x_s, y_s) out = im.resize((x_s, y_s), Image.ANTIALIAS) return out def get_new_img_xy(infile, image_size): """返回一个图片的宽、高像素""" im = Image.open(infile) (x, y) = im.size lv = round(x / image_size, 2) + 0.01 x_s = x // lv y_s = y // lv # print("x_s", x_s, y_s) # out = im.resize((x_s, y_s), Image.ANTIALIAS) return x_s, y_s # 定义图像拼接函数 def image_compose(image_colnum, image_size, image_rownum, image_names, image_save_path, x_new, y_new): to_image = Image.new('RGB', (image_colnum * x_new, image_rownum * y_new)) # 创建一个新图 # 循环遍历,把每张图片按顺序粘贴到对应位置上 total_num = 0 for y in range(1, image_rownum + 1): for x in range(1, image_colnum + 1): from_image = resize_by_width(image_names[image_colnum * (y - 1) + x - 1], image_size) # from_image = Image.open(image_names[image_colnum * (y - 1) + x - 1]).resize((image_size,image_size ), Image.ANTIALIAS) to_image.paste(from_image, ((x - 1) * x_new, (y - 1) * y_new)) total_num += 1 if total_num == len(image_names): break return to_image.save(image_save_path) # 保存新图 def get_image_list_fullpath(dir_path): file_name_list = os.listdir(dir_path) image_fullpath_list = [] for file_name_one in file_name_list: file_one_path = os.path.join(dir_path, file_name_one) if os.path.isfile(file_one_path): image_fullpath_list.append(file_one_path) else: img_path_list = get_image_list_fullpath(file_one_path) image_fullpath_list.extend(img_path_list) return image_fullpath_list def merge_images(image_dir_path,image_size,image_colnum): # 获取图片集地址下的所有图片名称 image_fullpath_list = get_image_list_fullpath(image_dir_path) image_fullpath_list = [i for i in image_fullpath_list if "crops" not in i] print("image_fullpath_list", len(image_fullpath_list), image_fullpath_list,"========") image_save_path = r'{}.jpg'.format(image_dir_path) # 图片转换后的地址 # image_rownum = 4 # 图片间隔,也就是合并成一张图后,一共有几行 image_rownum_yu = len(image_fullpath_list) % image_colnum if image_rownum_yu == 0: image_rownum = len(image_fullpath_list) // image_colnum else: image_rownum = len(image_fullpath_list) // image_colnum + 1 x_list = [] y_list = [] for img_file in image_fullpath_list: img_x, img_y = get_new_img_xy(img_file, image_size) x_list.append(img_x) y_list.append(img_y) print("x_list", sorted(x_list)) print("y_list", sorted(y_list)) x_new = int(x_list[len(x_list) // 5 * 4]) y_new = int(x_list[len(y_list) // 5 * 4]) image_compose(image_colnum, image_size, image_rownum, image_fullpath_list, image_save_path, x_new, y_new) # 调用函数 # for img_file in image_fullpath_list: # resize_by_width(img_file,image_size) if __name__ == '__main__': image_dir_path = r'/home/yons/pytorch/wang/yolov5-master/runs/detect/Sliding' # 图片集地址 image_size = 128 # 每张小图片的大小 image_colnum = 10 # 合并成一张图后,一行有几个小图 merge_images(image_dir_path, image_size, image_colnum)

在这里插入图片描述 可以看到测试结果还是非常不错的这是我32张的表现。

单张图片进行测试

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

我这里主要介绍脱离yolo,单独脚本进行测试,并返回坐标和预测图片。 代码从yolo源码中debug抠出来的,将pt模型转为onnx模型,在调用此脚本

import os import sys import time from io import BytesIO import onnxruntime import torch import torchvision import numpy as np import cv2 # 图像处理 from PIL import Image def padded_resize(im, new_shape=(640, 640), stride=32): try: shape = im.shape[:2] r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # dw, dh = np.mod(dw, stride), np.mod(dh, stride) dw /= 2 dh /= 2 if shape[::-1] != new_unpad: # resize im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(114, 114, 114)) # add border # Convert im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB im = np.ascontiguousarray(im) im = torch.from_numpy(im) im = im.float() im /= 255 im = im[None] im = im.cpu().numpy() # torch to numpy return im except: print("123") def xywh2xyxy(x): # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y return y def box_iou(box1, box2): """ Return intersection-over-union (Jaccard index) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format. Arguments: box1 (Tensor[N, 4]) box2 (Tensor[M, 4]) Returns: iou (Tensor[N, M]): the NxM matrix containing the pairwise IoU values for every element in boxes1 and boxes2 """ def box_area(box): # box = 4xn return (box[2] - box[0]) * (box[3] - box[1]) area1 = box_area(box1.T) area2 = box_area(box2.T) # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, labels=(), max_det=300): """Runs Non-Maximum Suppression (NMS) on inference results Returns: list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ nc = prediction.shape[2] - 5 # number of classes xc = prediction[..., 4] > conf_thres # candidates # Checks assert 0


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3