当前位置: 首页 > news >正文

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

目录

文档扫描项目说明

前言

文档扫描代码总体演示

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

​编辑

代码功能详解

1. 预处理阶段

2. 边缘检测

3. 轮廓处理

4. 透视变换

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 rectdef 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 warpeddef 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 imageif 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 = approxbreak# 展示结果
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 ospreprocess = "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 = approxbreak# 展示结果
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 ospreprocess = "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)绝对路径即可

http://www.dtcms.com/a/265395.html

相关文章:

  • DHCP中继及动态分配
  • 万字详解AVL树
  • 【指针(4)-- 深入理解指针】
  • “AI+”赋能千行百业创新融合的应用场景
  • UE5音频技术
  • 【动态规划】P11188 「KDOI-10」商店砍价|普及+
  • 钉钉企业应用开发系列:前端实现自定义右上角菜单(dd.http + Vue3)
  • 缺少关键的 MapReduce 框架文件
  • 数据仓库DataVault建模方法的前世今生
  • 【Python】图像识别的常用功能函数
  • MyBatis 之基础概念与框架原理详解
  • 【AI News | 20250702】每日AI进展
  • 设计模式篇:理解工厂模式
  • PyTorch 安装使用教程
  • 【51单片机串行通信实验】2022-6-3
  • 数据库基础——事务隔离级别
  • 热血三国建筑攻略表格
  • Dubbo RPC 序列化问题记录
  • 信号与槽(1)
  • JXLS 库导出复杂 Excel
  • 多模态AI Agent技术栈解析:视觉-语言-决策融合的算法原理与实践
  • MySQL 8.0 OCP 1Z0-908 题目解析(18)
  • 如何摆脱情绪的自动驾驶模式:掌控你的内心反应
  • 如何将信息从 iPhone 同步到Mac(完整步骤和示意图)
  • 网络工具如何帮助消除网络安全风险
  • 解决RHEL/Rocky Linux 虚拟化KVM添加 物理主机异常
  • Python Rich 详解:让终端输出焕发新生
  • 一、Docker:一场颠覆应用部署与运维的容器革命
  • C# Linq to SQL:数据库编程的解决方案
  • YOLOv8 模型转换 ONNX 后 C# 调用异常:一个参数引发的跨平台适配难题