如果是想训练一个手写体识别的模型,用一些前人收集好的手写文字集就好了,比如中科院的这些数据集。但是如果我们只是想要训练一个专门用于识别印刷汉字的模型,那么我们就需要各种印刷字体的训练集,那怎么获取呢?借助强大的图像库,自己生成就行了!

先捋一捋思路,生成文字集需要什么步骤:

  1. 确定你要生成多少字体,生成一个记录着汉字与label的对应表。
  2. 确定和收集需要用到的字体文件。
  3. 生成字体图像,存储在规定的目录下。
  4. 适当的数据增强。

第三步的生成字体图像最为重要,如果仅仅是生成很正规的文字,那么用这个正规文字集去训练模型,第一图像数目有点少,第二模型泛化能力比较差,所以我们需要对字体图像做大量的图像处理工作,以增大我们的印刷体文字数据集。

我总结了一下,我们可以做的一些图像增强工作有这些:

  1. 文字扭曲
  2. 背景噪声(椒盐)
  3. 文字位置(设置文字的中心点)
  4. 笔画粘连(膨胀来模拟)
  5. 笔画断裂(腐蚀来模拟)
  6. 文字倾斜(文字旋转)
  7. 多种字体

做完以上增强后,我们得到的数据集已经非常庞大了。


一、生成汉字与label的对应表

这里的汉字、label映射表的生成我使用了pickel模块,借助它生成一个id:汉字的映射文件存储下来。
这里举个小例子说明怎么生成这个“汉字:id” 映射表。

首先在一个txt文件里写入你想要的汉字,如果对汉字对应的ID没有要求的话,我们不妨使用该汉字的排位作为其ID,比如“一二三四五”中,五的ID就是00005。如此类推,把汉字读入内存,建立一个字典,把这个关系记录下来,再使用pickle.dump存入文件保存。

简单说就是给汉字一个id作为label,我们最终模型的输出是对应的id值。

二、收集字体文件
字体文件上网收集就好了,但是值得注意的是,不是每一种字体都支持汉字,所以我们需要筛选出真正适合汉字生成的字体文件才可以。我一共使用了十三种汉字字体作为我们接下来汉字数据集用到的字体,具体如下图:
当然,如果需要进一步扩大数据集来增强训练得到的模型的泛化能力,可以花更多的时间去收集各类汉字字体,那么模型在面对各种字体时也能从容应对,给出准确的预测。

收集字体的原因是为了提升模型的性能,我们在生成图片是会生成不同字体的图片文字,这样训练得到的模型能识别多种字体。

三、文字图像生成

首先是定义好输入参数,其中包括输出目录、字体目录、测试集大小、图像尺寸、图像旋转幅度等等。

def args_parse():#解析输入参数parser = argparse.ArgumentParser(description=description, formatter_class=RawTextHelpFormatter)parser.add_argument('--out_dir', dest='out_dir',default=None, required=True,help='write a caffe dir')parser.add_argument('--font_dir', dest='font_dir',default=None, required=True,help='font dir to to produce images')parser.add_argument('--test_ratio', dest='test_ratio',default=0.2, required=False,help='test dataset size')parser.add_argument('--width', dest='width',default=None, required=True,help='width')parser.add_argument('--height', dest='height',default=None, required=True,help='height')parser.add_argument('--no_crop', dest='no_crop',default=True, required=False,help='', action='store_true')parser.add_argument('--margin', dest='margin',default=0, required=False,help='', )parser.add_argument('--rotate', dest='rotate',default=0, required=False,help='max rotate degree 0-45')parser.add_argument('--rotate_step', dest='rotate_step',default=0, required=False,help='rotate step for the rotate angle')parser.add_argument('--need_aug', dest='need_aug',default=False, required=False,help='need data augmentation', action='store_true')   args = vars(parser.parse_args()) return args

接下来需要将我们第一步得到的对应表读入内存,因为这个表示ID到汉字的映射,我们在做一下转换,改成汉字到ID的映射,用于后面的字体生成。

#将汉字的label读入,得到(ID:汉字)的映射表label_dict
label_dict = get_label_dict()char_list=[]  # 汉字列表
value_list=[] # label列表
for (value,chars) in label_dict.items():print (value,chars)char_list.append(chars)value_list.append(value)# 合并成新的映射关系表:(汉字:ID)
lang_chars = dict(zip(char_list,value_list))
font_check = FontCheck(lang_chars)

我们对旋转的角度存储到列表中,旋转角度的范围是[-rotate,rotate].

if rotate < 0:roate = - rotateif rotate > 0 and rotate <= 45:all_rotate_angles = []for i in range(0, rotate+1, rotate_step):  all_rotate_angles.append(i)for i in range(-rotate, 0, rotate_step):all_rotate_angles.append(i)#print(all_rotate_angles)

现在说一下字体图像是怎么生成的,首先我们使用的工具是PIL。PIL里面有很好用的汉字生成函数,我们用这个函数再结合我们提供的字体文件,就可以生成我们想要的数字化的汉字了。我们先设定好我们生成的字体颜色为黑底白色,字体尺寸由输入参数来动态设定。

