基于神经网络的OCR识别

Optical Character Recognition(OCR) 光学识别,通俗的讲就是识别图片内的文字,比如身份证上的身份证号,姓名,地址等,银行卡上的卡号 等等.

Evil

Github repo

Evil是一个iOS和macOS平台下简单的识别框架。支持通过 CocoaPods、Carthage 和 Swift Package Manager 安装。底层的识别模型可以很容易的迁移到其他平台。

c16b08733a8676e9a62251b94609baab.png

OCR识别的基本流程

  1. 从整张图片截取需要识别的区域 eg: 从一整张图片中截取身份证所在的矩形区域
  2. 截取文字区域 eg: 通过一定的算法截取到身份证号码所在的区域
  3. 对文字区域进行一系列的预处理方便下一步操作 eg: 高斯模糊、膨胀等等
  4. 分割文字,讲文字区域分割为单个的
  5. 将单个字丢进神经网络识别

Evil使用最新的Vision框架来实现。前4步 Apple 为我们提供了很好用系统方法来使用 例如: VNDetectTextRectanglesRequest。所以这里我们不讨论前4步的一些实现细节,如果大家想学习一下api的使用,可以看这里。

如何使用神经网络识别单个字

我个人认为对于少量的印刷体文字的识别可以用图片分类模型来处理,如果大家有更好的解决方法欢迎交流。假如你是一名CNN调参侠那接下来的内容就很好理解了, 但是如果你没有神经网络相关的基础知识,接下来的内容可能有点晦涩,因为毕竟我也是只懂个皮毛~。假如你之前没有相关知识,可以了解一下Apple为我们提供的Turi Create,可以免去自己设计网络。

0x00 设计网络

首先我们需要设计一个CNN网络来输入我们的单个字图片让它识别,因为我们的识别任务很简单,所以网络架构会很简单。 以下是 Keras (2.0.6) 代码:

model = Sequential()model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu'))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.5))model.add(Conv2D(64, (3, 3), activation='relu'))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.2))model.add(Conv2D(128, (1, 1), activation='relu'))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.2))model.add(Flatten())model.add(Dense(128, activation='relu'))model.add(Dense(num_classes, activation='softmax'))复制代码

0x01 生成训练数据

我们知道要对网络进行训练,必须需要大量的原始数据那我们没有怎么办呢?有些训练资源在网络上可以找到,但是像我们这里要识别身份证号码,怎么办呢?

当然是写脚本生成啦,比如我们先生成很多很多的身份证号码区域。进行一些随机变化增加数据的多样性。

o_image = Image.open(BACKGROUND) draw_brush = ImageDraw.Draw(o_image) font_size = random.randint(-5, 5) + 35 draw_brush.text((10 + random.randint(-10, 10), 15 + random.randint(-2, 2)), LABELS, fill='black', font=ImageFont.truetype(FONT, font_size)) o_image = ImageEnhance.Color(o_image).enhance( random.uniform(0.5, 1.5)) # 着色 o_image = ImageEnhance.Brightness(o_image).enhance( random.uniform(0.5, 1.5)) # 亮度 o_image = ImageEnhance.Contrast(o_image).enhance( random.uniform(0.5, 1.5)) # 对比度 o_image = ImageEnhance.Sharpness(o_image).enhance( random.uniform(0.5, 1.5)) # 旋转 o_image = o_image.rotate(random.randint(-2, 2)) o_image.save(output + '/%d.png' % idx)复制代码

有了文字区域以后就需要对文字区域进行分割为单字然后训练网络,因为接下来的任务具有通用性,所以我索性写了一个小工具叫做PrepareBot。具体代码在这里,大家感兴趣可以去看看。

0x02 训练网络

有了数据,有了网络模型 训练网络就很简单了大概如下:

model.fit_generator(generator=train_data_generator)复制代码

好了到这里,大家观察一下网络的收敛情况和识别精度,如果不是很糟糕的话,就可以把这个model保存起来了,为以后的识别任务做准备啦。注意这一步生成的Keras model 是跨平台,也就是说在windows,linux 甚至是android 上都可以用来识别哦。

0x03 转换网络

前面几步我们生成的是Keras 的网络模型,如何在Evil中使用这些模型呢?首先我们需要使用苹果提供的工具coremltools,将keras模型转换为CoreModel具体使用大概如下

# Prepare model for inferencefor k in model.layers: if type(k) is keras.layers.Dropout: model.layers.remove(k) model.save("./temp.model")core_ml_model = coremltools.converters.keras.convert("./temp.model
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