项目实践-文档扫描OCR识别

这次我们将使用OCR进行实战。

我们将使用示例图像:

                                              

首先我们需要安装tesserocr

在Windows下安装tessocr,首先需要下载tesseract,它为tesserocr提供了支持。

进入下载页面,可以看到有各种.exe文件的下载列表:

其中文件名中带有dev的为开发版本,不带dev的为稳定版本,可以选择下载不带dev的版本,需要安装 “tesseract-ocr-w64-setup-v4.0.0-beta.1.20180608.exe”,因为要与 tesserocr-2.2.2 匹配。

下载完成后双击,一路next:

此时可以勾选Additional language data(download)选项来安装OCR识别支持的语言包,这样OCR便可以识别多国语言。然后一路点击Next按钮即可。

去系统环境变量Path里添加OCR的环境变量如E:\Program Files (x86)\Tesseract-OCR

接下来,再安装tesserocr即可,此时直接使用pip安装:

pip install pytesseract

检测流程:

边缘检测 -> 获得轮廓 -> ****变换(即放平,包括平移旋转反转等) -> OCR识别。

这些原理我们之前都讲过,就不在过多阐述了。

边缘检测

if __name__ == “__main__”:  

      # 读取输入  

      image = .imread(args[“image”])  

      # resize 坐标也会相同变化  

      ratio = image.shape[0] / 500.0  

      orig = image.copy()  

   

      image = resize(orig, height = 500) # 同比例变化:h指定500,w也会跟着变化  

   

      # 预处理  

      gray = .cvtColor(image, .COLOR_BGR2GRAY)  

      gray = .GaussianBlur(gray, (5, 5), 0)  

      edged = .Canny(gray, 75, 200)  # 边缘检测  

   

      # 展示预处理结果  

      print(“STEP 1: 边缘检测”)  

      .imshow(“Image”, image)  

      .imshow(“Edged”, edged)  

      .waitKey(0)  

      .destroyAllWindows()  

获得轮廓

   # 轮廓检测  

      cnts = .findContours(edged.copy(), .RETR_LIST, .CHAIN_APPROX_SIMPLE)[0]  

      # cnts中可检测到许多个轮廓,取前5个最大面积的轮廓  

      cnts = sorted(cnts, key = .contourArea, reverse = True)[:5]  

   

      # 遍历轮廓  

      for c in cnts: # C表示输入的点集  

             # 计算轮廓近似  

             peri = .arcLength(c, True)  

             # epsilon表示从原始轮廓到近似轮廓的最大距离,它是一个准确度参数  

             # True表示封闭的  

             approx = .approxPolyDP(c, 0.02 * peri, True)  

             print(approx,approx.shape)  

             # 4个点的时候就拿出来,screenCnt是这4个点的坐标  

             if len(approx) == 4:   # 近似轮廓得到4个点,意味着可能得到的是矩形  

                    screenCnt = approx    # 并且最大的那个轮廓是很有可能图像的最大外围  

                    break  

   

      # 展示结果  

      print(“STEP 2: 获取轮廓”)  

      .drawContours(image, [screenCnt], -1, (0, 255, 0), 2)  

      .imshow(“Outline”, image)  

      .waitKey(0)  

      .destroyAllWindows()  

****变换

  

    # ****变换  

      # 4个点的坐标 即4个(x,y),故reshape(4,2)  

      # 坐标是在变换后的图上得到,要还原到原始的原图上,需要用到ratio  

      print(screenCnt.shape)  

      warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)  

同一个py文件中,在main函数前,****变换函数 four_point_transform:  

def order_points(pts):  

      # 初始化4个坐标点的矩阵  

      rect = np.zeros((4, 2), dtype = “float32”)  

   

      # 按顺序找到对应坐标0123分别是 左上,右上,右下,左下  

      # 计算左上,右下  

      print(“pts :\n “,pts)  

      s = pts.sum(axis = 1)         # 沿着指定轴计算第N维的总和  

      print(“s : \n”,s)  

      rect[0] = pts[np.argmin(s)]       # 即pts[1]  

      rect[2] = pts[np.argmax(s)]      # 即pts[3]  

      print(“第一次rect : \n”,rect)  

      # 计算右上和左下  

      diff = np.diff(pts, axis = 1)      # 沿着指定轴计算第N维的离散差值  

      print(“diff : \n”,diff)  

      rect[1] = pts[np.argmin(diff)]   # 即pts[0]  

      rect[3] = pts[np.argmax(diff)]  # 即pts[2]  

      print(“第二次rect :\n “,rect)  

      return rect  

   

def four_point_transform(image, pts):  

      # 获取输入坐标点  

      rect = order_points(pts)  

      (A, B, C, D) = rect  

      # (tl, tr, br, bl) = rect  

   

      # 计算输入的w和h值  

      w1 = np.sqrt(((C[0] – D[0]) ** 2) + ((C[1] – D[1]) ** 2))  

      w2 = np.sqrt(((B[0] – A[0]) ** 2) + ((B[1] – A[1]) ** 2))  

      w = max(int(w1), int(w2))  

   

      h1 = np.sqrt(((B[0] – C[0]) ** 2) + ((B[1] – C[1]) ** 2))  

      h2 = np.sqrt(((A[0] – D[0]) ** 2) + ((A[1] – D[1]) ** 2))  

      h = max(int(h1), int(h2))  

   

      # 变换后对应坐标位置  

      dst = np.array([    # 目标点  

             [0, 0],  

             [w – 1, 0],     # 防止出错,-1  

             [w – 1, h – 1],  

             [0, h – 1]], dtype = “float32”)  

   

      # 计算变换矩阵       (平移+旋转+翻转),其中  

      M = .getPerspectiveTransform(rect, dst)       # (原坐标,目标坐标)  

      print(M,M.shape)  

      warped = .warpPerspective(image, M, (w, h))  

   

      # 返回变换后结果  

      return warped  

