Opencv学习(四)OCR识别

什么是OCR识别

OCR是指对文本资料进行扫描后对图像文件进行分析处理,获取文字及版面信息的过程。用Opencv进行OCR识别时,通常分为两步:扫描、识别。

如何进行OCR识别

整体流程

1.读取图像
2.预处理(灰度--二值)
3.边缘检测
4.轮廓检测
5.轮廓近似
6.透视变换
7.OCR识别
8.展示结果

具体实现

Step1:边缘检测

1.读取图像

import cv2
import numpy as np
# 读取输入
image = cv2.imread('receipt.jpg')
#坐标也会相同变化
ratio = image.shape[0] / 500.0
orig = image.copy()
image = resize(orig, height = 500)

将输入的图像resize成高为500的等比例缩小的图像,所以之后所获取的关键点的坐标也是基于resize后的图像得到的,故在这里我们需要先知道图片resize的比例,称为ratio.
同时,为了方便,在这里写了一个函数进行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
    if width is None:
        r=height/float(h)
        dim=(int(w*r),height)
    else:
        r=width/float(w)
        dim=(width,int(h*r))
    
    resized=cv2.resize(image,dim,interpolation=inter)
    return resized

2.预处理

#预处理
#灰度转换
gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
#高斯滤波--去噪点
gray=cv2.GaussianBlur(gray,(5,5),0)

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

imshow("canny",edged);

image

Step2:获取轮廓

#轮廓检测--面积最大的轮廓就是需要的
cnts,hierarchy=cv2.findContours(edged.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnts=sorted(cnts,key=cv2.contourArea,reverse=True)[:5]

#遍历轮廓
for c in cnts:
    #计算轮廓近似
    peri=cv2.arcLength(c,True)
    approx=cv2.approxPolyDP(c,0.02*peri,True)
    
    #4个点的时候就拿出来
    if len(approx)==4:
        screenCnt=approx
        break
#显示结果
print("STEP2:获取轮廓")
cv2.drawContours(image,[screenCnt],-1,(0,0,255),2,LINE_AA)
imshow("outline",image);

image

Step3:透视变换

透视变换的基本原理

首先引入两个函数完成透视变换的操作。
(1)order_points(pts)函数:将上一步得到的轮廓的四个顶点按照左上,右上,右下,左下的顺序排序。
其原理为:首先计算每个点所包含的两个坐标的和,最小的为左上角的点,最大的为右下角的点。然后计算每个点所包含的两个坐标的差,最小的为右上角的点,最大的为左下角的点。

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

(2)four_point_transform(image, pts):透视变换。

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))

    # 变换后对应坐标位置(-1只是为了防止有误差出现,不-1也可以。)
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype = "float32")

    # 计算变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后结果
    return warped
# 透视变换
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
# 二值处理
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('scan.jpg', ref)
# 展示结果
print("STEP 3: 变换")
cv2.imshow("Scanned", ref)
cv2.waitKey(0)

变换后的结果:
image

Step4:OCR识别

1.下载
https://digi.bib.uni-mannheim.de/tesseract/
选择一个版本进行下载

2.安装
下载完成后打开一路next安装完成

3.环境变量配置
将刚刚安装的目录添加到环境变量中
(可以在命令行窗口(cmd)中输入tesseract -v进行测试,会输出版本号。)

4.OCR识别测试
在命令行窗口中输入tesseract scan.jpg result,会将刚才扫描的图片上的信息写入result.txt文件中。

5.在python中实现

  • 5.1 先安装pytesseract---pip install pytesseract
  • 5.2 在库文件夹中找到pytesseract文件夹里的pytesseract.py文件,打开,修改里面tesseract_cmd一行为绝对路径。
    image

6.在python中引入相关的库

from PIL import Image
import pytesseract
import cv2
import os

7.执行识别操作

preprocess = 'blur' #thresh

image = cv2.imread('scan.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

if preprocess == "thresh":
    gray = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

if preprocess == "blur":
    gray = cv2.medianBlur(gray, 3)
    
filename = "{}.png".format(os.getpid())
cv2.imwrite(filename, gray)
    
text = pytesseract.image_to_string(Image.open(filename))
print(text)
os.remove(filename)

8.最终效果
image

完整代码
#ocr_demo.py   输入参数:--image D:\image\paper.jpg
import cv2
import argparse
import numpy as np
import imutils

ap=argparse.ArgumentParser()
ap.add_argument("-i","--image",required=True,help="path to input image")
args=vars(ap.parse_args())

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
    if width is None:
        r=height/float(h)
        dim=(int(w*r),height)
    else:
        r=width/float(w)
        dim=(width,int(h*r))
    
    resized=cv2.resize(image,dim,interpolation=inter)
    return resized

def order_point(pts):
    #一共4个坐标点
    rect=np.zeros((4,2),dtype="float32")
    
    #按顺序找到对应坐标,左上,右上,右下,左下
    #计算左上,右下
    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_point(pts)
    (tl,tr,br,bl)=rect
    
    #计算输入的w和h值
    #w---x的平方+y的平方开根号   取比较大的那个
    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))
    
    #h同理
    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")
    #dst=np.array([[0,0],[500,0],[666,500],[0,666]],dtype="float32")
    #计算变换矩阵
    #2维----3维---2维
    M=cv2.getPerspectiveTransform(rect,dst)
    warped=cv2.warpPerspective(image,M,(maxWidth,maxHeight))
    
    return warped

#读取图片
image=cv2.imread(args["image"])


ratio=image.shape[0]/500.0
orig=image.copy()

image=resize(orig,height=500)


#预处理
gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
gray=cv2.GaussianBlur(gray,(5,5),0)

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

imshow("canny",edged);


#轮廓检测
cnts,hierarchy=cv2.findContours(edged.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnts=sorted(cnts,key=cv2.contourArea,reverse=True)[:5]


#遍历轮廓
for c in cnts:
    #计算轮廓近似
    peri=cv2.arcLength(c,True)
    approx=cv2.approxPolyDP(c,0.02*peri,True)
    
    #4个点的时候就拿出来
    
    if len(approx)==4:
        screenCnt=approx
        break
    
#显示结果
print("STEP2:获取轮廓")
cv2.drawContours(image,[screenCnt],-1,(0,0,255),2,LINE_AA)
imshow("outline",image);

#cv.Circle(img, center, radius, color, thickness=1, lineType=8, shift=0) → None

#透视变换
wraped=four_point_transform(orig,screenCnt.reshape(4,2)*ratio)

#二值处理
wraped=cv2.cvtColor(wraped,cv2.COLOR_RGB2GRAY)
ref=cv2.threshold(wraped,100,255,cv2.THRESH_BINARY)[1]
cv2.imwrite("scan.jpg",ref)

#展示结果
print("STEP3:变换")
imshow("Original",resize(orig,width=500))
imshow("Scanned",ref)
waitKey()
#ocr.py
from PIL import Image
import pytesseract
import cv2
import os
from cv2 import waitKey

preprocess='blur'

image=cv2.imread("scan.jpg")
gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)

if preprocess=="thresh":
    gray=cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    
if preprocess=="blur":
    gray=cv2.medianBlur(gray,3)
    
filename="{}.png".format(os.getpid())
cv2.imwrite(filename,gray)

text=pytesseract.image_to_string(Image.open(filename))

print(text)
os.remove(filename)

cv2.imshow("Image",image)
cv2.imshow("output",gray)

waitKey()

posted @ 2021-06-18 09:40  学不会SLAM的  阅读(4267)  评论(0编辑  收藏  举报