『工程项目实践』表格识别 — V2.0


一、功能实现

1.1 resize_img

def resize_image(img, pix_max, pix_min):
    """ 根据图片设置的最大、最小阈值 resize 图片(同比例) """
    img_size = img.shape
    h_mul_w = img_size[0] * img_size[1]

    im_scale = 1.0
    if h_mul_w > pix_max:
        im_scale = float(pix_max) / h_mul_w
    elif h_mul_w < pix_min:
        im_scale = float(pix_min) / h_mul_w

    new_h = int(img_size[0] * im_scale)
    new_w = int(img_size[1] * im_scale)

    re_im = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    return re_im, (float(new_h) / img_size[0], float(new_w) / img_size[1])

1.2 四分类方向检测

  • step 1: 图像输入的 shape=(224, 224) 且为灰度图。
  • step 2:vgg16 为 backbone 的 4 分类模型 (0, 90°, 180°, 270°),检测后根据结果旋转图片,将图片摆正。 注意这里使用的是一个 onnx 模型,用 onnxruntime 框架执行运算,仅在 cpu 下,速度可达 0.06s/张。
  • step 3: 在方向检测摆正图片后,先对图片进行 makeborder 操作,再输入到接下来的识别逻辑中,copyMakeBorder补上一圈白色的边,防止有的图表格线是顶着边的,不利于 unet 检测。

1.3 表格线的语义分割和提取

  • step 1: 对于已经旋转过的图片,通过一个 Unet 网络做语义分割,得到横线与纵线的概率矩阵,然后利用 measure 模块对两个概率矩阵进行处理分析,从而提取表格中的横线与纵线。
  • step 2: 根据横线的斜率,计算图片倾斜角,并再次旋转图片,使横线正好平行于视图。
  • step 3: 由于 mask 可能出现断线,故用一些形态学算法,补上这些断线,为正确提取单元格做准备。
  • step 4: 此部分返回三个值,同等旋转后的 img, img_seg,以及表格的 Rows_y_merge,以便更好的是实现表格内的 cell 的定位。

1.4 找到图中表格与非表格区域: find_tables

  • step 1: 根据 img_seg 找到图中的大包围框,使用的方法是在 mask 里 “找白色轮廓”
  • step 2: 根据找到的大包围框(表格部分),将原图切成表格、非表格区域,非表格区域按普通 ocr 方法处理。

1.5 获得表格内的 cells 位置信息:find_cells

  • step 1: 用于寻找表格内部每个单元格的位置坐标(xmin, ymin, xmax, ymax),便于之后截取出来识别,注意这一步仅仅是寻找单元格的坐标,至于所处的行列信息以及里面包含的文字内容识别此步不考虑。
  • step 2: 由于白色线分隔出来的小黑块就是单元格位置,因此寻找黑色连通域就可以了,skimage 有个很好的包 measure,可以很方便的完成连通域的寻找以及 bbox 的获取。

1.6 获得图片中的文本位置信息:find_text

根据 tables 的坐标位置信息进行图片分割,返回文本区域位置坐标信息。

1.7 初始化 json 字典

构造形如合合的初始 AI json 字典,可以去合合官网看字典结构和每个字段的含义,以便接下来的识别信息直接填入字典中。

1.8 文本区域识别:recognize_text

  • step 1: 根据文本区域的位置信息,截取 roi 文本图片;
  • step 2: 对该文本区域进行 craft 检测,返回 box 坐标信息,然后根据 box 的坐标来进行排序调整;
  • step 3: 因为 craft 检测的 box 可能导致一行文字被分割开来,为了保持原有的格式,进行同一行文字合并并排序;
  • step 4: 文本 batch 识别
  • step 5: batch_text 解析,返回识别的结果,填入到 josn 字典中。

1.9 表格区域识别

step 1: cell 所处行列的判别

  • 任务是确定每个单元格的 start_column, end_column, start_row, end_row,目前的算法是做四次,依次确定 start_column, end_column, start_row, end_row。以 start_column 为例,将所有单元格按 xmin 排序,那么同一始列的 xmin 一定很接近,不同起始列的 xmin 有明显差异,如果投影在 x 轴上,同一列的会聚在一起,列转换时会有明显的突变。
  • 同样的 end_column 对应 xmax,start_row 对应 ymin,end_row 对应 ymax。
  • 但是在实验中发现,row 更易发生错误,那个跳变的阈值很难定,原因是有可能有下面这样的图:这种情况的行就不能这么做了,直观的想一想 1,2,3 的位置 ymin 的变化量是差不多的。故此,第二版的思路是,记住每条横线的位置(Rows_y)。
  • 起始行是第一行的单元格只能夹在 1,2 之间,依次类推。因为这样相对比较麻烦,而且第一版对列的判别基本没问题,所以用 1.0 思想做 start_column, end_column,2.0 思想做 start_row, end_row。

step 2: cell 内部文字识别

  • 接下来是确定每个单元格里的文字内容,因为有些单元格里面的文字不止一行,crnn 是不具备识别这种图的能力的,并且有的单元格留白太多,也不利于 crnn 识别。如果对每一个单元格都用文字检测模型去定位文字位置,则代价太高,时间耗时太长。针对表格文字比较规整这一特点。因此先做 line_split 算法,快速的将单元格内待识别的内容切割出来,送进 crnn 识别。
  • 表格 cell 内的文字分割后进行 batch 处理,送入 crnnOcr2 进行文字识别。

step 3: batch_text 解析

1.10 整理成合合 AI 表格 ocr 的返回 json 格式

二、网络结构

本项目中一共用了4个网络,作用各不相同

网络名称框架作用模型位置
vgg16onnx四分类,0-90-180-270判别./onnx
unetdarknet语义分割,二类,一类表格横线,一类纵线./darknet
craftpytorch非表格区域的文字检测./craft
crnnpytorch文字识别./crnn

三、运行需要的关键性环境说明

  • python 必须 3.6 版本以上!原因:2.7 不支持 onnxruntime 运算,3.5 对 scikit-image 库支持有限
  • torch 1.4.0 with CUDA 10.0
  • opencv 4.2.0
  • skimage 0.16.2
  • web 0.51
  • onnx 1.6.0
  • onnxruntime 1.2.0
  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 23
    评论
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

libo-coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值