导入环境
导入必要的库
numpy: 用于处理数值计算。
argparse: 用于处理命令行参数。
cv2: OpenCV库,用于图像处理。
python
import numpy as np
import argparse
import cv2
设置命令行参数
python
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="images/page.jpg", help="Path to the image to be scanned")
args = vars(ap.parse_args())
定义坐标排序函数
对四个坐标点进行排序,确定文档的四个角(左上,右上,右下,左下)。
使用欧氏距离来计算和排序点。
python
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
- 此函数用于排序提供的四个点,确保点的顺序为左上、右上、右下和左下,这对后续的透视变换非常重要。
定义透视变换函数
使用cv2.getPerspectiveTransform和cv2.warpPerspective来计算变换矩阵并应用
python
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 = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
# 返回变换后结果
return warped
- 接收原始图像和四个顶点坐标,然后应用透视变换,从而获取图像的正视图。
定义图像缩放函数
python
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
- 用于调整图像尺寸,使图像处理过程中的操作更加高效。
主逻辑部分
-
图像预处理:
- 读取图像,调整大小,并转换为灰度图。
- 应用高斯模糊和Canny边缘检测准备图像进行轮廓检测。
-
轮廓检测:
- 使用
cv2.findContours
寻找边缘,这是寻找文档轮廓的关键步骤。 - 选择轮廓面积最大的前五个轮廓。
- 使用
-
透视变换:
- 对检测到的轮廓(如果准确地检测到四点)应用透视变换。
- 将图像从斜视角转换为正视图,便于文档的进一步处理和分析。
-
结果保存和显示:
- 应用二值化处理,并保存变换后的扫描图像。
- 显示原始和扫描后的图像。
关键知识点
- 高斯模糊 (
GaussianBlur
): 用于去除图像噪声并平滑图像。 - Canny边缘检测 (
Canny
): 用于在图像中检测边缘,是轮廓检测的关键步骤。 - 轮廓检测 (
findContours
): 在二值图像中寻找轮廓,用于图形、图像和物体的形状分析。 - 透视变换 (
getPerspectiveTransform
,warpPerspective
): 在进行文档扫描或修正图像视角时非常有用。
python
if __name__ == '__main__':
# 读取输入
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_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
# 展示预处理结果
print("STEP 1: 边缘检测")
cv2.imshow("Image", image)
cv2.imshow("Edged", edged)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 轮廓检测 opencv3
# cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1][0]
# cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
# 使用OpenCV 4.x的方式来调用findContours
contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 确保轮廓是适当的数据类型
cnts = [np.array(cnt, dtype='float32') for cnt in contours]
# 排序并选择最大的5个轮廓
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]
# 遍历轮廓
screenCnt = None
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.astype(int)
break
if screenCnt is not None:
# 展示结果
print("STEP 2: 获取轮廓")
# print(screenCnt)
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
cv2.imshow("Outline", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 透视变换
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 = 650))
cv2.imshow("Scanned", resize(ref, height = 650))
cv2.waitKey(0)
-
Canny算子检测结果图:
-
定 四个顶点
-
仿射变换结果
OCR识别
Tesseract 是一个开源的光学字符识别(OCR)引擎,最初由惠普实验室于1985年开发,并在2006年由Google赞助成为一个开源项目。Tesseract 能够识别多种格式的图像文件并将它们转换成文本。它支持多种语言的识别,并且可以通过训练来识别新的语言或优化现有语言的识别效果。
主要特点:
- 多语言支持:Tesseract 支持100多种语言的识别。
- 高度可定制:用户可以训练Tesseract来识别新的字体或优化特定语言的识别。
- 多种输出格式:Tesseract 可以输出普通文本、hOCR(带有布局信息的HTML)、PDF等格式。
- 集成易用 :可以通过命令行使用,也可通过其API集成到其他应用程序中,比如通过
pytesseract
在Python中使用。
使用方法:
在命令行中,Tesseract 可以简单地通过指定输入图像和输出文件名来使用,如:
bash
tesseract image.png output -l eng
这里-l eng
指定了使用英语语言包。
pytesseract:
在Python中,pytesseract
是一个将Tesseract引擎功能封装的库,允许Python直接调用Tesseract进行图像到文本的转换。使用前需要确保Tesseract已安装在系统上,并且正确配置了环境变量或在pytesseract
的tesseract_cmd
属性中指定了Tesseract的路径。
应用场景:
- 文档数字化:将纸质文档扫描后识别为数字文本。
- 自动化表单处理:从填写的表单中提取信息。
- 车牌识别:用于交通监控或自动收费系统。
- 辅助技术:帮助视觉障碍人士阅读印刷材料。
Tesseract是一个功能强大的工具,因其开源和高效被广泛用于商业和研究领域。
1. 导入必要的库
- PIL (Python Imaging Library): 用于图像的打开和处理。
- pytesseract: 是Google的Tesseract-OCR引擎的Python封装,用于识别图像中的文字。
- cv2 (OpenCV): 用于图像处理的库,这里用于读取和预处理图像。
python
from PIL import Image
import pytesseract
import cv2
import os
2. 图像预处理
- 读取图像 : 使用
cv2.imread
读取图像文件。 - 转换为灰度图 : 使用
cv2.cvtColor
将读取的彩色图像转换为灰度图,因为OCR通常在灰度图上进行。 - 应用阈值或模糊处理 :
- 如果预处理方式为"thresh"(阈值),使用
cv2.threshold
应用阈值化处理,这可以帮助去除背景噪声并突出文本。 - 如果预处理方式为"blur"(模糊),使用
cv2.medianBlur
应用中值模糊,以减少图像噪声。
- 如果预处理方式为"thresh"(阈值),使用
python
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)
3. 保存处理后的图像
- 保存文件 : 使用
cv2.imwrite
将处理后的灰度图像临时保存为一个新文件,文件名由当前进程ID命名。
4. 文本识别
- 使用
pytesseract.image_to_string
函数读取步骤3中保存的灰度图像文件,识别其中的文本。
python
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)
cv2.waitKey(0)
5. 输出和清理
- 打印识别的文本。
- 删除临时文件 : 使用
os.remove
删除保存的临时图像文件。 - 显示图像 : 使用
cv2.imshow
展示原始图像和处理后的图像。 - 等待按键 : 使用
cv2.waitKey(0)
暂停程序,等待用户按键继续。
知识点总结
- OpenCV的灰度转换和图像滤波:灰度转换有助于简化数据,滤波有助于减少噪声,这两者都是提高OCR准确性的关键步骤。
- 阈值处理与模糊处理的选择:不同的图像预处理方法适用于不同类型的图像和需求,阈值处理适用于高对比度图像,而模糊处理适用于噪声较多的图像。
- pytesseract的使用:封装了Tesseract-OCR引擎,能够从图像中识别和提取文字。
通过仿射变换矫正后图像为:
识别结果为:
源码上传地址
链接 ----------------上传地址 文档OCR识别(tesseract)