1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > python生成文字点选验证码→训练yolo目标检测模型→识别文字点选验证码

python生成文字点选验证码→训练yolo目标检测模型→识别文字点选验证码

时间:2021-02-15 09:43:18

相关推荐

python生成文字点选验证码→训练yolo目标检测模型→识别文字点选验证码

python生成文字点选验证码→训练yolo目标检测模型→识别文字点选验证码

目录

python生成文字点选验证码→训练yolo目标检测模型→识别文字点选验证码前言一、生成文字点选验证码二、YOLOv3三、YOLOv5四、识别效果五、参考链接写在最后

前言

就在去年的这个时候,我写了python生成验证码→处理验证码→建立CNN模型训练→测试模型准确率→识别验证码这篇文章,开启了我的CNN学习之旅接着过了半年,我又写了python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率这篇文章,又开启了我的GAN学习之旅那么,接下来,即将开启我的YOLO学习之旅

一、生成文字点选验证码

作为十几年杰迷的我,那必须得弄点范特西的数据集,于是乎,我想到了,用周杰伦的歌曲名称+专辑封面来生成我的文字点选验证码图片,效果如下:

具体实现逻辑如下:

从专辑图片中随机选取一张作为背景,并将其大小改为520x520从歌曲中随机选取1~5首歌曲的歌名遍历选取到的几首歌曲的歌名从40~50的字号中随机选取一个字号从-90°~90°中随机选取文字旋转的角度从所有颜色中随机选取一种字体颜色以及在背景图片中随机选取一个坐标点xmin,ymin最后将处理后的文字图片放到背景图片中,以及生成每首歌的归一化后label坐标x,y,w,h

代码如下:

from tqdm import tqdmfrom PIL import Image, ImageDraw, ImageFont, ImageOpsimport shutil,osimport numpy as npclass CreateData:def __init__(self,create_num):self.jay_img_paths=['JAY/' + i for i in os.listdir('JAY/')] # 背景图片路径self.font_path='../simhei.ttf' # 字体路径self.img_save_path='images/' # 生成训练集图片的路径self.label_save_path='labels/' # 生成图片对应label的路径self.test_path='test/' # 生成测试集图片的路径# 100首周杰伦歌曲名称self.songs=['可爱女人', '星晴', '黑色幽默', '龙卷风', '屋顶', '爱在西元前', '简单爱', '开不了口', '上海一九四三', '双截棍', '安静', '蜗牛', '你比从前快乐', '世界末日', '半岛铁盒', '暗号', '分裂', '爷爷泡的茶','回到过去', '最后的战役', '晴天', '三年二班', '东风破', '你听得到', '她的睫毛', '轨迹', '断了的弦', '七里香', '借口', '搁浅', '园游会', '夜曲', '发如雪', '黑色毛衣', '枫', '浪漫手机', '麦芽糖', '珊瑚海', '一路向北', '听妈妈的话', '千里之外', '退后', '心雨', '白色风车', '千山万水', '不能说的秘密', '牛仔很忙', '彩虹', '青花瓷', '阳光宅男','蒲公英的约定', '我不配', '甜甜的', '最长的电影', '周大侠', '给我一首歌的时间', '花海', '魔术先生', '说好的幸福呢', '時光機','乔克叔叔', '稻香', '说了再见', '好久不见', '愛的飛行日記', '超人不会飞', 'Mine Mine', '公主病', '你好吗', '疗伤烧肉粽', '水手怕水', '世界未末日', '超跑女神', '明明就', '爱你没差', '夢想啟動', '大笨钟', '傻笑', '手语', '乌克丽丽', '哪裡都是你','算什么男人', '怎么了', '我要夏天', '手写的从前', '听爸爸的话','美人魚', '听见下雨的声音', '说走就走', '一点点', '前世情人', '不该', '告白气球', '愛情廢柴', '等你下课', '不爱我就拉倒', '说好不哭', '我是如此相信', 'Mojito', '瓦解']self.song2label={song:i for i,song in enumerate(self.songs)}self.label2song={i:song for i,song in enumerate(self.songs)}self.create_num=create_numself.image_w=520self.image_h=520self.max_iou=0.5 # 每首歌名的boxes的iou不能超过0.5def create_folder(self):while True:try:for path in [self.img_save_path,self.label_save_path,self.test_path]:shutil.rmtree(path,ignore_errors=True)os.makedirs(path,exist_ok=True)breakexcept:passdef bbox_iou(self,box2):'''两两计算iou'''for box1 in self.tmp_boxes:inter_x1=max([box1[0],box2[0]])inter_y1=max([box1[1],box2[1]])inter_x2=min([box1[2],box2[2]])inter_y2=min([box1[3],box2[3]])inter_area=(inter_x2-inter_x1+1) * (inter_y2-inter_y1+1)box1_area=(box1[2]-box1[0]+1) * (box1[3]-box1[1]+1)box2_area=(box2[2]-box2[0]+1) * (box2[3]-box2[1]+1)iou=inter_area / (box1_area + box2_area - inter_area + 1e-16)if iou > self.max_iou:# 只要有一个与之的iou大于阈值则重新来过return iouelse:return 0def draw_text(self,image,image_draw,song):iou=np.infnum=0while iou > self.max_iou:if num >= 100:# 为了避免陷进死循环,如果循环100次都没有找到合适的位置,则iou>0.5的阈值失效breakrandom_font_size=np.random.randint(40,50) # 随机字号random_rotate=np.random.randint(-90,90) # 随机旋转角度random_color=np.random.randint(0,256,3) # 随机字体颜色random_x,random_y=np.random.randint(1,520,2) # 随机xmin,yminfont = ImageFont.truetype(self.font_path, random_font_size)label=self.song2label[song]size_wh=font.getsize(song)img = Image.new('L', size_wh)img_draw = ImageDraw.Draw(img)img_draw.text((0, 0), song, font=font, fill=255)img_rotate = img.rotate(random_rotate, resample=2, expand=True)img_color = ImageOps.colorize(img_rotate, (0,0,0), random_color)w,h=img_color.sizexmin=random_xymin=random_y# 为了避免超出520x520,修正xmin,yminif random_x+w > self.image_w:xmin=self.image_w - w - 2if random_y+h > self.image_h:ymin=self.image_h - h - 2xmax=xmin+wymax=ymin+hboxes=(xmin,ymin,xmax,ymax)iou=self.bbox_iou(boxes)num+=1image.paste(img_color, box=(xmin,ymin), mask=img_rotate)# image_draw.rectangle(boxes,outline=tuple(random_color))return image,boxes,labeldef process(self,boxes):'''将xmin,ymin,xmax,ymax转为x,y,w,h以及归一化坐标,生成label'''x1,y1,x2,y2=boxesx=((x1+x2)/2)/self.image_wy=((y1+y2)/2)/self.image_hw=(x2-x1)/self.image_wh=(y2-y1)/self.image_hreturn [x,y,w,h]def main(self):'''主函数'''self.create_folder() # 重置所需文件夹for i in tqdm(range(self.create_num+3)):random_song_num=np.random.randint(1,5) # 随机1~4首random_jay_img_path=np.random.choice(self.jay_img_paths) # 随机背景image=Image.open(random_jay_img_path).convert('RGB').resize((self.image_w,self.image_h))image_draw=ImageDraw.Draw(image)boxes_list=[]label_list=[]self.tmp_boxes=[] # 用于计算两两boxes的ioufor j in range(random_song_num):song=np.random.choice(self.songs)image,boxes,label=self.draw_text(image,image_draw,song)self.tmp_boxes.append(boxes)boxes_list.append(self.process(boxes))label_list.append(label)# save image and labelimage_filename=self.img_save_path+f'image{i}.png' if i < self.create_num else self.test_path+f'test{i}.png'label_filename=self.label_save_path+f'image{i}.txt' if i < self.create_num else self.test_path+f'test{i}.txt'image.save(image_filename)with open(label_filename,'w') as f:for k in range(len(label_list)):# label x y w hf.write(f'{label_list[k]} {boxes_list[k][0]} {boxes_list[k][1]} {boxes_list[k][2]} {boxes_list[k][3]}\n')if __name__ == '__main__':creator=CreateData(5000)creator.main()

二、YOLOv3

代码过多,就不放上来了,直接看结果。

参考了崔庆才崔大写的滑块验证码识别/Python3WebSpider/DeepLearningImageCaptcha2,只是修改了dataset相关代码,配置文件信息,以及训练的代码等等。

dataset的修改:因为我复现崔大的代码时,发现其label文件的格式是:class xmin ymin w h

所以就自己重新改写了一下,修改成:class x y w h配置文件即yolov3.cfg的修改 三个yolo层的classes参数改为数据集的类别个数,即100三个yolo层的上一个convolutional层的filters参数改为3*(类别个数+5),即315 训练策略 epoch:100batch size:16img size:416数据集划分:80%即4000张用于训练,20%即1000张用于验证gradient accumulations:5(即被5整除的批次,优化器暂停更新梯度信息)优化器:Adam GPU内存占用:15G训练耗时:4.5小时

