基于python-opencv的CV2实现图片OCR前的扫描摆正OCR识别【代码实现】

  • 实验目的
  • 代码实现
  • 预处理(注意Resize图像)
  • 轮廓检测(找到矩形)
  • 透视变换(摆正图像)
  • OCR识别文字
  • 实验结果
  • 发票图片
  • 自己随便拍的图片


实验目的

本实验的目的主要是实现诸如发票,pdf扫描成的图片,如何可以实现找到发票(这里都用发票指代了)外轮廓,把桌面等信息消除,直接将发票清晰摆正呈现,方便后续的OCR识别。
2.本次实验的重点在于预处理-找到外轮廓外接矩形-透视变换摆正图片,最终的OCR扫描可以参考我的博客【Python】图像文字识别:从图片中识别出文字(Pytesseract安装配置与使用),以前已经实现过,就不赘述。用百度API也可以,效果会更好,也已经实现。

主要想讲的是图1到图2过程:

好用的python ocr包 python ocr训练_透视变换


好用的python ocr包 python ocr训练_python_02

代码实现

预处理(注意Resize图像)

import cv2
from imutils.perspective import four_point_transform
import pytesseract
import os
from PIL import Image
import argparse
import matplotlib as plt
import numpy as np
# 绘图展示
def cv2_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

image = cv2.imread("D:/check2.jpg")
cv2_show('origin',image)
#ratio = image.shape[0] / 800  # 比例,h除以500,w自行计算
#print(ratio)
orig = image.copy()  # copy()不对原图改变
#500是设置的h为500,(int(image.shape[1]/ratio))为变化后的w,(h,w)
# resize_image = cv2.resize(orig, (800,int(image.shape[1]/ratio)))
resize_image = cv2.resize(orig, None,fx=0.2,fy=0.2)
# 想用原图直接注释上一条用下一条即可
# resize_image=image.copy()
cv2_show('resize',resize_image)

# 预处理操作
gray = cv2.cvtColor(resize_image, cv2.COLOR_BGR2GRAY)
cv2_show('gray',gray)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
cv2_show('GaussianBlur',gray)
edged = cv2.Canny(gray, 75, 200)

原图太大,现需要resize:

好用的python ocr包 python ocr训练_python_03


灰度:

好用的python ocr包 python ocr训练_python_04


高斯:

好用的python ocr包 python ocr训练_python_05


!!!!这里需要注意Resize时候:!!!!

resize图片时候比例不要用设置好的一个值,比如定好h是500,则:

ratio = image.shape[0] / 500  # 比例,原图h除以想要的500则是比例
print(ratio)
orig = image.copy()  # copy()不对原图改变
#500是设置的h为500,(int(image.shape[1]/ratio))为变化后的w,(h,w)
#resize(原图,(设置的想要的h,设置的相应比例变化的高))
resize_image = cv2.resize(orig, (500,int(image.shape[1]/ratio)))

这样可以,但是在后面轮廓划定,透视变化摆正图像时(如下面代码),会出现倾斜情况:

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

好用的python ocr包 python ocr训练_python_06


因此resize图片时候比例我们直接设置比例,不用ratio值:

resize_image = cv2.resize(orig, None,fx=0.2,fy=0.2)
#意为w,h缩小为原来5倍

后面透视变换摆正图像时候直接乘以1/fx即可(此处5倍):

wraped = four_point_transform(orig, screenCnt.reshape(4, 2)*5)

轮廓检测(找到矩形)

重点是近似计算找轮廓!!!
approx=cv2.approxPolyDP(c, 0.02* peri, True) # 检测出来的轮廓可能是离散的点,故因在此做近似计算,使其形成一个矩形。做精度控制,原始轮廓到近似轮廓的最大的距离,较小时可能为多边形;较大时可能为矩形。
这里的值如果太小,比如0.0002等,可能近似轮廓是多边形,不是矩形,因此选择0,02即可。
注意:对于findContours:
cnts可能有几百个轮廓,里面的各种字都会被圈出来,一般外围轮廓是最大,所以直接进行排序,再从里面找,会更简单。

cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]  # 将轮廓按照面积的大小进行排序,并且选出前5个中最大的轮廓

刚开始不知道,所有的在一起找,由于精度问题没太懂,就浪费了很多时间找外围轮廓。

上代码:

# 轮廓检测
cnts, hierancy = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 找出图像中的轮廓
# cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]  # 将轮廓按照面积的大小进行排序,并且选出前5个中最大的轮廓,当多个小票时
print('cnts',len(cnts))

for c in cnts:
    peri = cv2.arcLength(c, True)  # 周长,闭合
    # print(peri)
    approx=cv2.approxPolyDP(c, 0.02* peri, True)  # 检测出来的轮廓可能是离散的点,故因在此做近似计算,使其形成一个矩形
    # 做精度控制,原始轮廓到近似轮廓的最大的距离,较小时可能为多边形;较大时可能为矩形
    # True表示闭合
    if len(approx)==4:  # 如果检测出来的是矩形,则break本段if
        screenCnt = approx
        print(len(approx))

image=resize_image.copy()
cv2.drawContours(image, [screenCnt], -1, (0, 0, 255), 2)  # 绘制轮廓,-1表示全部绘制
cv2_show('contour', image)

好用的python ocr包 python ocr训练_计算机视觉_07

透视变换(摆正图像)

重点是:four_point_transform(resize_image, screenCnt.reshape(4, 2))
这个函数导入包即可

from imutils.perspective import four_point_transform

代码:

# 变换
# 透视变换:摆正图像内容
# wraped = four_point_transform(resize_image, screenCnt.reshape(4, 2))
# 在原图上改
wraped = four_point_transform(orig, screenCnt.reshape(4, 2)*5)
cv2_show('wrap',wraped)
wraped = cv2.cvtColor(wraped, cv2.COLOR_BGR2GRAY)
cv2_show('wrap2',wraped)
ref = cv2.threshold(wraped, 100, 255, cv2.THRESH_BINARY)[1]
cv2_show('ref',ref)
# ref=cv2.resize(ref,None,fx=0.3,fy=0.3)
cv2.imwrite("d:/test.jpg", ref)  
# 必须加后缀名,把完成摆正的图片保存下来用于后续识别

这里需要注意:如果是在resize后的图上操作可能最终会出现摆正后图像也不清楚的状态,如下所示。

在resize图上对检测后轮廓进行透视变换:

好用的python ocr包 python ocr训练_python_08

因此我们需要对原图进行处理,前面说过,我们已经对原图进行resize时fx=0.2,fy=0.2,缩小了5倍,这里只需要(在原图上,后面对选中轮廓区域点进行乘以1/fx倍)即可:

four_point_transform(original_image, screenCnt.reshape(4, 2)5)*

最终效果好,如下图。

在原图上对检测后轮廓进行透视变换:

好用的python ocr包 python ocr训练_python_09


原图完胜!!!ヽ(・ω・´メ)灰度:

好用的python ocr包 python ocr训练_透视变换_10


二值后即可用于识别:

好用的python ocr包 python ocr训练_好用的python ocr包_11

OCR识别文字

十分简单,但pytesseract的安装可能会有各种问题,参照这篇博客即可。

import pytesseract
text = pytesseract.image_to_string(Image.open(filename))  # 转化成文本

实验结果

发票图片

resize后的原图:

好用的python ocr包 python ocr训练_计算机视觉_12

结果:

好用的python ocr包 python ocr训练_好用的python ocr包_13

自己随便拍的图片

效果也可,记得把原图右旋转一下再做。

原图:

好用的python ocr包 python ocr训练_opencv_14


resize后的图:

好用的python ocr包 python ocr训练_透视变换_15


找到轮廓:

好用的python ocr包 python ocr训练_好用的python ocr包_16


结果:

在原图上做的透视变换:

好用的python ocr包 python ocr训练_python_17


效果还可!

好用的python ocr包 python ocr训练_计算机视觉_18

好用的python ocr包 python ocr训练_opencv_19

----EchoZhang-----03/29-----发现实战解决问题才能真正有点懂某一点的意思!继续抓住3月小尾巴搞搞opencv!-------