前言
偶尔整理笔记,发现两三年前写的纯用opencv实现发票图片中的表格检测的笔记。虽然现在已经是深度学习网络的天下,但是回头看看过去的探索,感觉还是有点意思的,主要用来给我自己做个笔记备份,同时分享给踏入图像的初学者们呀~
0 简介
ocr的识别基本实现了通用识别功能之后,还需要实现发票、户口本等的识别,但是想要实现发票等有表格的文件的识别,还需要额外的处理。因为传统的文字框检测工具yolo会将一行文字一起识别。而发票这类表格数据,即使在同一行中,也因为竖线的划分,所以并不能认为是一行是一体的。
对于这种问题,我的思路就是首先将图片按照表格拆分成子图,然后将每个子图放入后续的文字识别框架单独识别,最后将所有的结果整合之后返回给用户。加上前前后后的处理过程,大致可以分为如下几步:
- 判断图片是否需要大角度旋转(90,180,270)
- 判断是否需要小角度的旋转,保证横线的水平
- 使用opencv对表格的小矩形框进行提取
- 对表格以外的区域进行划分(如上图所示)
- 将所有的子图送入ocr模型进行检测
- 拼接结果
这里主要介绍一下在进行2,3,4图像处理过程中使用的函数工具以及部分拓展阅读。先列出对我帮助非常大的文章
- 要点初见:Python+OpenCV校正并提取表格中的各个框
- OpenCV—python 图像矫正(基于傅里叶变换—基于透视变换)
- python 图片中的表格识别
- OpenCV—Python 表格提取
- OpenCV—python 形态学处理(腐蚀、膨胀、开闭运算、边缘检测)
1 判断是否需要小角度的旋转
发票中有很多的横线,使用Canny函数获取轮廓+霍夫函数获取直线(这基本上是一个组合拳),然后可以根据这些横线的斜率的均值来确定图像是否有倾斜,以及倾斜之后需要旋转的角度。然后以图像的左下角为坐标中心,完成旋转工作。
import cv2
import numpy as np
import pytesseract
import cv2 as cv
import math
image = cv2.imread('C:\\Users\\14192\\Desktop\\7.jpg', 1)
# 灰度图片
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 50, 150, apertureSize=3) # 50,150,3
cv.imwrite('test_3\\edges_whole.jpg', edges)
lines = cv.HoughLinesP(edges, 1, np.pi / 180, 500, 0, minLineLength=50, maxLineGap=50) # 650,50,20
print("一共检测到{}条直线".format(len(lines)))
pi = 3.1415
theta_total = 0
theta_count = 0
for line in lines:
x1, y1, x2, y2 = line[0]
rho = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
theta = math.atan(float(y2 - y1) / float(x2 - x1 + 0.001))
print(rho, theta, x1, y1, x2, y2)
if theta < pi / 4 and theta > -pi / 4:
theta_total = theta_total + theta
theta_count += 1
cv.line(image_copy, (x1, y1), (x2, y2), (0, 0, 255), 2)
# cv.line(edges, (x1, y1), (x2, y2), (0, 0, 0), 2)
theta_average = theta_total / theta_count
print(theta_average, theta_average * 180 / pi)
cv.imwrite('test_3\\line_detect4rotation.jpg', image_copy)
affineShrinkTranslationRotation = cv.getRotationMatrix2D((0, rows), theta_average * 180 / pi, 1)
gray = cv.wa