1. 校验–判别用户上传图片是否为营业执照
这一部分目前有两个已实现的方案:
- 使用SIFT特征点检测方法,将用户上传图片与营业执照图片模板进行SIFT方法匹配,之后因为速度原因,将整个营业执照的模板改变为只有“营业执照”四个字的模板,速度从8s左右提升至1s以内。但是因为模板的改变,会存在偶尔识别错误的情况。另,我对这部分的SIFT方法不了解。
- 使用vgg16进行一个简单的分类。将用户上传图片使用vgg16模型进行分类,判别是否为营业执照图片。因为目前营业执照图片数据较少,所以采用迁移学习。下载vgg16预训练模型,改变全连接层且只训练全连接层。这部分的难点为:①数据集较小,采用迁移学习可以弥补。②负样本的不完全性也会导致模型分类失败。这样的情况在几次实验过程中已经出现。例如,第一次训练好的vgg模型,可以识别动物,风景,人物等为负类,但是身份证图片却也判别为营业执照。那么接下来就又需要将身份证之类的证件图片(身份证,驾照,护照等)加入到负样本中。第二次训练模型之后,在第一次的基础上,模型已经可以区分证件照片。但是此时发现,只要是有文字的图片,模型都判别为正样本!接下来开始第三次丰富负样本集,将含有文字信息的照片加入负样本并重新训练模型之后,就可以正确区分了。在这里,可以发现如果用户上传的非营业执照图片是模型没有见过的,它就有可能将其划分为正类,所以,后续可能还需要进一步的丰富负样本集合,但是由于正样本数量较少,所以也不能将负样本集合持续增大,否则正负样本不平衡问题就会出现,那么用户不管上传什么图片,模型都会判别为负类。所以,归根到底还是数据集较小的原因。
所以,目前的想法是同时使用两个方法,当这两个方法均投票负类时,才将该图片判别为负类,否则就开始检测步骤。
2. 文字区域检测—CTPN算法
2.1 CTPN算法原理
首先,放上原论文链接,有兴趣的小伙伴可以看一下原文。还有一个中英文对照版本的可以参考。
与faster RCNN不同的是,faster RCNN做的是物体检测,而CTPN方法做文本检测的其中一个难点就在于文本行的长度变化是非常剧烈的。因此如果是采用基于faster rcnn等通用物体检测框架的算法都会面临一个问题?怎么生成好的text proposal?这个问题实际上是比较难解决的。
CTPN文章作者转换思路,首先考虑文字目标的特殊性,一个很大的先验是,文字总是水平排列的。作者认为预测文本水平方向的位置比预测竖直方向上的位置要困难得多。所以检测的过程中 不妨引入一个类似数学上“微分”的思想,如下图所示,先检测一个个小的、固定宽度的文本段。在后处理部分再将这些小文本段连接起来,得到文本行。
具体的说,作者的基本想法就是去预测文本的竖直方向上的位置,水平方向的位置不预测。因此作者提出了一个vertical anchor的方法。与faster rcnn中的anchor类似,但是不同的是,vertical anchor的宽度都是固定好的了,论文中的大小是16个像素。而高度则从11像素到273像素变化,总共10个anchor。
整体流程:
- 首先,使用VGG16作为base net提取特征,得到conv5_3的特征作为feature map,大小是W×H×C。(这里说一下,feature map 的大小一般为batchWHC,但是LSTM的输入是batchmax_length*word_dim,这里怎么对应起来的呢?从图中可以看出,将feature map的H作为是batch,也就是一行是一个batch, 将W作为是max_length, 而C作为word_dim.)
- 然后在这个feature map上做滑窗,窗口大小是3×3。也就是每个窗口都能得到一个长度为3×3×C的特征向量。这个特征向量将用来预测和10个anchor之间的偏移距离,也就是说每一个窗口中心都会预测出10个text propsoal。
- 将上一步得到的特征输入到一个双向的LSTM中,得到长度为W×256的输出,然后接一个512的全连接层,准备输出。
- 输出层部分主要有三个输出:
- 2k个vertical coordinate,因为一个anchor用的是中心位置的高(y坐标)和矩形框的高度两个值表示的,所以一个用2k个输出(k=10,对应第二步中的10个anchor)。(注意这里输出的是相对anchor的偏移)。
- 2k个score,因为预测了k个text proposal,所以有2k个分数,text和non-text各有一个分数。
- k个side-refinement,这部分主要是用来精修文本行的两个端点的,表示的是每个proposal的水平平移量。
- 这是会得到密集预测的text proposal,所以会使用一个标准的非极大值抑制算法来滤除多余的box。
- 最后使用基于图的文本行构造算法,将得到的一个一个的文本段合并成文本行。
一些细节:
-
vertical anchor
① k个anchor的设置如下:宽度都是16像素,高度从11~273像素变化(每次乘以1.4)
② 预测的k个vertical coordinate的坐标如下:
回归的高度和bounding box的中心的y坐标如下,带*的表示是groundTruth,带a的表示是anchor
③ score阈值设置:0.7 (+NMS)
④ 与真值IoU大于0.7的anchor作为正样本,与真值IoU最大的那个anchor也定义为正样本,这个时候不考虑IoU大小有没有到0.7,这样做有助于检测出小文本。
⑤ 与真值IoU小于0.5的anchor定义为负样本。
⑥ 只保留score大于0.7的proposal -
BLSTM
① 文章使用了双向的LSTM,每个LSTM有128个隐层
② 加了RNN之后,整个检测将更加鲁棒 -
Side-refinement
① 文本线构造算法(多个细长的proposal合并成一条文本线)
主要思想:每两个相近的proposal组成一个pair,合并不同的pair直到无法再合并为止(没有公共元素)
判断两个proposal,Bi和Bj组成pair的条件:
Bj->Bi, 且Bi->Bj。(Bj->Bi表示Bj是Bi的最好邻居)
Bj->Bi 条件1:Bj是Bi的邻居中距离Bi最近的,且该距离小于50个像素
Bj->Bi 条件2:Bj和Bi的vertical overlap大于0.7
固定要regression的box的宽度和水平位置会导致predict的box的水平位置不准确,所以作者引入了side-refinement,用于水平位置的regression。where xside is the predicted x-coordinate of the nearest horizontal side (e.g., left or right side) to current anchor. x∗ side is the ground truth (GT) side coordinate in x-axis, which is pre-computed from the GT bounding box and anchor location. cax is the center of anchor in x-axis. wa is the width of anchor, which is fixed, wa = 16
-
训练
① 对于每一张训练图片,总共抽取128个样本,64正64负,如果正样本不够就用负样本补齐。这个和faster rcnn的做法是一样的。
② 训练图片都将短边放缩到600像素。 -
总结
这篇文章的方法最大亮点在于把RNN引入检测问题(以前一般做识别)。文本检测,先用CNN得到深度特征,然后用固定宽度的anchor来检测text proposal(文本线的一部分),并把同一行anchor对应的特征串成序列,输入到RNN中,最后用全连接层来分类或回归,并将正确的text proposal进行合并成文本线。这种把RNN和CNN无缝结合的方法提高了检测精度。 -
问题
① 没有很好地处理多方向的文本行
② 训练的时候由于有regression和LSTM,需要小心控制梯度爆炸。
2.2 直接使用CTPN预训练模型
CTPN论文的作者公开的代码是基于caffe框架的:代码链接;B站视频的讲解是基于pytorch的,他的代码放在百度云上(链接: https://pan.baidu.com/s/1wToAbOulqpLxFhtOV5wdhg 提取码: 6y24 (配套视频请添加微信digexiaozhushou))他的其他资料可以在github上查找;后来有大神基于tensorflow实现了CTPN算法(代码链接),基本上所有基于tensorflow的都是基于此代码进行的,本文也是基于此代码进行的。
如果想直接使用eragonruan写的CTPN模型进行文本区域定位,可以依照以下步骤进行:
- 从github下载代码,链接:https://github.com/eragonruan/text-detection-ctpn
- 环境配置:
备注:gcc与g++也要求在6.0以上,否则会报错。 - 编译。在项目文件中执行以下命令,最后将会在bbox文件夹中生成nms.so 和 bbox.so这两个文件.
cd utils/bbox
chmod +x make.sh
./make.sh
- 下载作者训练好的模型。作者给出了 googl drive 和 百度云两个链接,但是到目前为止(2020/08/13),百度云链接已经失效, googl drive还可以下载,链接:https://drive.google.com/file/d/1HcZuB_MHqsKhKEKpfF1pEU85CYy4OlWO/view。
- 将下载好的模型zip文件解压,放在项目一级目录下即可。如下图所示。
(解释一下为什么main,nets,utils每个包都有两个,因为python import自己写的其他模块时,需要该模块在包里面,而不是文件夹中。python中严格区分包和文件夹。包的定义就是包含__init__.py的文件夹。如果没有__init__.py,那么就是普通的文件夹。)
- 打开/main/demo.py文件,将下面代码中对应的文件位置修改好,就可以直接运行了。
tf.app.flags.DEFINE_string('test_data_path', 'data/demo/', '')
tf.app.flags.DEFINE_string('output_path', 'data/res/', '')
tf.app.flags.DEFINE_string('gpu', '0', '')
tf.app.flags.DEFINE_string('checkpoint_path', '../checkpoints_mlt/', '')
FLAGS = tf.app.flags.FLAGS
- 运行demo.py文件后,会在output_path中对每一个图片产生两个输出。如下图所示。
原图:
输出图片:
备注:CTPN对水平文字的检测效果不错,但是对于竖直和倾斜文字的检测效果不佳,这是由于程序中对于标签数据进行的水平切分(宽为16的矩形框),在利用rnn进行文本行合并时,一直是水平方向导致的。
输出文本:
其中每一行对应一个文本框,八个整数分别对应从左上角开始的(x,y)坐标,按顺时针旋转。最后一个小数数值是概率。
512,173,544,173,544,200,512,200,0.99868757
624,321,736,321,736,347,624,347,0.99857223
464,415,592,415,592,438,464,438,0.99849284
480,310,624,310,624,324,480,324,0.9982535
304,179,512,179,512,212,304,212,0.9981123
96,339,240,339,240,355,96,355,0.99799806
512,459,720,459,720,479,512,479,0.99753165
80,225,144,225,144,245,80,245,0.99751484
96,370,736,370,736,383,96,383,0.99750817
608,481,704,481,704,499,608,499,0.99740076
96,203,240,203,240,216,96,216,0.99715686
96,278,320,278,320,292,96,292,0.99708265
592,508,752,508,752,521,592,521,0.99705267
416,574,592,574,592,586,416,586,0.9969637
416,564,592,564,592,576,416,576,0.99678135
192,384,480,384,480,396,192,396,0.9967604
608,183,688,183,688,195,608,195,0.9967121
656,567,784,567,784,580,656,580,0.9966543
48,568,288,568,288,582,48,582,0.99655676
176,398,336,398,336,411,176,411,0.9965299
240,226,592,226,592,249,240,249,0.9964445
608,413,752,413,752,443,608,443,0.9963811
96,308,320,308,320,324,96,324,0.9963319
464,281,608,281,608,296,464,296,0.99630785
464,339,560,339,560,355,464,355,0.99630004
368,508,496,508,496,530,368,530,0.9962746
80,178,240,178,240,194,80,194,0.99618113
参考
- B站视频:迪哥有点愁,基于Pytorch框架进行ocr识别实战 https://www.bilibili.com/video/BV1F7411x7B9?p=1
- 知乎:晟沚,CTPN论文解读,https://zhuanlan.zhihu.com/p/31915483
- Github:eragonruan, text-detection-ctpn, https://github.com/eragonruan/text-detection-ctpn
- 博客园:python_worm, Python自定义包在linux服务器导入错误的解决办法 https://www.cnblogs.com/fanjp666888/p/9243411.html