# 生成字体图像
class Font2Image(object):def __init__(self,width, height,need_crop, margin):self.width = widthself.height = heightself.need_crop = need_cropself.margin = margindef do(self, font_path, char, rotate=0):find_image_bbox = FindImageBBox()# 黑色背景img = Image.new("RGB", (self.width, self.height), "black")draw = ImageDraw.Draw(img)font = ImageFont.truetype(font_path, int(self.width * 0.7),)# 白色字体draw.text((0, 0), char, (255, 255, 255),font=font)if rotate != 0:img = img.rotate(rotate)data = list(img.getdata())sum_val = 0for i_data in data:sum_val += sum(i_data)if sum_val > 2:np_img = np.asarray(data, dtype='uint8')np_img = np_img[:, 0]np_img = np_img.reshape((self.height, self.width))cropped_box = find_image_bbox.do(np_img)left, upper, right, lower = cropped_boxnp_img = np_img[upper: lower + 1, left: right + 1]if not self.need_crop:preprocess_resize_keep_ratio_fill_bg = \PreprocessResizeKeepRatioFillBG(self.width, self.height,fill_bg=False,margin=self.margin)np_img = preprocess_resize_keep_ratio_fill_bg.do(np_img)# cv2.imwrite(path_img, np_img)return np_imgelse:print("img doesn't exist.")

我们写两个循环,外层循环是汉字列表,内层循环是字体列表,对于每个汉字会得到一个image_list列表,里面存储着这个汉字的所有图像。

for (char, value) in lang_chars.items():  # 外层循环是字image_list = []print (char,value)#char_dir = os.path.join(images_dir, "%0.5d" % value)for j, verified_font_path in enumerate(verified_font_paths):    # 内层循环是字体   if rotate == 0:image = font2image.do(verified_font_path, char)image_list.append(image)else:for k in all_rotate_angles: image = font2image.do(verified_font_path, char, rotate=k)image_list.append(image)

我们将image_list中图像按照比例分为训练集和测试集存储。

        test_num = len(image_list) * test_ratiorandom.shuffle(image_list)  # 图像列表打乱count = 0for i in range(len(image_list)):img = image_list[i]#print(img.shape)if count < test_num :char_dir = os.path.join(test_images_dir, "%0.5d" % value)else:char_dir = os.path.join(train_images_dir, "%0.5d" % value)if not os.path.isdir(char_dir):os.makedirs(char_dir)path_image = os.path.join(char_dir,"%d.png" % count)cv2.imwrite(path_image,img)count += 1

写好代码后,我们执行如下指令,开始生成印刷体文字汉字集。

python gen_printed_char.py --out_dir ./dataset --font_dir ./chinese_fonts --width 30 --height 30 --margin 4 --rotate 30 --rotate_step 1

解析一下上述指令的附属参数:

  1. –out_dir 表示生成的汉字图像的存储目录
  2. –font_dir 表示放置汉字字体文件的路径
  3. –width --height 表示生成图像的高度和宽度
  4. –margin 表示字体与边缘的间隔
  5. –rotate 表示字体旋转的范围,[-rotate,rotate]
  6. –rotate_step 表示每次旋转的间隔

生成这么一个3755个汉字的数据集的所需的时间还是很久的,估计接近一个小时。其实这个生成过程可以用多线程、多进程并行加速,但是考虑到这种文字数据集只需生成一次就好,所以就没做这方面的优化了。数据集生成完我们可以发现,在dataset文件夹下得到train和test两个文件夹,train和test文件夹下都有3755个子文件夹,分别存储着生成的3755个汉字对应的图像,每个子文件的名字就是该汉字对应的id。随便选择一个train文件夹下的一个子文件夹打开,可以看到所获得的汉字图像,一共634个。

四、额外的图像增强

第三步生成的汉字图像是最基本的数据集,它所做的图像处理仅有旋转这么一项,如果我们想在数据增强上再做多点东西,想必我们最终训练出来的OCR模型的性能会更加优秀。我们使用opencv来完成我们定制的汉字图像增强任务。

因为生成的图像比较小,仅仅是30*30,如果对这么小的图像加噪声或者形态学处理,得到的字体图像会很糟糕,所以我们在做数据增强时,把图片尺寸适当增加,比如设置为100×100,再进行相应的数据增强,效果会更好。

噪点增加

def add_noise(cls,img):for i in range(20): #添加点噪声temp_x = np.random.randint(0,img.shape[0])temp_y = np.random.randint(0,img.shape[1])img[temp_x][temp_y] = 255return img

适当腐蚀

def add_erode(cls,img):kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))    img = cv2.erode(img,kernel) return img

适当膨胀

def add_dilate(cls,img):kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))    img = cv2.dilate(img,kernel) return img

然后做随机扰动

def do(self,img_list=[]):aug_list= copy.deepcopy(img_list)for i in range(len(img_list)):im = img_list[i]if self.noise and random.random()<0.5:im = self.add_noise(im)if self.dilate and random.random()<0.25:im = self.add_dilate(im)if self.erode and random.random()<0.25:im = self.add_erode(im)    aug_list.append(im)return aug_list

