写在前面

文档扫描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工具包,具体安装方法总结如下:

  1. 打开网址https://digi.bib.uni-mannheim.de/tesseract/进行下载(打不开就科学上网)。
  2. 配置环境变量如E:\Program Files (x86)\Tesseract-OCR(此为安装目录)。
  3. tesseract -v进行测试,tesseract XXX.png 得到结果 。
  4. 打开prompt进入相应环境中输入pip install pytesseract
  5. 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:转载请标明原文出处!

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