接下来可以直接进行识别了,我们来看所有的代码:

  导入工具包  

 import numpy as np  

 import argparse  

 import   

 import pytesseract  

 from PIL import Image  

   

   

 def order_points(pts):  

    #   一共  4  个坐标点  

    rect = np.zeros((4, 2), dtype = “float32”)  

   

    #   按顺序找到对应坐标  0123  分别是  左上,右上,右下,左下  

    #   计算左上,右下  

    s = pts.sum(axis = 1)  

    rect[0] = pts[np.argmin(s)]  

    rect[2] = pts[np.argmax(s)]  

   

    #   计算右上和左下  

    diff = np.diff(pts, axis = 1)  

    rect[1] = pts[np.argmin(diff)]  

    rect[3] = pts[np.argmax(diff)]  

   

    return rect  

   

 def four_point_transform(image, pts):  

    #   获取输入坐标点  

    rect = order_points(pts)  

    (tl, tr, br, bl) = rect  

   

    #   计算输入的  w  和  h  值  

    widthA = np.sqrt(((br[0] – bl[0]) ** 2) + ((br[1] – bl[1]) ** 2))  

    widthB = np.sqrt(((tr[0] – tl[0]) ** 2) + ((tr[1] – tl[1]) ** 2))  

    maxWidth = max(int(widthA), int(widthB))  

   

    heightA = np.sqrt(((tr[0] – br[0]) ** 2) + ((tr[1] – br[1]) ** 2))  

    heightB = np.sqrt(((tl[0] – bl[0]) ** 2) + ((tl[1] – bl[1]) ** 2))  

    maxHeight = max(int(heightA), int(heightB))  

   

    #   变换后对应坐标位置  

    dst = np.array([  

       [0, 0],  

       [maxWidth – 1, 0],  

       [maxWidth – 1, maxHeight – 1],  

       [0, maxHeight – 1]], dtype = “float32”)  

   

    #   计算变换矩阵  

    M = .getPerspectiveTransform(rect, dst)  

    warped = .warpPerspective(image, M, (maxWidth, maxHeight))  

   

    #   返回变换后结果  

    return warped  

   

 def resize(image, width=None, height=None, inter=.INTER_AREA):  

    dim = None  

    (h, w) = image.shape[:2]  

    if width is None and height is None:  

       return image  

    if width is None:  

       r = height / float(h)  

       dim = (int(w * r), height)  

    else:  

       r = width / float(w)  

       dim = (width, int(h * r))  

    resized = .resize(image, dim, interpolation=inter)  

    return resized  

   

 #   读取输入  

 image = .imread(“images/page.jpg”)  

 #  坐标也会相同变化  

 ratio = image.shape[0] / 500.0  

 orig = image.copy()  

   

   

 image = resize(orig, height = 500)  

   

 #   预处理  

 gray = .cvtColor(image, .COLOR_BGR2GRAY)  

 gray = .GaussianBlur(gray, (5, 5), 0)  

 edged = .Canny(gray, 75, 200)  

   

 #   展示预处理结果  

 print(“STEP 1:   边缘检测  “)  

 .imshow(“Image”, image)  

 .imshow(“Edged”, edged)  

 .waitKey(0)  

 .destroyAllWindows()  

   

 #   轮廓检测  

 cnts = .findContours(edged.copy(), .RETR_LIST, .CHAIN_APPROX_SIMPLE)[0]  

 cnts = sorted(cnts, key = .contourArea, reverse = True)[:5]  

   

 #   遍历轮廓  

 for c in cnts:  

    #   计算轮廓近似  

    peri = .arcLength(c, True)  

    # C  表示输入的点集  

    # epsilon  表示从原始轮廓到近似轮廓的最大距离,它是一个准确度参数  

    # True  表示封闭的  

    approx = .approxPolyDP(c, 0.02 * peri, True)  

   

    # 4  个点的时候就拿出来  

    if len(approx) == 4:  

       screenCnt = approx  

       break  

   

 #   展示结果  

 print(“STEP 2:   获取轮廓  “)  

 .drawContours(image, [screenCnt], -1, (0, 255, 0), 2)  

 .imshow(“Outline”, image)  

 .waitKey(0)  

 .destroyAllWindows()  

   

 #   ****变换  

 warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)  

   

 #   二值处理  

 warped = .cvtColor(warped, .COLOR_BGR2GRAY)  

 ref = .threshold(warped, 100, 255, .THRESH_BINARY)[1]  

 #   展示结果  

 print(“STEP 3:   变换  “)  

 text = pytesseract.image_to_string(ref)  

 print(text)  

 .imshow(“Original”, resize(orig, height = 650))  

 .imshow(“Scanned”, resize(ref, height = 650))  

 .waitKey(0)  

可以看到最终的OCR识别结果:

更多openvino技术信息可以入群交流〜                                           

OpenVINO技术交流群QQ223824636               

申请时备注:B站

资源下载: