OCR标注贵,所以我们需要「自己造数据」,即数据合成。数据合成的原料是「字体文件、没有字的背景图、文本语料」,过程是「用某种字体,将某些文字渲染在背景图上」。合成的目标是「合成数据和目标数据看起来要尽量接近,比较像」。
在「场景文本」方面,SynText是一个传说中做得还不错的文本合成工具。那么就来试一试,合成一点自己的数据。
先说结论:生成出来的东西不能用。建议放弃。
材料准备
下载代码
不多说,直接git clone就完事儿了
main/master分支说的是针对Python2的,其实我们可以使用 2to3
这个Python自带的工具,将版本「升级」为Python3
下载原材料-Part1
按照SynthText的说法,他们会根据深度图,在图片上「较为平坦」的地方渲染上文字。所以就需要下载一下他们处理好的图片。——自己做也是可以的啦,只是说还需要安装Matlab这个大魔头,比较麻烦。所以还是用他们处理好的比较省事儿。8000张背景图也算够用。
按照说明,需要下载 imnames.cp、bg_img.tar.gz、depth.h5和seg.h5这四个东西。
下载原材料-Part2
在gen.py里面,我们还发现了这个文件: http://www.robots.ox.ac.uk/~ankush/renderer_data.tar.gz 也需要下载下来,并解压缩。我们称解压缩后的路径为renderer_data
加入自己的东西
上面说了,我们希望绕过的是「matlab的部分」。所以对照着最开始的「背景图、字体、语料」的清单——我们还需要准备字体和语料
准备字体
首先,筛出来一些字体。可以参考这篇博客。
为啥要筛字体?如果你做过相关工作你就会知道,字体文件真的是千奇百怪,有些字体真的不适合用来做渲染,例如那些稀奇古怪的Icon字体(例如A是大洋洲,B是北美洲,C是南美洲;再或者,《塞尔达传说:荒野之息》里面的西卡文字,其实也是字体)、大小写不分的字体、过于花哨的字体(例如,A头上开朵花、著名的「小人举牌」字体)。
然后,将它们的路径保存成一个txt文件,替换renderer_data/fonts里面的字体列表文件。
准备语料
这个就比较随意了……如果嫌麻烦的话,可以直接替换 renderer_data/newsgroup/newsgroup.txt 。不想替换的话,在代码里面改也成,下文会说到。
改代码
适配Python3
Python2都死了好几年了……就别在用了,直接上Python3吧。官方说master分支里面的代码是只适配Python2的,我们自己动手让它适配Python3,也不难。
首先,Python有2to3这个工具,可以查一下用法。我这里直接在每个文件夹里面使用 2to3 -w *.py 简单暴力。
然后,这份代码里面多处用到了pickle这个序列化的东西(就是那些 .cp 文件)。由于Python2和Python3的兼容性原因,我们需要把open()函数的”r”改成”rb”,”w”改成”wb”,同时在pickle.load()里面添加一下参数,改为 pickle.load(f, encoding=”bytes”)。
适配下载的东西
我也是看了好久才看懂 use_preproc_bg.py 是干啥的……简而言之,使用 use_preproc_bg.py 这个文件里面的东西,替换掉 gen.py 里 main 函数里面相应的东西即可。同时还要注意,由于替换了东西, get_data 函数可以直接干掉,同时 wget 这个依赖就可以去掉了。
跑代码和Debug
好了,跑就是了。会出现几个Bug:
第一个是语料。如果你使用了自己的语料,但不是覆盖的 renderer_data/newsgroup/newsgroup.txt ,那么会报文件找不到。这个是一个硬编码的东西,改掉即可。
第二个是在synthgen.py 里面的 cv2.findContours 会报错。解决办法是去掉最前面的那个返回值接收。
第三个是colorize3_poisson.py里面一直会报 ValueError: zero-size array to reduction operation minimum which has no identity ,这个我没想通。
其他……反正在运行的过程中会不断报错,不影响的话忽略即可,只是生成的数据会少一些而已。——多跑几遍啦~
生成速度会比较慢,大概每秒1张。
转换数据格式
原来代码生成出来的是 h5 格式的「压缩包」,如果用在自己的项目里面的话需要拆解这个文件,转换成自己需要的格式。
本来要转换格式,顺带的做一下可视化吧,虽然自带也有可视化:
from pathlib import Path
import cv2
import h5py
import numpy as np
from tqdm import tqdm
db = h5py.File("SynthText.h5", 'r')
for ith, name in tqdm(enumerate(db["data"].keys())):
sample_name = f"{ith:06d}"
img_data = np.array(db["data"][name])
text = data.attrs["txt"].tolist()
bbox = data.attrs["wordBB"].astype(int).transpose(2, 1, 0)
img_data = cv2.polylines(img_data, bbox, True, (0, 0, 255), 1)
data_out.put_image(f"image/{sample_name}.jpg", cv2.cvtColor(img_data, cv2.COLOR_BGR2RGB))
print("Done")
遇到的坑
果然是学术代码……没有怎么考虑到易用性。比如硬编码了语料文件路径。
应该是字体考虑不周,所以生成出来的东西并不怎么能用。会有比较多的「一个位置放多个文本行,导致有些显示不全」,还会出现「有些文本行没有框,有些文本行框不对,有些框里面没有文本行」。所以,个人并不建议用它。
那些pickle文件一直报错。本来想重新在Python2下面读出来再生成一下,结果发现依旧报错。然后尝试了print出来,手动复制,再贴到代码里面,重新生成一下,然后发现这个方法可行。但是,有个文件里面存的是numpy.array,不能print出来再贴回去……于是找到了 encoding 这个参数。
发表回复