English README.
欢迎扫码加入QQ交流群:
主要变更:
- 优化了对数字识别的准确度。
- 优化了模型结构,进一步降低了模型的大小,提升了预测速度;最小模型从原来的
6.8M
降为4.7M
。 - 使用了爱因互动 Ein+自己的CDN存储模型文件,下载速度超快。
- 提供了预测速度更快的
shorter (-s)
版预训练模型:densenet-lite-s-gru
和densenet-lite-s-fc
。 - 默认模型由之前的
conv-lite-fc
改为densenet-lite-fc
。 - 预测支持使用GPU。
- bugfixs:
- 修复同时初始化多个实例时会报错的问题;
- Web 调用时的内存泄露。感谢 @myuanz;
- 输入图片宽度很小时导致异常;
- 去掉
f-print
。
更多更新说明见 RELEASE Notes。
cnocr 是 Python 3 下的中英文OCR工具包,自带了多个训练好的识别模型(最小模型仅 4.7M
),安装后即可直接使用。
cnocr 主要针对的是排版简单的印刷体文字图片,如截图图片,扫描件等。目前内置的文字检测和分行模块无法处理复杂的文字排版定位。如果要用于场景文字图片的识别,需要结合其他的场景文字检测引擎使用,例如同样基于 MXNet 的文字检测引擎 cnstd 。
本项目起源于我们自己 (爱因互动 Ein+) 内部的项目需求,所以非常感谢公司的支持。
嗯,安装真的很简单。
pip install cnocr
注意:请使用Python3 (3.4, 3.5, 3.6以及之后版本应该都行),没测过Python2下是否ok。
cnocr的ocr模型可以分为两阶段:第一阶段是获得ocr图片的局部编码向量,第二部分是对局部编码向量进行序列学习,获得序列编码向量。目前两个阶段分别包含以下的模型:
- 局部编码模型(emb model)
conv
:多层的卷积网络;conv-lite/conv-lite-s
:更小的多层卷积网络;后缀没有-s
表示把图片长度压缩到1/4
再做预测,有-s
表示把图片长度压缩到1/8
再做预测。以下类似。densenet/densenet-s
:一个小型的densenet
网络;densenet-lite/densenet-lite-s
:一个更小的densenet
网络。
- 序列编码模型(seq model)
lstm
:一层的LSTM网络;gru
:一层的GRU网络;fc
:两层的全连接网络。
cnocr v1.2 目前包含以下可直接使用的模型,训练好的模型都放在 cnocr-models 项目中,可免费下载使用:
模型名称 | 局部编码模型 | 序列编码模型 | 模型大小 | 迭代次数 | 测试集准确率 | 测试集中的图片预测速度 (秒/张,环境:单GPU) |
---|---|---|---|---|---|---|
conv-lite-fc | conv-lite | fc | 18M | 25 | 98.61% | 0.004191 |
densenet-lite-gru | densenet-lite | gru | 9.5M | 39 | 99.04% | 0.003349 |
densenet-lite-fc | densenet-lite | fc | 4.7M | 40 | 97.61% | 0.003299 |
densenet-lite-s-gru | densenet-lite-s | gru | 9.5M | 35 | 98.52% | 0.002434 |
densenet-lite-s-fc | densenet-lite-s | fc | 4.7M | 40 | 97.20% | 0.002429 |
模型名称是由局部编码模型和序列编码模型名称拼接而成。
图片预测速度是在单个GPU环境下做的测试, 绝对值依赖机器资源,意义不大;但不同模型之间的相对值是可以参考的。
局部编码模型的名称如果以-s
结尾,表示把图片长度压缩到 1/8
做预测;没有以-s
结尾则表示把图片长度压缩到1/4
再做预测。相对于中文单字的大小,部分英文字母如i
、l
占位较少,对图片长度压缩过大会影响英文的识别精度。所以在英文场景下,建议使用不以-s
结尾的局部编码模型,如densenet-lite-fc
、densenet-lite-gru
。
本项目的初期代码fork自 crnn-mxnet-chinese-text-recognition,感谢作者 diaomin。
但源项目使用起来不够方便,所以我在此基础上做了一些封装和重构。主要变化如下:
-
不再使用需要额外安装的MXNet WarpCTC Loss,改用原生的 MXNet CTC Loss。所以安装极简!
-
自带训练好的中文OCR识别模型。不再需要额外训练!
-
增加了预测(或推断)接口。所以使用方便!
首次使用cnocr时,系统会自动下载zip格式的模型压缩文件,并存于 ~/.cnocr
目录(Windows下默认路径为 C:\Users\<username>\AppData\Roaming\cnocr
)。
下载后的zip文件代码会自动对其解压,然后把解压后的模型相关目录放于~/.cnocr/1.2.0
目录中。
如果系统无法自动成功下载zip文件,则需要手动从 cnocr-models 下载此zip文件并把它放于 ~/.cnocr/1.2.0
目录。如果Github下载太慢,也可以从 百度云盘 下载, 提取码为 msua
。
放置好zip文件后,后面的事代码就会自动执行了。
类CnOcr
是OCR的主类,包含了三个函数针对不同场景进行文字识别。类CnOcr
的初始化函数如下:
class CnOcr(object):
def __init__(
self,
model_name='densenet-lite-fc',
model_epoch=None,
cand_alphabet=None,
root=data_dir(),
context='cpu',
name=None,
):
其中的几个参数含义如下:
model_name
: 模型名称,即上面表格第一列中的值。默认为densenet-lite-fc
。model_epoch
: 模型迭代次数。默认为None
,表示使用默认的迭代次数值。对于模型名称densenet-lite-fc
就是40
。cand_alphabet
: 待识别字符所在的候选集合。默认为None
,表示不限定识别字符范围。cnocr.consts
中内置了两个候选集合:(1) 数字和标点NUMBERS
;(2) 英文字母、数字和标点ENG_LETTERS
。root
: 模型文件所在的根目录。- Linux/Mac下默认值为
~/.cnocr
,表示模型文件所处文件夹类似~/.cnocr/1.2.0/densenet-lite-fc
。 - Windows下默认值为
C:\Users\<username>\AppData\Roaming\cnocr
。
- Linux/Mac下默认值为
context
:预测使用的机器资源,可取值为字符串cpu
、gpu
,或者mx.Context
实例。name
:正在初始化的这个实例的名称。如果需要同时初始化多个实例,需要为不同的实例指定不同的名称。
每个参数都有默认取值,所以可以不传入任何参数值进行初始化:ocr = CnOcr()
。
类CnOcr
主要包含三个函数,下面分别说明。
函数CnOcr.ocr(img_fp)
可以对包含多行文字(或单行)的图片进行文字识别。
函数说明:
- 输入参数
img_fp
: 可以是需要识别的图片文件路径(如上例);或者是已经从图片文件中读入的数组,类型可以为mx.nd.NDArray
或np.ndarray
,取值应该是[0,255]
的整数,维数应该是(height, width, 3)
,第三个维度是channel,它应该是RGB
格式的。 - 返回值:为一个嵌套的
list
,类似这样[['第', '一', '行'], ['第', '二', '行'], ['第', '三', '行']]
。
调用示例:
from cnocr import CnOcr
ocr = CnOcr()
res = ocr.ocr('examples/multi-line_cn1.png')
print("Predicted Chars:", res)
或:
import mxnet as mx
from cnocr import CnOcr
ocr = CnOcr()
img_fp = 'examples/multi-line_cn1.png'
img = mx.image.imread(img_fp, 1)
res = ocr.ocr(img)
print("Predicted Chars:", res)
上面使用的图片文件 examples/multi-line_cn1.png内容如下:
上面预测代码段的返回结果如下:
Predicted Chars: [['网', '络', '支', '付', '并', '无', '本', '质', '的', '区', '别', ',', '因', '为'],
['每', '一', '个', '手', '机', '号', '码', '和', '邮', '件', '地', '址', '背', '后'],
['都', '会', '对', '应', '着', '一', '个', '账', '户', '一', '―', '这', '个', '账'],
['户', '可', '以', '是', '信', '用', '卡', '账', '户', '、', '借', '记', '卡', '账'],
['户', ',', '也', '包', '括', '邮', '局', '汇', '款', '、', '手', '机', '代'],
['收', '、', '电', '话', '代', '收', '、', '预', '付', '费', '卡', '和', '点', '卡'],
['等', '多', '种', '形', '式', '。']]
如果明确知道要预测的图片中只包含了单行文字,可以使用函数CnOcr.ocr_for_single_line(img_fp)
进行识别。和 CnOcr.ocr()
相比,CnOcr.ocr_for_single_line()
结果可靠性更强,因为它不需要做额外的分行处理。
函数说明:
- 输入参数
img_fp
: 可以是需要识别的单行文字图片文件路径(如上例);或者是已经从图片文件中读入的数组,类型可以为mx.nd.NDArray
或np.ndarray
,取值应该是[0,255]
的整数,维数应该是(height, width)
或(height, width, channel)
。如果没有channel,表示传入的就是灰度图片。第三个维度channel可以是1
(灰度图片)或者3
(彩色图片)。如果是彩色图片,它应该是RGB
格式的。 - 返回值:为一个
list
,类似这样['你', '好']
。
调用示例:
from cnocr import CnOcr
ocr = CnOcr()
res = ocr.ocr_for_single_line('examples/rand_cn1.png')
print("Predicted Chars:", res)
或:
import mxnet as mx
from cnocr import CnOcr
ocr = CnOcr()
img_fp = 'examples/rand_cn1.png'
img = mx.image.imread(img_fp, 1)
res = ocr.ocr_for_single_line(img)
print("Predicted Chars:", res)
对图片文件 examples/rand_cn1.png:
的预测结果如下:
Predicted Chars: ['笠', '淡', '嘿', '骅', '谧', '鼎', '皋', '姚', '歼', '蠢', '驼', '耳', '胬', '挝', '涯', '狗', '蒽', '子', '犷']
函数CnOcr.ocr_for_single_lines(img_list)
可以对多个单行文字图片进行批量预测。函数CnOcr.ocr(img_fp)
和CnOcr.ocr_for_single_line(img_fp)
内部其实都是调用的函数CnOcr.ocr_for_single_lines(img_list)
。
函数说明:
- 输入参数
img_list
: 为一个list
;其中每个元素是已经从图片文件中读入的数组,类型可以为mx.nd.NDArray
或np.ndarray
,取值应该是[0,255]
的整数,维数应该是(height, width)
或(height, width, channel)
。如果没有channel,表示传入的就是灰度图片。第三个维度channel可以是1
(灰度图片)或者3
(彩色图片)。如果是彩色图片,它应该是RGB
格式的。 - 返回值:为一个嵌套的
list
,类似这样[['第', '一', '行'], ['第', '二', '行'], ['第', '三', '行']]
。
调用示例:
import mxnet as mx
from cnocr import CnOcr
from cnocr.line_split import line_split
ocr = CnOcr()
img_fp = 'examples/multi-line_cn1.png'
img = mx.image.imread(img_fp, 1).asnumpy()
line_imgs = line_split(img, blank=True)
line_img_list = [line_img for line_img, _ in line_imgs]
res = ocr.ocr_for_single_lines(line_img_list)
print("Predicted Chars:", res)
更详细的使用方法,可参考 tests/test_cnocr.py 中提供的测试用例。
也可以使用脚本模式预测:
python scripts/cnocr_predict.py --file examples/multi-line_cn1.png
返回结果同上面。
结合文字检测引擎 cnstd 使用
对于一般的场景图片(如照片、票据等),需要先利用场景文字检测引擎 cnstd 定位到文字所在位置,然后再利用 cnocr 进行文本识别。
from cnstd import CnStd
from cnocr import CnOcr
std = CnStd()
cn_ocr = CnOcr()
box_info_list = std.detect('examples/taobao4.jpg')
for box_info in box_info_list:
cropped_img = box_info['cropped_img'] # 检测出的文本框
ocr_res = cn_ocr.ocr_for_single_line(cropped_img)
print('ocr result: %s' % ''.join(ocr_res))
注:运行上面示例需要先安装 cnstd :
pip install cnstd
cnstd 相关的更多使用说明请参考其项目地址。
cnocr自带训练好的模型, 安装后即可直接使用。但如果你需要训练自己的模型,请参考下面的步骤。所有代码均可在文件 Makefile 中找到。
为了提升训练效率,在开始训练之前,需要使用mxnet的recordio
首先把数据转换成二进制格式:
DATA_ROOT_DIR = data/sample-data
REC_DATA_ROOT_DIR = data/sample-data-lst
# `EMB_MODEL_TYPE` 可取值:['conv', 'conv-lite-rnn', 'densenet', 'densenet-lite']
EMB_MODEL_TYPE = densenet-lite
# `SEQ_MODEL_TYPE` 可取值:['lstm', 'gru', 'fc']
SEQ_MODEL_TYPE = fc
MODEL_NAME = $(EMB_MODEL_TYPE)-$(SEQ_MODEL_TYPE)
# 产生 *.lst 文件
gen-lst:
python scripts/im2rec.py --list --num-label 20 --chunks 1 \
--train-idx-fp $(DATA_ROOT_DIR)/train.txt --test-idx-fp $(DATA_ROOT_DIR)/test.txt --prefix $(REC_DATA_ROOT_DIR)/sample-data
# 利用 *.lst 文件产生 *.idx 和 *.rec 文件。
# 真正的图片文件存储在 `examples` 目录,可通过 `--root` 指定。
gen-rec:
python scripts/im2rec.py --pack-label --color 1 --num-thread 1 --prefix $(REC_DATA_ROOT_DIR) --root examples
利用下面命令在CPU上训练模型:
# 训练模型
train:
python scripts/cnocr_train.py --gpu 0 --emb_model_type $(EMB_MODEL_TYPE) --seq_model_type $(SEQ_MODEL_TYPE) \
--optimizer adam --epoch 20 --lr 1e-4 \
--train_file $(REC_DATA_ROOT_DIR)/sample-data_train --test_file $(REC_DATA_ROOT_DIR)/sample-data_test
如果需要在GPU上训练,把上面命令中的参数 --gpu 0
改为--gpu <num_gpu>
,其中的<num_gpu>
为使用的GPU数量。注意,使用GPU训练需要安装mxnet的GPU版本,如mxnet-cu101
。
评估模型的代码依赖一些额外的python包,使用下面命令安装这些额外的包:
pip install cnocr[dev]
训练好的模型,可以使用脚本 scripts/cnocr_evaluate.py 评估在测试集上的效果:
# 在测试集上评估模型,所有badcases的具体信息会存放到文件夹 `evaluate/$(MODEL_NAME)` 中
evaluate:
python scripts/cnocr_evaluate.py --model-name $(MODEL_NAME) --model-epoch 1 -v -i $(DATA_ROOT_DIR)/test.txt \
--image-prefix-dir examples --batch-size 128 -o evaluate/$(MODEL_NAME)
当然,也可以查看模型在单个文件上的预测效果:
predict:
python scripts/cnocr_predict.py --model_name $(MODEL_NAME) --file examples/rand_cn1.png
上面所有代码均可在文件 Makefile 中找到。
- 支持图片包含多行文字 (
Done
) - crnn模型支持可变长预测,提升灵活性 (since
V1.0.0
) - 完善测试用例 (
Doing
) - 修bugs(目前代码还比较凌乱。。) (
Doing
) - 支持
空格
识别(sinceV1.1.0
) - 尝试新模型,如 DenseNet,进一步提升识别准确率(since
V1.1.0
) - 优化训练集,去掉不合理的样本;在此基础上,重新训练各个模型
- 加入场景文本检测功能