【Opencv图像处理之文档扫描OCR识别】
本文识别案例图片如下图。这个过程中涉及图像预处理、边缘检测、透视变换等,后续章节中将对OCR的整个过程进行概述。编辑环境:Python 3.6.3 + Opencv 3.4.1.15 + Pycharmps:转载请标明原文出处!
写在前面
文档扫描OCR识别所要做的工作为将将印刷或手写文档(如下图)转换为可编辑、可搜索的文本,从而方便用户对文本的编辑、存储和共享。
本文识别案例图片如下图。这个过程中涉及图像预处理、边缘检测、透视变换等,后续章节中将对OCR的整个过程进行概述。
编辑环境:Python 3.6.3 + Opencv 3.4.1.15 + Pycharm
ps:转载请标明原文出处!
1 图像的读入与预处理
1.1 参数的定义
所用ID为pycharm,为方便对不同图片进行OCR识别,引入argparse模块来定义参数,代码如下。其中,add_argument中required需定义为True值方可在Edit Configuration Settings 界面进行修改,代码下方即为定义方法(将红色划线部分修改为OCR识别对象图像即可)。
ag = argparse.ArgumentParser()
ag.add_argument('-i', '--image', required=True, help='Path to the image to be scanned')
args = vars(ag.parse_args())
1.2 图像获取
定义完参数后,需从args中获取图像,代码如下。
img = cv2.imread(args['image'])
img_resized = resize(img, height=500)
cv_show(img_resized)
resize封装函数如下,进行resize操作仅仅因为原图较大,笔记本显示不全,将其转换一下后能看到所有图像。
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
if width is None and height is None:
return image
elif width is None and height is not None:
r = height/float(h)
dim = (int(r*w), height)
else:
r = width/float(w)
dim = (int(r*h), width)
# interpolation表示插值方法
resized = cv2.resize(image, dim, interpolation=inter)
return resized
1.3 图像预处理
为提高轮廓检测的精确度,需对图像进行预处理,预处理步骤不固定,以最后结果最佳为准。本文依次采用灰度化处理、高斯滤波、边缘检测,得到下图。
img_resized_gray = cv2.cvtColor(img_resized, cv2.COLOR_BGR2GRAY) # 转为灰度图
img_resized_gray = cv2.GaussianBlur(img_resized_gray, (5, 5), 0) # 高斯滤波
edged = cv2.Canny(img_resized_gray, 75, 200)
cv_show(edged)
2 轮廓检测
为得到透视变换的处理范围,需得到图像中纸张的轮廓,此时用到轮廓检测技术。
cnt = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
代码较简单,列在上面了。需注意的是,cnt是一个包含多个轮廓的列表,要得到最外面的轮廓,还需进一步操作。操作方法也较简单,先通过cv2.contourArea函数对轮廓进行面积排序,从大到小排列,取前五个(面积最大的五个)轮廓。再对每个轮廓进行多边形逼近,以得到一个边数较少的近似多边形approx。最后只保留边数为4的多边形即为我们所需要的轮廓。
cnt = sorted(cnt, key=cv2.contourArea, reverse=True)[:5] # 5也不是固定的,万一有干扰项
for c in cnt:
epsilon = 0.02*cv2.arcLength(c, closed=True)
approx = cv2.approxPolyDP(c, epsilon, closed=True)
if len(approx)== 4:
scanCnt = approx
break
效果如下
3 透视变换
透视变换采用4点变换技术,首先得到矩形外轮廓4角点的坐标,再计算出矩形的两条宽和两条长的相对长度,将较长的长和宽的数值赋予转换后的矩形边框。最后用cv2.warpPerspective函数完成转换。
为方便代码书写,采用封装函数形式完成透视变换。
ratio = img.shape[0] / 500.0
warped = fout_point_transform(originate, scanCnt.reshape(4, 2)*ratio)
相关封装函数定义如下。
def orderpoint(pst):
# 计算四个角的坐标
res = np.zeros((4, 2), dtype='float32')
sum_1 = np.sum(pst, axis=1)
res[0] = pst[np.argmin(sum_1)]
res[2] = pst[np.argmax(sum_1)]
diff_1 = np.diff(pst, axis=1)
res[1] = pst[np.argmin(diff_1)]
res[3] = pst[np.argmax(diff_1)]
return res
def fout_point_transform(image,pst):
# 获得4个角的坐标
edge_point = orderpoint(pst)
(tl, tr, br, bl) = edge_point
width1 = np.sqrt((tl[0] - tr[0])**2 + (tl[1] - tr[1])**2)
width2 = np.sqrt((bl[0] - br[0])**2 + (bl[1] - br[1])**2)
max_width = max(int(width1), int(width2))
length1 = np.sqrt((tl[0] - bl[0])**2 + (tl[1] - bl[1])**2)
length2 = np.sqrt((tr[0] - br[0])**2 + (tr[1] - br[1])**2)
max_length = max(int(length1), int(length2))
distance = np.array([
[0, 0],
[max_width-1, 0],
[max_width-1, max_length-1],
[0, max_length-1]], dtype='float32')
m = cv2.getPerspectiveTransform(edge_point, distance)
warped = cv2.warpPerspective(image, m, (max_width, max_length))
return warped
转换效果如下,将不同角度的图像转换为正视图。
4 保存图像
透视变换后,对图像进行保存操作以便进行文本识别任务。保存前,为提高精确度,对图像进行二值化处理,再用imwrite函数进行保存操作。
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1]
cv_show(warped)
cv2.imwrite('scan.jpg', ref)
5 文本识别
文本识别前,需要安装一下pytesseract工具包,具体安装方法总结如下:
- 打开网址https://digi.bib.uni-mannheim.de/tesseract/进行下载(打不开就科学上网)。
- 配置环境变量如E:\Program Files (x86)\Tesseract-OCR(此为安装目录)。
- tesseract -v进行测试,tesseract XXX.png 得到结果 。
- 打开prompt进入相应环境中输入pip install pytesseract
- tesseract_cmd 修改为绝对路径即可
安装完成后,即可进行文本识别工作,剩下的就比较简单了,直接上代码。
from PIL import Image
import pytesseract
import cv2
import os
image = cv2.imread('scan.jpg')
# 预处理操作与之前一样
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 3)
text = pytesseract.image_to_string(Image.open(filename))
print(text)
最终结果如下:
效果还是不错的!
6 结语
该任务为学习时练手任务,适合小白上手,欢迎各位大佬交流!!关注博主私聊即可获得全套源码!
ps:转载请标明原文出处!
更多推荐
所有评论(0)