这次我们将使用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站