⽤OpenCV和OCR识别图⽚中的表格数据!OpenCV简直太强⼤了!
在很多时候,我们的数据来源形式是多种多样的,有时候数据(或表格)也会呈现在图⽚中。
那么,我们如何来获取图⽚中的有⽤数据呢?当⼀张图⽚中含有表格数据的时候,我们可以⽤
OpenCV识别表格中的直线,然后再⽤OCR技术识别其中的⽂字。
本⽂仅作为如何识别图⽚中的表格的⼀个例⼦,希望能给读者⼀些启⽰。笔者⽤到的⼯具如
下:
opencv
pyteressact
numpy
我们⽤opencv来识别表格中的直线,⽤pyteressact来识别单元格⽂字,⽤numpy做数值处理。
我们要识别的⽰例图⽚(AI.png)如下:
⽰例图⽚ AI.png
我们分以下⼏步进⾏识别:
1. 识别表格中的横线,即分割记录(每⼀⾏)的横线;
2. 识别表格中的竖线,即每个列的分割线;
3. 到数据所在的单元格;
4. 利⽤pyteressact识别单元格的⽂字。
识别表格中的横线
识别横线之前,我们先创建⼀个图⽚表格识别类(ImageTableOCR),如下:
# -*- coding: utf-8 -*-
import cv2
import pytesseract
import numpy as np
class ImageTableOCR(object):
# 初始化
def __init__(self, ImagePath):
# 读取图⽚
self.image = cv2.imread(ImagePath, 1)
# 把图⽚转换为灰度模式
其中self.image为RGB模块的图⽚,ay为灰度模式的图⽚。
接下来,我们识别图⽚中的分割两条记录的横线。注意到,相邻两条记录之间的颜⾊是不⼀致的,因此,我们利⽤图⽚灰度化后,每⼀⾏像素的平均值的差的绝对值来作为相邻两条记录的分割线,这样就能检测出分割两条记录的横线了。具体的识别横线的函数的Python代码如下:(接以上代码)
# 横向直线检测
def HorizontalLineDetect(self):
# 图像⼆值化
ret, thresh1 = cv2.ay, 240, 255, cv2.THRESH_BINARY)
# 进⾏两次中值滤波
blur = dianBlur(thresh1, 3) # 模板⼤⼩3*3
blur = dianBlur(blur, 3) # 模板⼤⼩3*3
h, w = ay.shape
# 横向直线列表
horizontal_lines = []
for i in range(h - 1):
# 到两条记录的分隔线段,以相邻两⾏的平均像素差⼤于120为标准
if an(blur[i, :]) - np.mean(blur[i + 1, :])) > 120:
# 在图像上绘制线段
horizontal_lines.append([0, i, w, i])
cv2.line(self.image, (0, i), (w, i), (0, 255, 0), 2)
horizontal_lines = horizontal_lines[1:]
# print(horizontal_lines)
return horizontal_lines
⾸先对图⽚进⾏⼆值化处理,再进⾏两次中值滤波,这样是为了使相邻两条记录之间的像素区别尽可能⼤。然后对该图⽚中的每⼀⾏的像素进⾏检测,以相邻两⾏的平均像素差⼤于120为标准,识别出分割两条记录的横线。识别后的横线如下:(图⽚中的绿⾊线段)
识别横线后的图⽚
识别表格中的竖线
在这⼀步中,我们利⽤opencv中的Hough直线检测⽅法来检测图⽚中的竖线。完整的Python代码如下:(接以上代码)
# 纵向直线检测
def VerticalLineDetect(self):
# Canny边缘检测
edges = cv2.ay, 30, 240)
# Hough直线检测
minLineLength = 500
maxLineGap = 30
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap).tolist()
lines.append([[13, 937, 13, 102]])
lines.append([[756, 937, 756, 102]])
sorted_lines = sorted(lines, key=lambda x: x[0])
# 纵向直线列表
vertical_lines = []
for line in sorted_lines:
for x1, y1, x2, y2 in line:
# 在图⽚上绘制纵向直线
if x1 == x2:
print(line)
vertical_lines.append((x1, y1, x2, y2))
cv2.line(self.image, (x1, y1), (x2, y2), (0, 0, 255), 2)
return vertical_lines
⾸先我们对灰度图⽚进⾏Canny边缘检测,在此基础上再利⽤Hough直线检测⽅法识别图⽚中的直线,要求识别的最⼤间距为30,线段长度最⼩为500,并且为竖直直线(x1 == x2),当然,也有⼀些⼈为的因素,那就是笔者⾃⼰添加了两条竖直直线([[13, 937, 13, 102]],[[756, 937, 756, 102]])。运⾏上述⽅法,输出的结果如下:
[[13, 937, 13, 102]]
[[75, 937, 75, 102]]
[[77, 937, 77, 102]]
[[270, 937, 270, 104]]
[[272, 937, 272, 102]]
[[756, 937, 756, 102]]
识别竖直直线后的图⽚如下:(图⽚中的红⾊线段)
识别竖线后的图⽚
可以看到,图⽚六条竖直的线段都已经完整标记出来了。
识别图⽚中的单元格
在识别图⽚中的单元格之前,我们先来识别每个单元格所在的顶点,也就是上述识别后的横线
与竖线的交点。完整的Python代码如下:(接以上代码)
# 顶点检测
def VertexDetect(self):
vertical_lines = self.VerticalLineDetect()
horizontal_lines = self.HorizontalLineDetect()
# 顶点列表
vertex = []
for v_line in vertical_lines:
for h_line in horizontal_lines:
vertex.append((v_line[0], h_line[1]))
#print(vertex)
# 绘制顶点
for point in vertex:
cv2.circle(self.image, point, 1, (255, 0, 0), 2)
return vertex
顶点检测后的图⽚如下:(图⽚中的蓝⾊点即为每个单元格的顶点)
顶点检测后的图⽚
vertical怎么读由此可见,我们识别出来的单元格的顶点是正确的。接着,我们把这些单元格取出来,代码如下:(接以上代码)
# 寻单元格区域
def CellDetect(self):
vertical_lines = self.VerticalLineDetect()
horizontal_lines = self.HorizontalLineDetect()
# 顶点列表
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论