训练结果的如下:

---- best_mAP@0.5: 0.29220820871021674

---- best_epoch: 98

小结

知识巩固:

TP: 将正类预测为正类的数量FN: 将正类预测为负类的数量FP: 将负类预测为正类的数量TN: 将负类预测为负类的数量从验证集的指标看,recall高,precision低,说明FN比FP小。也就是说,模型将一首歌名识别成多首,且多数情况下其中就有一首是预测正确的训练了100个epoch,然而mAP@0.5的分数也才0.3左右,提升缓慢看趋势,随着训练epoch的增加,各项指标还是会再提升的

三、YOLOv5

代码过多,就不放上来了,直接看结果。

参考了作者的代码/ultralytics/yolov5,去掉了我认为是冗余的代码,主要是简化了train.py、val.py和detect.py的代码。

因为yolov5有提供多个模型:yolov5n、yolov5s、yolov5l、yolov5m、yolov5x,于是我就都尝试了一遍。

均采用以下训练策略:

epoch:100learning rate:0.001batch size:16image size:416augment:Falserect:Falsequad:Falsemulti scale:True数据集划分:80%即4000张用于训练,20%即1000张用于验证优化器:Adamlr scheduler:LambdaLR配置文件:hyp.scratch.yaml混合精度训练不使用平滑标签评价指标:fitness= 0.1 *mAP@0.5+ 0.9 *mAP@0.5:0.95

1. yolov5n

GPU内存占用:2G

训练耗时:2.2小时

模型大小:7.39MB

---- best_fitness=0.6837750339549021

---- best_epoch=87

训练结果的如下:

2. yolov5s

GPU内存占用:4.25G

训练耗时:2.5小时

模型大小:27.9MB

---- best_fitness=0.878297457833696

---- best_epoch=99

训练结果的如下:

3. yolov5l

GPU内存占用:12.8G

训练耗时:3.75小时

模型大小:178MB

---- best_fitness=0.9015696258245549

---- best_epoch=93

训练结果的如下:

4. yolov5m

GPU内存占用:8.5G

训练耗时:3小时

模型大小:81.4MB

---- best_fitness=0.9197881788592055

---- best_epoch=98

训练结果的如下:

5. yolov5x

GPU内存占用:15.5G

训练耗时:6.3小时

模型大小:332MB

---- best_fitness=0.921645471556

---- best_epoch=100

训练结果的如下:

小结

yolov5n模型最小,GPU内存占用最小,且训练时长也最短,可惜性能是最差的,但也比yolov3要好,这一点毋容置疑如果要考虑GPU内存、模型大小、训练时长和性能,那么yolov5s是最好的选择,性价比最高yolov5l、yolov5m和yolov5x的性能均达到了90%以上,综合考虑的话,我会选择yolov5m。

四、识别效果

最后,yolov3和yolov5分别对开头的那张图片进行识别,来看看实际的效果吧。(过滤条件均设置为0.5)

因为边幅有限,就比较一张吧,可以看得出来:

yolov3只识别出了等你下课稻香,且置信度也不是很高yolov5n将稻香识别成傻笑了,以及说好不哭的置信度也不是很高剩下的均成功识别出来了四首歌,且置信度都是非常高的。差别可能也不是很明显,可以多用几张图片进行测试,在我测试多几张后,yolov5x是最好的,毕竟分数最高。

五、参考链接

周杰伦官方专辑封面高清

崔庆才崔大写的滑块验证码识别

yolov5作者代码

以上即为本篇全部内容,代码我整理了一遍,且运行后无bug,若需要源代码的可以关注我的微信公众号《Python王者之路》,回复关键词:1226,即可获取。

写在最后

在看了崔大写的滑块验证码识别的推文后,我当时就已经想好了要出这一篇文章了

我先是复现了崔大的代码,当然,这其中遇到了很多的坑,毕竟第一次接触目标检测,之前只是会一点图片分类

可谓说历经千辛万苦,终于成功复现了,当时就想着要不直接写一篇:我的复现过程遇到的问题的文章算了

可是呢,看看yolov3的识别效果,如此难以接受

于是,又开始研究最新的yolov5,因为此时对yolo有了初步的认识,这时复现yolov5还算比较轻松

然后,花了一周左右的时间,测试出了最好的训练策略即本篇采用的策略

最后,又花了一周的时间,按我的训练策略来训练yolov5的5个模型,以及写这篇文章

虽然成功运用yolo模型来做目标检测了,但对于yolo具体细节还有待研究呀~

最后,提前祝大家元旦快乐吧!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。