输入指令

python gen_printed_char.py --out_dir ./dataset2 --font_dir ./chinese_fonts --width 100 --height 100 --margin 10 --rotate 30 --rotate_step 1 --need_aug

使用这种生成的图像如下图所示,第一数据集扩大了两倍,第二图像的丰富性进一步提高,效果还是明显的。当然,如果要获得最好的效果,还需要调一下里面的参数,这里就不再详细说明了。

OCR技术(大批量生成文字训练集)相关推荐

  1. 【OCR技术系列之三】大批量生成文字训练集

    放假了,终于可以继续可以静下心写一写OCR方面的东西.上次谈到文字的切割,今天打算总结一下我们怎么得到用于训练的文字数据集.如果是想训练一个手写体识别的模型,用一些前人收集好的手写文字集就好了,比如中 ...

  2. 【OCR三】大批量生成文字训练集(转)

    放假了,终于可以继续可以静下心写一写OCR方面的东西.上次谈到文字的切割,今天打算总结一下我们怎么得到用于训练的文字数据集.如果是想训练一个手写体识别的模型,用一些前人收集好的手写文字集就好了,比如中 ...

  3. 文字识别(四)--大批量生成文字训练集

    转自:https://www.cnblogs.com/skyfsm/p/8436820.html 上次谈到文字的切割,今天打算总结一下我们怎么得到用于训练的文字数据集.如果是想训练一个手写体识别的模型 ...

  4. 【OCR技术】大批量生成文字训练集

    向AI转型的程序员都关注了这个号

  5. OCR技术3-大批量生成文字训练集

    如果是想训练一个手写体识别的模型,用一些前人收集好的手写文字集就好了,比如中科院的这些数据集.但是如果我们只是想要训练一个专门用于识别印刷汉字的模型,那么我们就需要各种印刷字体的训练集,那怎么获取呢? ...

  6. 【OCR技术】大批量构造中文文字训练集

    向AI转型的程序员都关注了这个号??? 大数据挖掘DT数据分析  公众号: datadw 本文全部代码 github 地址 在公众号 datadw 里 回复 训练集  即可获取. 放假了,终于可以继续 ...

  7. python屏幕文字识别_python中使用OCR 技术进行《文字识别》

    # 导入组件 from uiautomatorimport deviceas d import pytesseract from PILimport Image import os import ti ...

  8. 【OCR技术系列之八】端到端不定长文本识别CRNN代码实现

    CRNN是OCR领域非常经典且被广泛使用的识别算法,其理论基础可以参考我上一篇文章,本文将着重讲解CRNN代码实现过程以及识别效果. 数据处理 利用图像处理技术我们手工大批量生成文字图像,一共360万 ...

  9. yolov3的训练(五)darknet的VOC测试集和训练集以及训练前准备

    VOC测试集和训练集     ################################## 同学们,这个系列的文件不要直接就跟着我操作了,因为这个是踩坑的记录,不是教程,我只是将整个流程记录下 ...

最新文章

  1. 无人值守u盘安装linux,从U盘无人值守安装linux操作系统(纯实践笔记)
  2. 分支定界法上下界_分支定界(Branch-and-Cut)方法的逻辑
  3. {在头值中找到无效的字符。} 发email的时候 遇到这个问题 老师解决
  4. 十四、List,Set,Collection,Collections
  5. linux文件的查看指令-cat-more-less
  6. ORM(手写简单ORM)
  7. 简易修复工具_汽车划痕的简单修复法,你get了吗?
  8. 运用EXCEL来解线性规划问题
  9. 复盘:windows ubuntu 双系统引导恢复、分区表恢复
  10. DB2 windows下9.5安装教程
  11. 访问控制(相关概述)
  12. ExtCertPathValidatorException: Could not validate certificate: null
  13. 物理学中的衔尾蛇(Ouroboros)
  14. 大学排行榜 : qs全球中国区仅大陆大学排行榜
  15. 中国志愿者服务器注册,中国志愿者服务网注册平台登录入口:http://www.chinavolunteer.cn/...
  16. 互联网行业薪资现状,月薪2万属于低收入? 6千外派包吃住
  17. 百度知道推出企业问答平台
  18. macos挂载磁盘映像_如何在Windows 7、8和10中挂载ISO映像
  19. [Paper Note] Densely Residual Laplacian Super-Resolution
  20. linux无线wps连接wifi,通过Wi-Fi保护的设置(WPS)设置无线连接在RV系列路由器

热门文章

  1. uni-app 微信小程序 引入iconfont
  2. 如何处理接口幂等性问题(重复提交)
  3. 论坛发贴与跟贴的技巧
  4. 华为 BGP协议基础配置与总结
  5. 凭算法突围,一战赚了 1090 亿,“恐怖” 的张一鸣!
  6. C语言实现计算数字能否被3个数整除
  7. BADI 和BAPI 的区别
  8. 2016 上半年 VR 报告:潜在用户4.5亿
  9. 服务器怎样创建多台虚拟主机,服务器是如何实现多台虚拟主机
  10. DBA所需要具备技能