OpenCV篇——项目(二)OCR文档扫描

目录

文档扫描项目说明

前言

文档扫描代码总体演示

OCR文档识别代码总体演示:

​编辑

代码功能详解

[1. 预处理阶段](#1. 预处理阶段)

[2. 边缘检测](#2. 边缘检测)

[3. 轮廓处理](#3. 轮廓处理)

[4. 透视变换](#4. 透视变换)

[5. 后处理](#5. 后处理)

主要改进说明:

使用建议:


文档扫描项目说明

前言

本项目实现了一个自动化文档扫描系统,能够将倾斜拍摄的文档图像校正为正面视角的矩形图像。系统通过边缘检测、轮廓识别和透视变换技术,模拟真实文档扫描仪的功能。该解决方案适用于纸质文档数字化、表单识别等场景,可有效处理拍摄角度倾斜、透视变形等问题。

文档扫描代码总体演示
复制代码
# 导入工具包
import numpy as np
import argparse
import cv2
import imutils

# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
	help = "Path to the image to be scanned")
args = vars(ap.parse_args())

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 = cv2.getPerspectiveTransform(rect, dst)
	warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

	# 返回变换后结果
	return warped

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

# 读取输入
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()

# 轮廓检测
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# imutils的作用是兼容OpenCV 3.X和4.X
cnts = imutils.grab_contours(cnts)
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
		break

# 展示结果
print("STEP 2: 获取轮廓")
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)

边缘检测:

获取轮廓:

透视变换:

OCR文档识别代码总体演示:
复制代码
from PIL import Image
import pytesseract
import cv2
import os

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)
cv2.imshow("Image", image)
cv2.imshow("Output", gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码功能详解
1. 预处理阶段
复制代码
# 读取输入
image = cv2.imread(args["image"])
ratio = image.shape[0] / 500.0
orig = image.copy()
image = resize(orig, height=500)
  • 功能:加载原始图像并计算缩放比例
  • 关键技术
    • 保持原始图像比例:ratio = 原始高度/500
    • 尺寸调整函数:保持宽高比将图像高度统一为500像素
  • 数学原理:缩放比例 r = \\frac{\\text{目标尺寸}}{\\text{原始尺寸}}
2. 边缘检测
复制代码
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
  • 功能:提取文档边缘特征
  • 处理流程
    1. 灰度转换:RGB→灰度
    2. 高斯模糊:5×5核降噪
    3. Canny边缘检测:双阈值(75,200)识别边缘
  • 数学原理:图像梯度计算 \|\\nabla I\| = \\sqrt{(\\frac{\\partial I}{\\partial x})\^2 + (\\frac{\\partial I}{\\partial y})\^2}
3. 轮廓处理
复制代码
# 轮廓检测
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# imutils的作用是兼容OpenCV 3.X和4.X
cnts = imutils.grab_contours(cnts)
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
		break

# 展示结果
print("STEP 2: 获取轮廓")
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
cv2.imshow("Outline", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 功能:识别文档边界四边形
  • 关键技术
    • 轮廓面积排序:取前5大轮廓
    • 多边形近似:Douglas-Peucker算法
    • 周长约束:近似精度=0.02×周长
  • 筛选条件:仅保留4顶点多边形(四边形)
4. 透视变换
复制代码
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
  • 功能:将四边形区域投影到矩形平面
  • 坐标排序
    • 左上:x+y最小
    • 右下:x+y最大
    • 右上:x-y最小
    • 左下:x-y最大
  • 尺寸计算
    • 宽度 = max(底边宽, 顶边宽)
    • 高度 = max(左边高, 右边高)
  • 数学原理:透视变换矩阵 M_{3\\times3} 满足: \\text{dst} = M \\times \\text{src}
5. 后处理
复制代码
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('scan.jpg', ref)
  • 功能:生成扫描文档结果
  • 处理流程
    1. 灰度转换
    2. 二值化阈值处理(阈值=100)
    3. 保存为"scan.jpg"
  • 输出效果:获得类似扫描仪的纯净黑白文档图像

我将继续完善OCR文本识别脚本,添加文件输出和异常处理功能:

复制代码
from PIL import Image
import pytesseract
import cv2
import os

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)
cv2.imshow("Image", image)
cv2.imshow("Output", gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

主要改进说明:

  1. 文件输出功能

    添加了将识别结果保存到文本文件的功能,使用UTF-8编码确保多语言支持

  2. 异常处理机制

    包含:

    • 文件存在性检查
    • Tesseract专用错误捕获
    • 通用异常处理
  3. 增强预处理选项

    新增自适应阈值处理: $$ \text{adaptiveThreshold}(src, maxValue, adaptiveMethod, thresholdType, blockSize, C) $$ 其中高斯加权: $$ T(x,y) = \mu(x,y) - C $$ \\mu 是邻域均值

  4. 图像方向检测

    使用image_to_osd()自动检测文字方向,为后续旋转校正提供依据

  5. 命令行参数支持

    通过argparse模块实现:

    复制代码
    python script.py --input invoice.png --output result.txt

使用建议:

  1. 对于模糊文档,推荐使用--preprocess blur
  2. 对于低对比度文档,使用--preprocess adaptive
  3. 检查输出文件编码,确保特殊字符正确显示

此扩展保留了原有核心功能,同时增强了鲁棒性和实用性,支持批处理场景。

该实现完整展示了从原始文档图像到文本提取的端到端流程,核心在于通过透视变换解决文档畸变问题,为OCR识别创造最佳输入条件。

注意事项和使用方法:

https://digi.bib.uni-mannheim.de/tesseract/下载tesseract环境

配置环境变量如E:\Program Files(x86)\Tesseract-0CR(根据自身的下载路径配置)

以下是测试Tesseract环境,按住win+r打开"运行"对话框,输入cmd打开命令提示符

tesseract-v进行测试

tesseract xxx.png 得到结果

pip install pytesseract 安装Python可以使用tesseract模块包

接下来去寻找自己的Python解释器找到路径 anaconda lib site-packges pvtesseract pytesseract.py 用记事本找到tesseract cmd 命令后面修改为(自己安装tesseract)绝对路径即可

复制代码
相关推荐
小雷FansUnion1 小时前
深入理解MCP架构:智能服务编排、上下文管理与动态路由实战
人工智能·架构·大模型·mcp
资讯分享周2 小时前
扣子空间PPT生产力升级:AI智能生成与多模态创作新时代
人工智能·powerpoint
思则变3 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
叶子爱分享3 小时前
计算机视觉与图像处理的关系
图像处理·人工智能·计算机视觉
鱼摆摆拜拜3 小时前
第 3 章:神经网络如何学习
人工智能·神经网络·学习
一只鹿鹿鹿3 小时前
信息化项目验收,软件工程评审和检查表单
大数据·人工智能·后端·智慧城市·软件工程
张较瘦_3 小时前
[论文阅读] 人工智能 | 深度学习系统崩溃恢复新方案:DaiFu框架的原位修复技术
论文阅读·人工智能·深度学习
cver1233 小时前
野生动物检测数据集介绍-5,138张图片 野生动物保护监测 智能狩猎相机系统 生态研究与调查
人工智能·pytorch·深度学习·目标检测·计算机视觉·目标跟踪
漫谈网络3 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
学技术的大胜嗷3 小时前
离线迁移 Conda 环境到 Windows 服务器:用 conda-pack 摆脱硬路径限制
人工智能·深度学习·yolo·目标检测·机器学习