【文字识别】PaddleOCR实战和算法解读

【文字识别】PaddleOCR实战和算法解读

  • 项目地址:
    • PaddleOCR:
    • 基于PaddleOCR的中软杯国二项目:
  • PaddleOCR简介:
    • 项目简介:
    • 在线体验:
  • 模型介绍:
    • 文本检测算法:
      • 1. 支持的开源算法:
      • 2. 开源算法精度:
      • 3. DB 算法简介:
        • 算法简介:
        • 模型结构:
        • 二值化操作:
        • 可微的二值化:
        • 可变形卷积:
        • 标签生成:
        • 损失函数:
        • 后处理:
    • 文字识别算法:
      • 1. 支持的开源算法:
      • 2. 开源算法精度:
      • 3. CRNN 算法简介:
        • CNN(卷积层):
        • RNN(序列层):
        • CTC(转录层):
  • PaddleOCR实战:
    • 安装依赖库:
    • 创建实例并查看图像:
    • 使用OCR模型进行文本检测和识别:

项目地址:

PaddleOCR:

https://github.com/PaddlePaddle/PaddleOCR

基于PaddleOCR的中软杯国二项目:

https://aistudio.baidu.com/aistudio/projectdetail/1188761

项目演示视频:

中软杯国二开源——基于OCR+NLP的企业实体识别项目

https://www.bilibili.com/video/BV1aA411K7zg

OCR+NLP应用案例:Android端文字检测和企业实体识别

https://www.bilibili.com/video/BV1kK4y1h75C

PaddleOCR简介:

项目简介:

PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。基于飞桨的OCR工具库,包含总模型仅8.6M的超轻量级中文OCR,单模型支持中英文数字组合识别、竖排文本识别、长文本识别。同时支持多种文本检测、文本识别的训练算法。

在线体验:

https://www.paddlepaddle.org.cn/hub/scene/ocr

【文字识别】PaddleOCR实战和算法解读_第1张图片

模型介绍:

文本检测算法:

1. 支持的开源算法:

PaddleOCR开源的文本检测算法包括:

  • DB:https://arxiv.org/abs/1911.08947
  • EAST:https://arxiv.org/abs/1704.03155
  • SAST:https://arxiv.org/abs/1908.05498

2. 开源算法精度:

【文字识别】PaddleOCR实战和算法解读_第2张图片

3. DB 算法简介:

算法简介:

【文字识别】PaddleOCR实战和算法解读_第3张图片
在 DB 算法之前,对于曲形文本的检测任务,基于分割的算法比基于回归的算法表现更好,但之前基于分割的算法,都需要进行手动设计二值化的后处理算法,将分割生成的概率图转换为文本的包围框。

该篇文章的作者提出了 Differentiable Binarization (DB),它可以在分割网络中执行二值化过程,可以自适应地设置二值化阈值,不仅简化了后处理,而且提高了文本检测的性能,并且在 5 个文本检测数据集上都取得了SOTA的效果。

模型结构:

【文字识别】PaddleOCR实战和算法解读_第4张图片

主要包含三个部分:

  • backbone提取特征(特征金字塔)
  • 特征金字塔被上采样到相同尺度构建一个特征图F
  • 使用F来预测概率图P和阈值图T,并通过P和T来生成二值图B

二值化操作:

标准二值化(Standard Binarization,SB)对于分割特征图 P ∈ R H ∗ W P\in R^{H*W} PRHW,使用下面的方式进行二值化处理:
在这里插入图片描述

可微的二值化:

由于上述公式中的二值方法不是可微的,因而就不能在分割网络中随着训练的过程进行优化,为了解决这个问题文章提出了一个函数来近似这个二值化过程:
在这里插入图片描述
其中 B ^ \hat B B^ 就是近似二值图,T是自适应的阈值图,k是膨胀因子(经验性设置k=50)。

则正样本标签和负样本标签的loss分别为:
【文字识别】PaddleOCR实战和算法解读_第5张图片
在下图中展示了阈值图对于检测的影响,就算没有阈值图的监督,阈值图也可以很好区分文本的边界:

【文字识别】PaddleOCR实战和算法解读_第6张图片

可变形卷积:

作者使用可变形卷积的原因是,可变形卷积可以提供更加丰富的感受野,这对于极端比例的文本检测效果有益:

【文字识别】PaddleOCR实战和算法解读_第7张图片
此外,为了增加网络的感受野,文章在backbone的stage3、stage4、stage5使用了deformable卷积。

标签生成:

在训练标签的生成过程中借鉴了PSENet的方法,使用标签收缩的方式进行,这里对于搜索的offset D DD使用下面的计算方式得到:
在这里插入图片描述
即如图所示:
【文字识别】PaddleOCR实战和算法解读_第8张图片

损失函数:

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

上面三个损失分量分别是分割概率损失、二值图损失、阈值图损失, α = 1.0 , β = 10.0 \alpha=1.0,\beta=10.0 α=1.0,β=10.0

并且为了样本均衡这里使用了困难样本挖掘,保持正负样本的比例为1:3。

后处理:

在推理过程中,可以使用概率图(probability map)或者近似概率图(approximate binary map)产生文本边缘框。为了提升效率,作者使用了概率图。产生预测结果分为三个步骤:

  • 概率图通过一个阈值获得二值图;
  • 通过二值图获得连接区域;
  • 收缩区域通过膨胀再扩展回来,使用公式:
    在这里插入图片描述
  • 其中 D , D^, D就是扩展补偿, A , A^, A是收缩多边形的面积, L , L^, L就是收缩多边形的周长, r , r^, r作者设置的是1.5。

【文字识别】PaddleOCR实战和算法解读_第9张图片

文字识别算法:

1. 支持的开源算法:

PaddleOCR基于动态图开源的文本识别算法列表:

  • CRNN:https://arxiv.org/abs/1507.05717
  • Rosetta:https://arxiv.org/abs/1910.05085
  • STAR-Net:http://www.bmva.org/bmvc/2016/papers/paper043/index.html
  • RARE:https://arxiv.org/abs/1603.03915v1
  • SRN:https://arxiv.org/abs/2003.12294

2. 开源算法精度:

【文字识别】PaddleOCR实战和算法解读_第10张图片

3. CRNN 算法简介:

CRNN 全称为 Convolutional Recurrent Neural Network,主要用于端到端地对不定长的文本序列进行识别,不用先对单个文字进行切割,而是将文本识别转化为时序依赖的序列学习问题,就是基于图像的序列识别。
【文字识别】PaddleOCR实战和算法解读_第11张图片
整个CRNN网络结构包含三部分,从下到上依次为:

  • CNN(卷积层),使用深度CNN,对输入图像提取特征,得到特征图;
  • RNN(循环层),使用双向LSTM对特征序列进行预测,对序列中的每个特征向量进行学习,并输出预测标签分布;
  • CTC loss(转录层),使用 CTC 损失,把从循环层获取的一系列标签分布转换成最终的标签序列。

CNN(卷积层):

输入图像为灰度图像(单通道);高度为32,这是固定的,图片通过 CNN 后,高度就变为1,这点很重要;宽度为160,宽度也可以为其他的值,但需要统一,所以输入CNN的数据尺寸为 (channel, height, width)=(1, 32, 160)。

CNN的输出尺寸为 (512, 1, 40)。即 CNN 最后得到512个特征图,每个特征图的高度为1,宽度为40。
【文字识别】PaddleOCR实战和算法解读_第12张图片
即:
【文字识别】PaddleOCR实战和算法解读_第13张图片

RNN(序列层):

因为 RNN 有梯度消失的问题,不能获取更多上下文信息,所以 CRNN 中使用的是 LSTM,LSTM 的特殊设计允许它捕获长距离依赖,不了解的话可以看一下这篇文章 对RNN和LSTM的理解。

LSTM 是单向的,它只使用过去的信息。然而,在基于图像的序列中,两个方向的上下文是相互有用且互补的。将两个LSTM,一个向前和一个向后组合到一个双向LSTM中。此外,可以堆叠多层双向LSTM,深层结构允许比浅层抽象更高层次的抽象。

