用YOLO3进行人民币编码的定位与切割

  • 背景介绍
  • 数据的预处理
  • 训练模型
  • 编码识别,坐标点的处理和保存
  • 编码切割

背景介绍

来自于TinyMind的一个计算机视觉的比赛,已经过去有一段时间了,不过官方开放了练习模式,用来学习还算是一个不错的选择,比赛地址https://www.tinymind.cn/competitions/47?rron=banner
主要的目的就是这个:

一共给了不到四万张图片,一共九种面值,基本上长这样:

本片文章的目的就是把人民币的编码给切割下来,至于为啥切割下来,个人认为是为了减少干扰,毕竟到时候要识别数字或者字母,人民币上还是有很多其他数字作为干扰的,而且大佬们都这么做了,跟着做总没啥错。本篇文章主要分三部分,数据的预处理,定位和切割。
yolo3没有用过的可以看我写的这篇文章https://blog.csdn.net/qq_39226755/article/details/100073309

数据的预处理

具体的处理方法还是上边那个链接,这里只写主要部分
我将九种面值的编码都归为一个类别,一共标注了1800张图片,每个200张(一共1000张其实就够用),当然是标的越多效果越好
标完之后就用脚本转化成txt的格式,这个工具官方文件里都有,自己看着稍微改一改,下边是我改的代码:

import xml.etree.ElementTree as ETxml_dir = 'H:\data\RMB\class_train_data\\xml_data'def convert_annotation(xml_dir, image_id, list_file): #对每个XML文件的信息进行提取in_file = open('{0}/{1}'.format(xml_dir, image_id))tree=ET.parse(in_file)root = tree.getroot()path = root.find('path').textlist_file.write(path)error_bool = Falsefor obj in root.iter('object'):xmlbox = obj.find('bndbox')b = (int(xmlbox.find('xmin').text), int(xmlbox.find('ymin').text), int(xmlbox.find('xmax').text), int(xmlbox.find('ymax').text))if len(b)!=4:error_bool = Truelist_file.write(" " + ",".join([str(a) for a in b]) + ',' + str(0))return error_boolimport os
lists = os.listdir(xml_dir)
list_file = open('RMB_train.txt', 'w')
for xml in lists:error_bool = convert_annotation(xml_dir,xml,list_file)list_file.write('\n')
list_file.close()if error_bool == False:#检查数据是否由五个数构成 xmin,ymin,xmax,ymax,classprint('转换成功!')
else:print('出错啦!')

最后类别的部分我根本就没有提取,直接就设置成了0,加了一些检查结果正不正常的代码,因为刚开始用的时候出错了,经常格式不对,奇怪的是我加完这个代码后一次也没出过错

之后我们在文件里就生成了一个训练集,就可以开始用了

这个训练集每一行代表一个图片,分为两部分,用空格隔开,第一部分是图片地址,第二部分是x_min,y_min,x_max,y_max这四个坐标和一个类别序号,这里是0

训练模型

直接用train.py训练就好了,我这里选择的是直接用darknet的文件进行的迁移学习,冻结前185层,锚的话没有改,选择的九个,我没有训练到损失最低,因为我的小电脑也承受不住这么大的压力,毕竟是为了学习,训练的模型能用就行,我分两次进行了训练,当时觉得没啥问题,现在想一想有点不对,因为训练两次就分了两次训练集和验证集,每次分的不一样就容易出现过拟合,应该一次训练两种学习率,好在结果显示没啥问题,效果如下:


训练到这种样子我觉得就差不多了,接下来才是重点。

编码识别,坐标点的处理和保存

我们接着拿这个模型去识别我们的RMB,结果发现并不是很理想,有时会识别一半,有时会出现两个框,每个框识别一半,真正能识别的比较完美的也就占一半,出现这样的结果肯定是不行的,所以我对输出的坐标进行了一些处理。
形容一下:



基本上就是这三种情况,只需要解决这三种就没的问题了,
前两种情况可以归为一类,就是目标没有括全,这样到时候是很麻烦的,我看了看样本,发现样本与样本之间的尺寸还是差很多的,所以我先设定了一个参数llr,就是指图片长度和方框长度之间的比,这样的话图片变大,方框也会变大,然后我又设了一个lwr,是图片的长宽比,通俗的理解就是第一个参数决定方框大小,第二个参数决定方框尺寸。也就是让这个方框按照一定的规则扩大,这样就不用担心没法覆盖编码了。
第二类就是多个框,这个好解决,我把两个框融合成一个框,选取最靠外的坐标值,比如这个top就选红色的top,left就选蓝色的left。
处理后的图片如下:


方法应该是有很多,这只是我能想到的最简单的。
代码用的qqwwee的yolo3 地址https://github.com/qqwweee/keras-yolo3

下边这段代码的原版在yolo.py中,自己改的部分我都写了注释

top_left,bottom_right = (1000,1000),(0,0)#先初始化两个值for i, c in reversed(list(enumerate(out_classes))):predicted_class = self.class_names[c]box = out_boxes[i]score = out_scores[i]label = '{} {:.2f}'.format(predicted_class, score)top, left, bottom, right = boxtop = max(0, np.floor(top + 0.5).astype('int32'))left = max(0, np.floor(left + 0.5).astype('int32'))bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))right = min(image.size[0], np.floor(right + 0.5).astype('int32'))print(label, (left, top), (right, bottom))##新添代码,for循环到这一行之前都没有改if top < top_left[1]:          #top和left都要选择最小的top_left = (top_left[0], top)if left < top_left[0]:top_left = (left,top_left[1])if bottom > bottom_right[1]:        #bottom和right都要选择最大的bottom_right = (bottom_right[0],bottom)if right > bottom_right[0]:bottom_right = (right,bottom_right[1])top,left = top_left[1],top_left[0]right,bottom = bottom_right[0],bottom_right[1]#得到top,left,right,bottom四个数long = bottom_right[0] - top_left[0]        #获得预测框的长和宽wide = bottom_right[1] - top_left[1]llr = 3.5 # 图片长与预测框长之间的比值if image.size[0]/long > llr:    #如果大于这个值,说明预测框太小了,对预选框进行扩大right += (image.size[0]/llr - long)/2left -= (image.size[0]/llr - long)/2long = right - leftlw = long/widelwr2 = 3.8 #预选框长宽比if lw >= lwr2:  #调整预选框的尺寸top -= (long/lwr2 - wide)/2bottom += (long/lwr2 - wide)/2else:left -= (wide*lwr2 - long)/2right += (wide*lwr2 - long)/2draw = ImageDraw.Draw(image)           #把处理后的框画出来# My kingdom for a good redistributable image drawing library.for i in range(thickness):draw.rectangle([left + i, top + i, right - i, bottom - i],outline=(255,0,0))del drawend = timer()print(end - start)#返回四个坐标和一个处理后的图片,方便测试return image,(int('{:.0f}'.format(left)),int('{:.0f}'.format(top))),(int(('{:.0f}'.format(right))),int('{:.0f}'.format(bottom)))

同时我把多余的代码都删除了,放着也可以,反正返回的值就是这些,只不过图片会比较乱

同时yolo_video.py也需要改一下,原来的代码就真的只是测试用的,在这个脚本里我创建了两个文件,一个用来储存处理好的图片和坐标,另一个存放出错的图片目录(包括打开出错和找不到编码)
添加了一个方法,修改了主程序(作者并没有写主函数),具体看注释

FLAGS = parser.parse_args()
###这行之前的代码没有改
log_dir = 'F:\DeepLearn\RMB_code/last_logs/log1/'        #日志(结果)保存目录
image_dir = 'H:\data\RMB/train_data/train_data/'     #图片根目录
if os.path.exists(log_dir) == False: #创建根目录,不然文件创建不出来os.makedirs(log_dir)
with open('{}correct_logs.txt'.format(log_dir),'w') as correct_logs:with open('{}error_logs.txt'.format(log_dir),'w') as error_logs :       #这里创建两个文件,一个用来存放处理好的图片,一个存放处理失败的图片image_lists = os.listdir(image_dir)    #收集图片地址if FLAGS.image:      #这里表示图片模式,属于原代码"""Image detection mode, disregard any remaining command line arguments"""print("Image detection mode")if "input" in FLAGS:print(" Ignoring remaining command line arguments: " + FLAGS.input + "," + FLAGS.output)detect_img2(YOLO(**vars(FLAGS)),image_lists,correct_logs,error_logs)  #后三个参数分别是图片地址集和两个用来存信息的文件#detect_img(YOLO(**vars(FLAGS)))#YOLO,图片,结果elif "input" in FLAGS:detect_video(YOLO(**vars(FLAGS)), FLAGS.input, FLAGS.output)else:print("Must specify at least video_input_path.  See usage with --help.")#新添方法,用来一次性处理多个图片def detect_img2(yolo,image_list,correct_logs,error_logs):all_num = len(image_list)error_num = 0for i in range(len(image_list)):  #对每个图片进行识别img = image_list[i]print('img:{0},进度:{1:.2f}%'.format(img,(i/all_num)*100)) #进度try:#打开图片image = Image.open(image_dir+img)except: #打开失败,就写到error_logs文件里print('Open Error! Try again!')error_logs.write("{}\n".format(image_dir + img)) error_num += 1continueelse:r_image,top_left,bottom_right = yolo.detect_image(image)if r_image == False:  #如果False说明返回的是0,没有识别到编码,写入error_logs中error_logs.write("{}\n".format(image_dir + img))error_num += 1continue# long = bottom_right[0]-top_left[0]         #用来测试用,展示各种参数# wide = bottom_right[1]-top_left[1]# print('点1:{0},点2:{1},长:{2},宽:{3},长宽比:{4}'.format(top_left,bottom_right,long,wide,long/wide))# print('图片长{0},宽{1},画框与圆框尺寸比例{2}'.format(image.size[0],image.size[1],image.size[0]/long))#处理好信息的存入correct_logs中correct_logs.write('{0},{1},{2},{3},{4}\n'.format(image_dir+img,top_left[0],top_left[1],bottom_right[0],bottom_right[1]))#图片地址,left,top,right,bottom#r_image.show()print('错误率:{}%,错误个数:{}'.format(error_num*100/all_num,error_num)) #打印错误的个数,和比例,让自己心里有个B数yolo.close_session()

处理完这些我们就可以开心的运行了,这个时候可以干点其他事,但是不能玩大型游戏,因为GPU被占满了,两个小时候再回来就会发现弄完了。

这次效果还不错,错误的比例非常低,基本上可以忽略的那种,63个图片可以实现手动切割或者识别,两个文件的内容如下:


接下来我们就可以准备切割了

编码切割

切割时一个非常简单的事情,只需要对像素进行复制,然后保存下来就行了。

import cv2target_dir ='./cut_images/' #要保存的目录
text_dir = 'F:\DeepLearn\RMB_code\last_logs\log1\correct_logs.txt' #我们储存的correct_logs.txt文件with open(text_dir,'r') as text_file:texts = text_file.readlines() #读取信息all_num = len(texts)for i in range(len(texts)):lists = texts[i].split(',')img = cv2.imread(lists[0])#对像素点进行操作 [Ymin:Ymax,Xmin:Xmax]image = img[int(lists[2]):int(lists[4]),int(lists[1]):int(lists[3])]#y1:y2,x1:x2#保存图片cv2.imwrite('{0}{1}'.format(target_dir,lists[0][-12:]),image)# cv2.imshow('sss',image)   #测试# cv2.waitKey()#B数print('存入{0},进度:{1:.2f}%'.format(lists[0][-12:],float(i*100/all_num)))

这样结果就出来了:

然后就可以用这个数据集进行文字识别了,离最终目标就差一步了,是不是很开心!!

用YOLO3进行人民币编码的定位与切割相关推荐

  1. Java多线程之死锁编码及定位分析

    Java多线程之死锁编码及定位分析 目录 死锁是什么 代码实现 死锁解决办法 1. 死锁是什么 死锁是指两个或两个以上的进程在执行过程中因争夺资而造成的一种互相等待的现象,若无外力干涉那它们都将无法推 ...

  2. 馆1:图书编码与定位

    1 格子编号 2 书籍定位码 书侧边,上为格子号,下为格子内编号. 不干胶贴纸 46mm*11.1mm 3 书籍条形码 8位 编码格式:128码: 大小:50x20mm 4 书单 得到 5 格子与书架 ...

  3. 死锁编码及定位分析(故障排查)

    什么是死锁? 在Java中使用多线程,就会有可能导致死锁问题.死锁会让程序一直卡住,不再程序往下执行.我们只能通过中止并重启的方式来让程序重新执行. 造成死锁的原因: 当前线程拥有其他线程需要的资源 ...

  4. Opencv ORC——文字定位与切割

    字符切割步骤 要做文字识别,第一步要考虑的就是怎么将每一个字符从图片中切割下来,然后才可以送入我们设计好的模型进行字符识别.现在就以下面这张图片为例,说一说最一般的字符切割的步骤是哪些. 我们实际上要 ...

  5. 文字识别(三)--文字定位与切割

    转自:https://www.cnblogs.com/skyfsm/p/8029668.html 要做文字识别,第一步要考虑的就是怎么将每一个字符从图片中切割下来,然后才可以送入我们设计好的模型进行字 ...

  6. 【数据竞赛】CV赛题总结:人民币面值与编码识别

    CV 人民币面值与编码 在2019年6月份参加了TinyMind人民币面值及编码识别比赛,最终获得了面试识别并列第二.编码识别初赛第三/复赛第五的成绩,在文本我将分享这次比赛的历程和我的学习收获,比赛 ...

  7. X264编码流程详解(转)

    http://blog.csdn.net/xingyu19871124/article/details/7671634 对H.264编码标准一直停留在理解原理的基础上,对于一个实际投入使用的编码器是如 ...

  8. 脚印:关于错误编码的管理的一些思考

    需求 错误编码定义的混乱带来了后期的管理和维护的问题: 1)应用内编码重复问题: 2)关联应用间编码重复问题: 3)干系人无法通过错误编码快速定位出现问题的应用: 4)各应用的错误描述没有统一的管理站 ...

  9. 调用模块里的action_初级测试人员进阶必备Python编码模块,看过的都说好

    出品 | 51Testing软件测试网 前言 ActionHelpers类在python安装路径\Lib\site-packages\appium\webdriver\extensions 下的  a ...

最新文章

  1. 北京智源大会6月23日精彩预告!(附问题征集)
  2. Verilog初级教程(23)Verilog仿真中的显示任务
  3. 挑战AI种番茄,第二届国际智慧温室种植挑战赛启动!
  4. 常见时间复杂度及对应关系
  5. LOJ #6051. 「雅礼集训 2017 Day11」PATH
  6. 模块 datetime
  7. Azure上部署FTP服务
  8. Atitit 获取剪贴板内容
  9. python安装osgeo库_python第三方库安装
  10. 软件测试面试必问的10个问题
  11. 国家开放大学2021春2045金融企业会计题目
  12. 百度地图 雷达/地理编码 功能使用
  13. 基于商品属性的相似度模型
  14. 如何在安卓手机上编辑Excel表格?
  15. 好人?坏人?做真实的人
  16. 基于springboot的汽车配件管理系统
  17. 8. 监督学习的统计理论
  18. 【好奇心驱动力】ESP32-CAM人体感应拍照并推送到微信
  19. 【JMeter】JMeter简介
  20. 华为大数据云issues

热门文章

  1. 破解58同城字体反爬
  2. WebShell --中国菜刀,管站之刀
  3. ZSC 1306: 沼跃鱼早已看穿了一切 题解
  4. 如何针对数据中心进行安全疏散和消防应急管理
  5. 2007年互联网发展趋势预测:RSS将成为主流
  6. Django migrate 命令
  7. IntelliJ IDEA 下的svn配置及使用的非常详细的图文总结
  8. 如何组装深度学习的计算机
  9. 关于前端框架vue/react及UI框架的配合
  10. 腾讯云CentOS7 LAMP(linux的apache MariaDB php)yum方式部署