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

2024-03-03 18:48

本文主要是介绍OCR技术3-大批量生成文字训练集,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

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

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

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

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

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

现在开始一步一步生成我们的3755个汉字的印刷体文字数据集。

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

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

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

二、收集字体文件

字体文件上网收集就好了,但是值得注意的是,不是每一种字体都支持汉字,所以我们需要筛选出真正适合汉字生成的字体文件才可以。我一共使用了十三种汉字字体作为我们接下来汉字数据集用到的字体,具体如下图:

当然,如果需要进一步扩大数据集来增强训练得到的模型的泛化能力,可以花更多的时间去收集各类汉字字体,那么模型在面对各种字体时也能从容应对,给出准确的预测。

三、文字图像生成

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

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个。

dataset下自动生成测试集和训练集

测试集和训练集下都有3755个子文件夹,用于存储每个汉字的图像。

生成出来的汉字图像

 

 

额外的图像增强

第三步生成的汉字图像是最基本的数据集,它所做的图像处理仅有旋转这么一项,如果我们想在数据增强上再做多点东西,想必我们最终训练出来的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

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

 至此,我们所需的印刷体汉字数据集已经成功生成完毕,下一步要做的就是利用这些数据集设计一个卷积神经网络做文字识别了!

原文地址:http://www.cnblogs.com/skyfsm/p/8436820.html

 

欢迎扫码关注我的微信公众号

 

这篇关于OCR技术3-大批量生成文字训练集的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/770552

相关文章

乐鑫 Matter 技术体验日|快速落地 Matter 产品,引领智能家居生态新发展

随着 Matter 协议的推广和普及,智能家居行业正迎来新的发展机遇,众多厂商纷纷投身于 Matter 产品的研发与验证。然而,开发者普遍面临技术门槛高、认证流程繁琐、生产管理复杂等诸多挑战。  乐鑫信息科技 (688018.SH) 凭借深厚的研发实力与行业洞察力,推出了全面的 Matter 解决方案,包含基于乐鑫 SoC 的 Matter 硬件平台、基于开源 ESP-Matter SDK 的一

一份LLM资源清单围观技术大佬的日常;手把手教你在美国搭建「百万卡」AI数据中心;为啥大模型做不好简单的数学计算? | ShowMeAI日报

👀日报&周刊合集 | 🎡ShowMeAI官网 | 🧡 点赞关注评论拜托啦! 1. 为啥大模型做不好简单的数学计算?从大模型高考数学成绩不及格说起 司南评测体系 OpenCompass 选取 7 个大模型 (6 个开源模型+ GPT-4o),组织参与了 2024 年高考「新课标I卷」的语文、数学、英语考试,然后由经验丰富的判卷老师评判得分。 结果如上图所

持久层 技术选型如何决策?JPA,Hibernate,ibatis(mybatis)

转自:http://t.51jdy.cn/thread-259-1-1.html 持久层 是一个项目 后台 最重要的部分。他直接 决定了 数据读写的性能,业务编写的复杂度,数据结构(对象结构)等问题。 因此 架构师在考虑 使用那个持久层框架的时候 要考虑清楚。 选择的 标准: 1,项目的场景。 2,团队的技能掌握情况。 3,开发周期(开发效率)。 传统的 业务系统,通常业

亮相WOT全球技术创新大会,揭秘火山引擎边缘容器技术在泛CDN场景的应用与实践

2024年6月21日-22日,51CTO“WOT全球技术创新大会2024”在北京举办。火山引擎边缘计算架构师李志明受邀参与,以“边缘容器技术在泛CDN场景的应用和实践”为主题,与多位行业资深专家,共同探讨泛CDN行业技术架构以及云原生与边缘计算的发展和展望。 火山引擎边缘计算架构师李志明表示:为更好地解决传统泛CDN类业务运行中的问题,火山引擎边缘容器团队参考行业做法,结合实践经验,打造火山

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st

YOLO v3 训练速度慢的问题

一天一夜出了两个模型,仅仅迭代了200次   原因:编译之前没有将Makefile 文件里的GPU设置为1,编译的是CPU版本,必须训练慢   解决方案: make clean  vim Makefile make   再次训练 速度快了,5分钟迭代了500次

百度OCR识别结构结构化处理视频

https://edu.csdn.net/course/detail/10506

前端 CSS 经典:文字描边

前言:文字描边有两种实现方式 1. text-shadow 设置 8 个方向的文字阴影,缺点是只有八个方向,文字转角处可能有锯齿状。不支持文字透明,设置 color: transparent,文字会成描边颜色。 <!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta http-equiv="X-UA-Comp

将一维机械振动信号构造为训练集和测试集(Python)

从如下链接中下载轴承数据集。 https://www.sciencedirect.com/science/article/pii/S2352340918314124 import numpy as npimport scipy.io as sioimport matplotlib.pyplot as pltimport statistics as statsimport pandas

FastAdmin/bootstrapTable 表格中生成的按钮设置成文字

公司有个系统后台框架用的是FastAdmin,后台表格的操作栏按钮只有图标,想要设置成文字。 查资料后发现其实很简单,主需要新增“text”属性即可,如下 buttons: [{name: 'acceptcompany',title: '复核企业',text:'复核企业',classname: 'btn btn-xs btn-primary btn-dialog',icon: 'fa fa-pe