对于我们生活中拍的关于单据以及文稿,我们如何将其转为成文档形式呢?对此我们可以利用OpenCV的图像处理来实现。
一、设计思路
Step1:边缘检测,抓取出文稿的边缘。
Step:2:获取轮廓,利用轮廓识别等基本算法获取到文稿的基本外轮廓。
Step3:进行透视变换,使文稿更加直观的展现。
Step4: OCR识别。
二、透视变换
图像的透视变换(Perspective Transformation)是指将图像利用透视变换矩阵投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。
如图所示,将原先图像投影到一个新的平面,让图像更直观。
三、OCR识别
OCR 识别,即光学字符识别,是一种通过扫描和识别纸质文档上的文字,将其转换成计算机可编辑和处理的数字文本格式的技术。简单来说,OCR 识别就是将纸质文档上的文字“翻译”成电脑能读懂的文字。
四、代码复现
(1)首先导入一些需要用的模块并且自定义一些需要的函数
import numpy as np
import cv2
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")
#自定义一个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)读取进来需要处理的图像并进行预处理(灰度处理,高斯滤波及边缘检测)
#读取进来需要扫描的图像
image=cv2.imread('D:\\OpenCV\\practice\\Scan\\images\\page.jpg')
ratio = image.shape[0] / 1000.0
orig = image.copy()
# 预处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
# 展示预处理结果
print("STEP 1: 边缘检测")
cv2.imshow("Image", image)
cv2.waitKey(5000)
cv2.destroyAllWindows()
cv2.imshow("Edged", edged)
cv2.waitKey(5000)
cv2.destroyAllWindows()
(3)轮廓检测
# 轮廓检测
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
cnts = sorted(cnts)
# 遍历轮廓
for c in cnts:
# 计算轮廓近似
peri = cv2.arcLength(c, True)
# C表示输入的点集
# epsilon表示从原始轮廓到近似轮廓的最大距离,它是一个准确度参数
# True表示封闭的
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 4个点的时候就拿出来
if len(approx) == 4:
screenCnt = approx
break
(4)透视变换,并且展示结果图
#仿射变换
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("Original", resize(orig, height = 250))
cv2.imshow("Scanned", resize(ref, height = 250))
cv2.waitKey(0)
(5)结果如图所示,对此我们再进行一步OCR识别即可实现文档转化。
cv2.imwrite('scan.jpg',ref)
image = Image.open('D:\OpenCV\scan.jpg')
code = pytesseract.image_to_string(image, lang='eng')
print(code)
五、总结
到此我们完成了文档扫描这一操作,对于OCR大家可以自行安装并了解其用法。在下节内容中,将更新基于OpenCV的图像拼接,实现全景图像。