这里采用的是两层各256单元的双向 LSTM 网络:

【文字识别】PaddleOCR实战和算法解读_第14张图片
通过上面一步,我们得到了40个特征向量,每个特征向量长度为512,在 LSTM 中一个时间步就传入一个特征向量进行分类,这里一共有40个时间步。

我们知道一个特征向量就相当于原图中的一个小矩形区域,RNN 的目标就是预测这个矩形区域为哪个字符,即根据输入的特征向量,进行预测,得到所有字符的softmax概率分布,这是一个长度为字符类别数的向量,作为CTC层的输入。即输出为 40 个长度为字符类别数的向量构成的后验概率矩阵。

【文字识别】PaddleOCR实战和算法解读_第15张图片

CTC(转录层):

转录是将 RNN 对每个特征向量所做的预测转换成标签序列的过程。数学上,转录是根据每帧预测找到具有最高概率组合的标签序列。即CTC是一种对不需要对齐的Loss计算方法,用于训练网络,被广泛应用于文本行识别和语音识别中。

序列合并机制:
CTC以“-”符号代表blank,RNN 输出序列时,在文本标签中的重复的字符之间插入一个“-”,比如输出序列为“bbooo-ookk”,则最后将被映射为“book”,即有blank字符隔开的话,连续相同字符就不进行合并。即对字符序列先删除连续重复字符,然后从路径中删除所有“-”字符,这个称为解码过程,而编码则是由神经网络来实现。引入blank机制,我们就可以很好地解决重复字符的问题。

CTC 称上述变换为 β \beta β 变换,例如: β ( − − b b o o − o o o k k ) = b o o k \beta(--bboo-oookk)=book β(bboooookk)=book。然 β \beta β 变换不是单对单映射。

一些符号表示:

对于LSTM给定输入 x x x (特征向量)的情况下,输出为 l l l (对应的字符)的概率为:

p ( l ∣ x ) = ∑ π ∈ β − 1 ( l ) p ( π ∣ x ) p(l|x)=\sum_{\pi \in \beta^{-1}(l)}p(\pi|x) p(lx)=πβ1(l)p(πx)

其中 π ∈ β − 1 ( l ) \pi \in \beta^{-1}(l) πβ1(l) 表示经过 β \beta β 变换后为 l l l 的路径。对于任意一条路径 π \pi π 有:

p ( π ∣ x ) = ∏ t = 1 T y π t t p(\pi|x)=\prod^T_{t=1}y^t_{\pi_t} p(πx)=t=1Tyπtt

例如对于 T = 12 T=12 T=12 的路径 π 1 \pi_1 π1
π 1 = ( − − s t t a − t − − − e ) \pi_1=(--stta-t---e) π1=(sttate)
p ( π 1 ∣ x ) = y − 1 ⋅ y − 2 ⋅ y s 3 ⋅ y t 4 ⋅ y t 5 ⋅ y a 6 ⋅ y − 7 ⋅ y t 8 ⋅ y − 9 ⋅ y − 10 ⋅ y − 11 ⋅ y e 12 ⋅ p(\pi_1|x)=y^1_-\cdot y^2_-\cdot y^3_s\cdot y^4_t\cdot y^5_t\cdot y^6_a\cdot y^7_-\cdot y^8_t\cdot y^9_-\cdot y^{10}_-\cdot y^{11}_-\cdot y^{12}_e\cdot p(π1x)=y1y2ys3yt4yt5ya6y7yt8y9y10y11ye12

CTC的训练:

CTC 的训练过程本质上是通过梯度 ∂ p ( l ∣ x ) ∂ w \frac{\partial p(l|x)}{\partial w} wp(lx) 调整 LSTM 的参数 w w w,使得输入样本为 π \pi π 时使得 p ( l ∣ x ) p(l|x) p(lx) 尽可能大。

因此 CTC 借用了 HMM 的“向前—向后”(forward-backward)算法来计算 p ( l ∣ x ) p(l|x) p(lx) ,这段比较长,大家可以参考:https://zhuanlan.zhihu.com/p/43534801

PaddleOCR实战:

安装依赖库:

!pip install shapely
!pip install pyclipper
Looking in indexes: https://mirror.baidu.com/pypi/simple/
Collecting shapely
[?25l  Downloading https://mirror.baidu.com/pypi/packages/98/f8/db4d3426a1aba9d5dfcc83ed5a3e2935d2b1deb73d350642931791a61c37/Shapely-1.7.1-cp37-cp37m-manylinux1_x86_64.whl (1.0MB)
[K     |████████████████████████████████| 1.0MB 13.1MB/s eta 0:00:01
[?25hInstalling collected packages: shapely
Successfully installed shapely-1.7.1
Looking in indexes: https://mirror.baidu.com/pypi/simple/
Collecting pyclipper
[?25l  Downloading https://mirror.baidu.com/pypi/packages/1a/2f/ba30c6fe34ac082232a89f00801ea087c231d714eb200e8a1faa439c90b5/pyclipper-1.2.0-cp37-cp37m-manylinux1_x86_64.whl (126kB)
[K     |████████████████████████████████| 133kB 12.5MB/s eta 0:00:01
[?25hInstalling collected packages: pyclipper
Successfully installed pyclipper-1.2.0
from PIL import Image, ImageDraw, ImageFont
from numpy import random
import paddlehub as hub
import numpy as np
import paddle.fluid as fluid

class Detector(object):
    def __init__(self):
        # 加载移动端预训练模型
        # self.ocr = hub.Module(name='chinese_ocr_db_crnn_mobile')
        # 服务端可以加载大模型,效果更好
        self.ocr = hub.Module(name='chinese_ocr_db_crnn_server')

    def feedCap(self, np_images, vis=True):

        results = self.ocr.recognize_text(
            # 图片数据,ndarray.shape 为 [H, W, C],BGR格式;
            images=[np_images],
            use_gpu=True,            # 是否使用 GPU;若使用GPU,请先设置CUDA_VISIBLE_DEVICES环境变量
            visualization=False,      # 是否将识别结果保存为图片文件;
            box_thresh=0.5,           # 检测文本框置信度的阈值;
            text_thresh=0.5)

        img = Image.fromarray(np_images[:, :, [2, 1, 0]])
        draw = ImageDraw.Draw(img)  # 图片上打印
        txt = []

        for result in results:
            data = result['data']
            for infomation in data:
                if vis:
                    for i in range(5):
                        pos = [(v[0]+i, v[1]+i)
                               for v in infomation['text_box_position']]
                        draw.polygon(pos, outline=(0, 255, 0))
                txt.append(infomation['text'])

        # img = np.array(img)[:, :, [2, 1, 0]]
        return img, txt

创建实例并查看图像:

import os
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
os.environ["CUDA_VISIBLE_DEVICES"] = '0'

img = cv2.imread('21.jpg')
plt.imshow(img[:, :, [2, 1, 0]])

使用OCR模型进行文本检测和识别:

ocr_model = Detector()

result, txt = ocr_model.feedCap(img)
plt.imshow(result)
plt.show()
print(txt)
[32m[2020-11-04 10:05:29,624] [    INFO] - Installing chinese_ocr_db_crnn_server module[0m
[32m[2020-11-04 10:05:29,627] [    INFO] - Module chinese_ocr_db_crnn_server already installed in /home/aistudio/.paddlehub/modules/chinese_ocr_db_crnn_server[0m
[32m[2020-11-04 10:05:30,104] [    INFO] - Installing chinese_text_detection_db_server module-1.0.2[0m
[32m[2020-11-04 10:05:30,107] [    INFO] - Module chinese_text_detection_db_server-1.0.2 already installed in /home/aistudio/.paddlehub/modules/chinese_text_detection_db_server[0m

【文字识别】PaddleOCR实战和算法解读_第16张图片

['正新鸡排', '遇见', '见', '天派', '天派', '元', 'Bh!', '31G元', '有爱就是', '超大派', '正新', '12元', '正新鸡排', '正新鸡排', '门市价18元', '再饮科1']

你可能感兴趣的:(深度学习-OCR,计算机视觉,神经网络,ocr,深度学习,人工智能)