接到个任务需要将几万张带表格的图片转换成结构化数据。

1. 大步骤

最终算是完成任务,但是识别率上还有一点问题,人工再过一下,还是蛮快的。先说一下大的步骤:分割单元格。将图片中的表格全部定位出来,然后按单元格裁剪成一个个小图片,以便后续分析及操作;

聚焦。其实就是将单元格中的文本区域裁剪出来,将多余的空白去掉;

大图片的识别。对于大图片用图像相似性的算法(phash+汉明距离)做识别;

小图片的识别。对于小图片,做字符分割,然后用NN做分类识别;

识别结果输出到txt;

txt输出到excel。将全部txt按照目标表格的格式,解析输出到excel。

1.1 分割单元格

既然只关心表格区域,所以第一步先将各个单元格拆分出来,截取成一个个小图片。尝试用图像的膨胀、腐蚀来定位表格区域,图像处理包skimage,最后算是定位出了表格区域,也分割出了各个单元格图片,其中部分中间过程的图片如下:

分割单元格这一块的基本流程是:读取图像;

二值化处理;

横向、纵向的膨胀、腐蚀操作,得到横线图img_row和竖线图img_col;

得到点图,img_row + img_col=img_dot;

得到线图,img_row × img_col=img_line(线图只是拿来看看的,后续没有用到);

浓缩点团到单个像素;

开始遍历各行的点,将各个单元格从二值图像上裁剪出来,保存到temp文件夹。

参考资料:

1.1.1 读取图像、二值化import skimage

# 读取图片,并转灰度图

img=io.imread(imgFilePath,True)

#二值化

bi_th=0.81

img[img<=bi_th]=0

img[img>bi_th]=1

1.1.2 膨胀、腐蚀操作# 膨胀腐蚀操作

def dil2ero(img,selem):

img=morphology.dilation(img,selem)

imgres=morphology.erosion(img,selem)

return imgres

# 求图像中的横线和竖线

rows,cols=img.shape

scale=80

