OpenCV OCR实战 文档扫描与文字检测

本文讲述使用OpenCV- python以及easyocr库实现文档扫描与文字检测的思路和具体实现过程。

内容

知识准备

项目概况

实施过程

代码说明

1.读入图片并进行预处理(灰度转换,高斯滤波)

2.对图片进行canny边缘检测,进一步处理

3.轮廓识别,轮廓排序,轮廓近似得到最外层轮廓角点

4.仿射变换,二值处理

5.文字识别

知识准备

本项目需要以下知识:

1.OpenCV图像基础操作,如读取,灰度转换等

2.阈值操作,如二值化

3.canny边缘检测以及boundingBox构建

4.卷积核构建

5.膨胀操作

6.形态学操作如close操作

7.用pyplot查看图片,便于debug

8.高斯滤波

9.easyocr库函数调用

10.仿射变换

项目概况

本项目旨在实现倾斜文档的自动扫描和文本检测

给定的测试图像如下

OpenCV OCR实战 文档扫描与文字检测

达到如图所示的最终效果

OpenCV OCR实战 文档扫描与文字检测

实施过程

1.读入图片并进行预处理(灰度转换,高斯滤波)

2.对图片进行canny边缘检测,进一步处理

3.轮廓识别,轮廓排序,轮廓近似得到最外层轮廓角点

4.仿射变换,二值处理

5.文字识别

代码说明

1.读入图片并进行预处理(灰度转换,高斯滤波)

import math

import cv2
import easyocr
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('bill.png')
img_gray = cv2.imread('bill.png', 0)
# show('result', img)
# show('res', img_gray)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
# show('gauss', img_blur)

本段代码实现了图片的读取和灰度转换,并按照一个5*5的卷积核进行高斯滤波操作。高斯滤波的意义在于滤除图像中的噪声点,有利于在提取边界时获得更准确有用的信息。

2.对图片进行canny边缘检测,进一步处理

edges = cv2.Canny(img_blur, 50, 200)
# show('canny', edges)
kernel = np.ones((2, 2), np.uint8)
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
edges_close = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, rectKernel)
edges_dilate = cv2.dilate(edges_close, kernel, iterations=3)
# show('dilate', edges_dilate)

# show('close', edges_close)
# show('dilate', edges_dilate)

本段代码对滤波之后的图片实施了canny边缘检测,构建了一个2*2的卷积核并执行了闭操作和膨胀操作。

canny后的结果如图

OpenCV OCR实战 文档扫描与文字检测

关闭操作结果

OpenCV OCR实战 文档扫描与文字检测

膨胀运算结果

OpenCV OCR实战 文档扫描与文字检测

可以看出,只进行一次Canny之后图片的边界信息都完整地呈现了出来,但由于我们下一步需要筛选出最外层边界,过多的边界信息会对筛选造成困难,所以加以闭操作和膨胀操作。闭操作使得文字的边界连在了一起,减少了边界的数量,增加了筛选的可靠性。膨胀操作使得边界变粗,增加了轮廓识别的可靠性。

3.轮廓识别,轮廓排序,轮廓近似得到最外层轮廓角点

contours, hierarchy = cv2.findContours(edges_dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours = sorted(contours, key=lambda cnts: cv2.arcLength(cnts, True), reverse=True)

img_copy = img.copy()
res = cv2.drawContours(img_copy, contours, 0, (0, 0, 255), 2)
# show('res', res)
img_copy = img.copy()
cnt = contours[0]
epsilon = 0.03 * cv2.arcLength(cnt, True)  # epsilon占周长的比例
approx = cv2.approxPolyDP(cnt, epsilon, True)
res2 = cv2.drawContours(img_copy, [approx], -1, (0, 0, 255), 5)
# print(approx)
# show('res2', res2)
[[lt], [lb], [rb], [rt]] = approx
# print(lt, lb, rb, rt)
[ltx, lty] = lt
[lbx, lby] = lb
[rbx, rby] = rb
[rtx, rty] = rt
# print(ltx, lty, lbx, lby, rbx, rby, rtx, rty)
lt = (ltx, lty)
lb = (lbx, lby)
rb = (rbx, rby)
rt = (rtx, rty)
# print(lt, lb, rb, rt)

这段代码实现了轮廓检测,将所有检测到的轮廓按长度排序,找到长度最长的轮廓(车票的外边界),逼近这个轮廓,得到一个矩形,得到它的四个角点的坐标,准备下一个仿射变换。

cnt画在原图中的效果如下:

OpenCV OCR实战 文档扫描与文字检测

4.仿射变换,二值处理

# 仿射变换
width = max(math.sqrt((rtx - ltx) ** 2 + (rty - lty) ** 2), math.sqrt((rbx - lbx) ** 2 + (rby - lby) ** 2))
height = max(math.sqrt((ltx - lbx) ** 2 + (lty - lby) ** 2), math.sqrt((rtx - rbx) ** 2 + (rty - rby) ** 2))
pts1 = np.float32([[ltx, lty], [rtx, rty], [lbx, lby], [rbx, rby]])
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
M = cv2.getPerspectiveTransform(pts1, pts2)
width = int(width)
height = int(height)
dst = cv2.warpPerspective(img, M, (width, height))

plt.subplot(121), plt.imshow(img), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()
print(dst)
resu = cv2.threshold(dst, 120, 255, cv2.THRESH_BINARY)[1]
plt.imshow(resu), plt.title('Result')
plt.show()
cv2.imwrite('OCR.jpg', resu)

这段代码实现了对小票的“摆正”。前两行求出了小票的宽和高,由于之前获得的角点围成的图形不一定是矩形,这里取了对应边长的最大值。pts1和pts2分别表示四个角点在原图中的坐标和其对应目标位置的坐标。M矩阵是原坐标向目标坐标的变换矩阵,这里可以通过cv自带的getPerspectiveTransform方法计算得出。最后通过warpPerspective方法将M与原图片相乘得到目标图片,另外还进行了二值化处理,保存,以便下一步进行OCR。

运行结果如图

OpenCV OCR实战 文档扫描与文字检测

5.文字识别

# ocr
# 创建reader对象

reader = easyocr.Reader(['ch_sim', 'en'])

# 读取图像

result = reader.readtext('OCR.jpg')
print(result)
for i in result:
    print(i[1])

这段代码调用了easyocr里的方法进行OCR,由于result列表的特殊结构,文字被储存在了每个列表元素的第二项。

运行结果

OpenCV OCR实战 文档扫描与文字检测

可以看出easyocr库对中文的支持度还是比较差的,但是基本达到了我们的目的。读者可以通过使用其他的OCR库来达到更高的识别成功率。另外,还可以对仿射变换后的图片进行更加优化的图形学处理来达到更好的效果。

此外,easyocr库需要利用CUDA来实现GPU加速,由于笔者使用的电脑为M1Pro芯片,并非nvadia显卡,故无法使用CUDA,而用CPU跑这段代码需要花一些时间,请大家务必注意。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2022年3月27日 下午2:44
下一篇 2022年3月27日

相关推荐