col_selem=morphology.rectangle(cols//scale,1)

img_cols=dil2ero(img,col_selem)

row_selem=morphology.rectangle(1,rows//scale)

img_rows=dil2ero(img,row_selem)

1.1.3 得到点图、线图# 线图

img_line=img_cols*img_rows

# 点图

img_dot=img_cols+img_rows_temp

img_dot[img_dot>0]=1

img_dot=clearEdge(img_dot,3)

1.1.4 浓缩点为单个像素# 收缩点团为单像素点(3×3)

def isolate(img):

idx=np.argwhere(img<1)

rows,cols=img.shape

for i in range(idx.shape[0]):

c_row=idx[i,0]

c_col=idx[i,1]

if c_col+1

img[c_row,c_col+1]=1

img[c_row+1,c_col]=1

img[c_row+1,c_col+1]=1

if c_col+2

img[c_row+1,c_col+2]=1

img[c_row+2,c_col]=1

img[c_row,c_col+2]=1

img[c_row+2,c_col+1]=1

img[c_row+2,c_col+2]=1

return img

img_dot=isolate(img_dot)

1.1.5 遍历各dot,裁剪图片

按行遍历各个顶点,判断这些顶点是否是目标单元格的顶点,即可将图片裁出。

1.2 聚焦

图片中的表格的各个单元格都已经截取出来,但是单元格有高有矮,不利于后续分析,所以想到只要聚焦文字区域就行,即单元格里的文字区域截取出,其余空白就不要了。聚焦方法就是按行、列分别求和,因为图片白色区域值为1,黑色区域值为0,所以按行求和后,全白部分的sum=width,文字区域及sum

代码如下:def focusImg(imgPath):

img=io.imread(imgPath)

img=color.rgb2gray(img)

img=img_as_float(img)

img=clearEdge(img,3)

# 求各列的和

col_sum=img.sum(axis=0)

# 求各行的和

row_sum=img.sum(axis=1)

idx_col_sum=np.argwhere(col_sum

if len(idx_col_sum)==0:

os.remove(imgPath)

return

col_start,col_end=idx_col_sum[0,0]-1,idx_col_sum[-1,0]+2

idx_row_sum=np.argwhere(row_sum

if len(idx_row_sum)==0:

os.remove(imgPath)

return

row_start,row_end=idx_row_sum[0,0]-1,idx_row_sum[-1,0]+2

经过聚焦操作,图片中的各个元素大可分成以下这些类别:

大概分析了一下图片,碰巧发现,焦后的标题类图片高度都大于13(大图片),而数值类图片高度都小于等于13(小图片)。大图片的种类数量不算多,大概一百多种。小图片基本上是金融、日期,还有一些特定字符比如 “/”、“N”、"*"什么的,所以对小图再做字符分割,也就十多种。

这时关于单元格里内容的识别,就有了以下操作:对于大图片,将一百多张图片作为模板,将输入的图片逾模板里的图片做相似性对比(phash+汉明距离);

对于小图片,做字符分割,使用pytorch+CNN做识别;

1.3 大图片识别(标题部分)

大图片内容的识别,基本上就是靠的模板匹配,具体算法原理看参考资料:

耗费了些时间整理好了模板文件夹,将图片里的文字作为文件名,在做模板初始化的时候就很方便的生成模板phash字典了:dic{key,value} => dic{fname,phash}

代码如下:hash_size=20

phashHamming_th=100

def hamming(h1, h2):

'''计算两图的汉明距离'''

return sum(sum(h1.hash^h2.hash))

def getText(img,bigPicTempleDic):

hashHere=imagehash.phash(img,hash_size=hash_size)

seq=[]

for key in bigPicTempleDic.keys():

seq.append((hamming(hashHere,bigPicTempleDic[key]),key))

res_minDis,res_key=sorted(seq,key=lambda x:x[0])[0]

#print('HMdis:{0}'.format(res_minDis))

if res_minDis

return res_key

else:

return '未识别出来'

#模板文件夹的路径

templePath=r'...\bigPicTemple'

bigPicTempleDic={'keyname':'phash'}

# 初始化模板字典

# dict{文件名,phash}

for fpath,fdir,fs in os.walk(templePath):

for f in fs:

fname,fext=os.path.splitext(f)

bigPicTempleDic[fname]=imagehash.phash(

Image.open(os.path.join(fpath,f)),

hash_size=hash_size)

del bigPicTempleDic['keyname']

1.4 小图片识别(字符分割+CNN)

对于小图片,则继续分割字符,再将单个字符输入CNN,识别结果。

1.4.1 字符分割

比如‘1,234’,分割为五个字符:‘1’,‘,’,‘2’,‘3’,‘4’。基本原理跟上文的聚焦差不多,就是找到字符之间的空隙。def splitChar(img):

imgF=img_as_float(img)

# 求各列的和

col_sum=imgF.sum(axis=0)

idx=np.argwhere(col_sum==col_sum.max())

images=[]

for i in range(1,len(idx)):

if idx[i,0]-idx[i-1,0]>1:

imgHere=img.crop((idx[i-1,0],0,idx[i,0]+1,img.height))

images.append(imgHere)

return images

1.4.2 pytorch+CNN字符识别

用这个主要是之前看到些minst的文章,也想试试手pytorch这些ML框架。其实一开始使用的softmax多分类,测试发现效果并不好,比如数字2、3、7经常会搞混。后来考虑到softmax输入的图片是转为一维数组输入,也丢失图像的像素之间的结构关系,所以就换成CNN了。

参考资料:

pytorch下载的时候,可能是上网不科学的缘故,安装地址刷不出,可以去这里试试:PyTorch 中文社区 - ApacheCNW

代码如下:import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

from torchvision import datasets, transforms

from torch.autograd import Variable

dicRes={

0:'0',

1:'1',

2:'2',

3:'3',

4:'4',

5:'5',

6:'6',

7:'7',

8:'8',

9:'9',

10:'N',

11:',',

12:'.',

13:'—',

14:'/',

15:'*',

16:'无'

}

def cnnPred(data):

'''data是一个[1,1,28,28]的图'''

data.resize((1,1,28,28))

data=torch.FloatTensor(data)

data=Variable(data, volatile=True)

output = model(data)

# get the index of the max

pred = output.data.max(1, keepdim=True)[1]

return dicRes[int(pred)]

class CNN(nn.Module):

def __init__(self):

super(CNN, self).__init__()

#1*28*28

self.conv1=nn.Sequential(

#16*28*28

#padding=(ks-1)/2时,图像大小不变

nn.Conv2d(in_channels=1,out_channels=16,kernel_size=5,stride=1,padding=2),

nn.ReLU(),

#16*14*14

nn.MaxPool2d(kernel_size=2)

)

self.conv2=nn.Sequential(

#32*14*14

nn.Conv2d(16,32,5,1,2),

nn.ReLU(),

#32*7*7

nn.MaxPool2d(2)

)

self.out=nn.Linear(32*7*7,17)

def forward(self, x):

x = self.conv1(x)

x = self.conv2(x)

x = x.view(x.size(0),-1)

output = self.out(x)

return output

model = CNN()

# 加载已训练好的参数

model.load_state_dict(torch.load('my_CNN_params.pkl'))

1.5 结果输出

单个图片输入,识别的结果输出到txt文本。将全部txt按照目标表格的样式,输出到excel,这些基本都是文件、文本、字符串的操作,就不细说了,参考资料:

2. 其他问题

2.1 有的表格的一条边颜色较浅

由于之前采用的是全局二值化,所以遇到这种表格一条边偏白的状况,二值化后就没了,导致表格的一些顶点没定位出来,最终结果就是输出到excel的时候,才发现一些数据错列了。

解决思路无非就是考虑自适应的二值化,或者是粗暴一点的分类二值化。由于赶时间,我用了比较粗暴的方法:即原全局二值化的图片img_forSplit,继续作为分割单元格的底图;

查看表格的浅色边的灰度值,直接以该值再做一个全局二值化图img,作为定位顶点的图。

代码如下:# 读取图片,并转灰度图

img=io.imread(imgFilePath,True)

#二值化

img_forSplit=copy.deepcopy(img)

#img 提取边框用

bi_th=img.max()*0.875

img[img

img[img>=bi_th]=1

# img_forSplit 分割用

bi_th=0.733

img_forSplit[img_forSplit

img_forSplit[img_forSplit>=bi_th]=1

2.2 字符分割有出错

测试发现对于两个0相连,或者是8相连这种容易分割失败。比如‘000’,理想状况是分割出3个‘0’,但往往还是割出‘000’。放大图像就发现了,0这种算是数字里比较宽的字符了,几个0放一起,中间的像素会有些模糊的黏连,这块我还没想好解决方法。

python图片内容长度识别_python 图片中的表格识别相关推荐

  1. 【应用】Python调用百度AI实现图片上表格识别

    [应用]Python调用百度AI实现图片上表格识别 简介 步骤 安装百度AI库 注册百度AI开放平台 调用AipOcr库识别表格文字 可能遇到的问题 批量操作 简介 Python免费调用百度AI实现图 ...

  2. 人口普查分析:利用python+百度文字识别提取图片中的表格数据

    今天发布了最新的人口普查结果,笔者拿到的文件是pdf格式(网上应该有).之前就一直想实现从pdf提取表格数据,输出为excel.正好这次有公开数据,因此打算用来练个手. 尝试了两种方法: 1.pyth ...

  3. python图片内容长度识别_教你如何用几行Python代码识别图片文字--就是这么简单!...

    今天给大家分享的主题是用百度的接口实现图片的文字识别. ​ 环境和配置要求 整体是用 Python 实现,所需要使用的第三方库包括 aip . PIL . keyboard . pyinstaller ...

  4. python 百度ocr识别_Python使用百度Ocr识别文字保存CSV

    1.准备: 1)Python开发环境, 笔者用的是3.7; 工具用的是Pycharm 2)百度云后台创建文字识别的应用, 获取AppID, API key, Secret Key 百度云后台创建文字识 ...

  5. python图片内容长度识别_Python实现识别图片内容的方法分析

    本文实例讲述了Python实现识别图片内容的方法.分享给大家供大家参考,具体如下: python识别图片内容. 这里我的环境为windows64位,python2.7.14 需要用到PIL模块和tes ...

  6. python花萼长度表_Python 数据分析答疑 5:Pandas入门

    8.23 第五课 Pandas入门作业 1: 使用如下代码创建 DataFrame, gdp = {"country":["United States", &q ...

  7. python制表符长度不_python \t python里的 \t 的长度具体是几个字符?

    python里的 \t 的长度具体是几个字符?如果没有你小编将不会痛苦,如果没有你小编将保持纯洁 python -c "print('123456789');print('\tA')&quo ...

  8. python实现验证码识别_python实现图文验证码识别

    一,验证码类别 以下为网站常见的验证码: 1.图片验证码:常见的为英文.数字.汉字,计算题等类型的验证码. 2.行为式验证码: 常见的有滑动拼图,文字点选,图标点选,推理拼图等类型的验证码. 3.手机 ...

  9. python excel操作单元格_python 操作excel表格的方法

    说明:由于公司oa暂缺,人事妹子在做考勤的时候,需要通过几个excel表格去交叉比对员工是否有旷工或迟到,工作量大而且容易出错. 这时候it屌丝的机会来啦,花了一天时间给妹子撸了一个自动化脚本. 1. ...

  10. python 写入第二列_python读写Excel表格的实例代码(简单实用)

    这篇文章主要介绍了python读写Excel表格的方法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下.需要先安装两个库:pip install xlrd.pip ...

最新文章

  1. 举个例子,如何用GCN图卷积神经网络实现摔倒监测?
  2. 一文带你玩转设计模式之「责任链」
  3. 最详细支付宝接口申请、使用!!!带详细流程--实践--支付宝当面付申请
  4. 关于父窗口获取跨域iframe子窗口中的元素
  5. 基于linux-2.6.35的class_create(),device_create解析
  6. ServiceMix中文教程
  7. 20159302 《网络攻击与防范》第四周学习总结
  8. 循环递归,相互结合,释放数据的价值
  9. Nacos 发布0.3.0版本,迄今为止最好看的版本
  10. 【Java】关于Java的一些基础知识点
  11. 如何在SQL Server中使用数据质量服务清除主数据服务数据
  12. 拼多多前端岗位笔试试题 问答题部分 2017/8/1
  13. 关于E-Prime 2.0 无法呈现音频的一种解决方案
  14. 快压下载|快压软件官方下载
  15. QQ通信原理及QQ是怎么穿透内网进行通信的?
  16. BottomNavigationView与Navigation使用
  17. 013:Django商城项目规划与环境搭建
  18. 南京理工大学计算机学院施静,“为是这个学院的一分子而骄傲”----院友风采(2014届):南京理工大学最年轻教授 祁志祥...
  19. 在月球上你会看到这些神奇景象:不可思议
  20. Advanced Installer 制作带升级功能的安装包

热门文章

  1. Framework类库
  2. 小程序tabBar右上角添加角标
  3. 电脑共享打印机拒绝访问要怎么办
  4. 倾斜摄影计算机配置,2019年倾斜摄影三维建模-台式、便携、多机集群配置推荐...
  5. SIM868获取LBS位置
  6. 税控盘是服务器系统,税控盘系统设置服务器地址
  7. 对Python 网络设备巡检脚本的实例讲解
  8. 上三角数字三角形(Java)
  9. Android权限动态权限修改和其他的Android配置修改
  10. Understanding Deep Image Representations by Inverting Them