目录

文档扫描项目说明

前言

文档扫描代码总体演示

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.pswp.cn/bicheng/87610.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87610.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/87610.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 中导出包含多个 Sheet 的 Excel 文件

在 Java 中导出包含多个 Sheet 的 Excel 文件,可以使用 Apache POI 或 EasyExcel(阿里开源库)。以下是两种方法的详细实现: 方法 1:使用 Apache POI(支持 .xls 和 .xlsx) 1. 添加 Maven 依赖 …

OneCode采用虚拟DOM结构实现服务端渲染的技术实践

一、技术背景与挑战 随着企业级应用复杂度的提升,传统服务端渲染(SSR)面临页面交互性不足的问题,而纯前端SPA架构则存在首屏加载慢和SEO不友好的缺陷。OneCode框架创新性地将虚拟DOM技术引入服务端渲染流程,构建了一套兼顾性能与开发效率的企…

变幻莫测:CoreData 中 Transformable 类型面面俱到(八)

概述 各位似秃似不秃小码农们都知道,在苹果众多开发平台中 CoreData 无疑是那个最简洁、拥有“官方认证”且最具兼容性的数据库框架。使用它可以让我们非常方便的搭建出 App 所需要的持久存储体系。 不过,大家是否知道在 CoreData 中还存在一个 Transfo…

汽车LIN总线通讯:从物理层到协议栈的深度解析

目录一、物理层:单线传输的信号奥秘1.1 电平定义与信号传输1.2 关键硬件组件作用二、数据链路层:帧结构与通信协议2.1 LIN帧的组成与功能2.2 主从式通信机制三、波特率同步:从节点的时钟校准原理四、软件实现:基于S32K144的主节点…

马尔可夫链:随机过程的记忆法则与演化密码

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术! 一、核心定义:无记忆的随机演化 马尔可夫链(M…

【vue3+tauri+rust】如何实现下载文件mac+windows

项目背景:【vue3taurirust】 由于Safari对于下载总是有诸多阻拦,目前需求windowsmac可以实现: 后端返回的url文件可以下载;前端根据dom元素生成的PDF报告可以下载(无远程URL); 我的尝试: 方法…

SQL 快速参考手册-SQL001

SQL 快速参考手册: 为方便快速学习和实践,提供了一份 SQL 快速参考手册,您可以打印出来随时查看,了解常见 SQL 命令的语法和用法。 SQL 数据类型 SQL 数据类型根据不同的数据库系统(如 Microsoft Access、MySQL、SQL…

学习java集合

集合与数组的对比集合的长度可变, 数组的长度不可变集合实际上跟数组一样, 是一种容器, 可以存放数据数组可以直接存放基本数据类型和引用数据类型集合可以存放引用数据类型, 但是不能直接存放基本数据类型, 如果要存放基本数据类型, 需要变成一个包装类才行泛型: 限定集合中存…

python训练day49 CBAM

import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self, in_channels, ratio16):"""通道注意力机制初始化参数:in_channels: 输入特征图的通道数ratio: 降维比例,用于减少参数量,默认…

在小程序中实现实时聊天:WebSocket最佳实践

前言 在当今互联网应用中,实时通信已经成为一个标配功能,特别是对于需要即时响应的场景,如在线客服、咨询系统等。本文将分享如何在小程序中实现一个高效稳定的WebSocket连接,以及如何处理断线重连、消息发送与接收等常见问题。 W…

Python网络爬虫编程新手篇

网络爬虫是一种自动抓取互联网信息的脚本程序,广泛应用于搜索引擎、数据分析和内容聚合。这次我将带大家使用Python快速构建一个基础爬虫,为什么使用python做爬虫?主要就是支持的库很多,而且同类型查询文档多,在同等情…

LeetCode.283移动零

题目链接:283. 移动零 - 力扣(LeetCode) 题目描述: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行…

2025年7月4日漏洞文字版表述一句话版本(漏洞危害以及修复建议),通常用于漏洞通报中简洁干练【持续更新中】,漏洞通报中对于各类漏洞及修复指南

漏洞及修复指南 一、暗链 危害:攻击者通过技术手段在用户网页中插入隐藏链接或代码,并指向恶意网站,可导致用户信息泄露、系统感染病毒,用户访问被劫持至恶意网站,泄露隐私或感染恶意软件,被黑客利用进行…

python --飞浆离线ocr使用/paddleocr

依赖 # python3.7.3 paddleocr2.7.0.2 paddlepaddle2.5.2 loguru0.7.3from paddleocr import PaddleOCR import cv2 import numpy as npif __name__ __main__:OCR PaddleOCR(use_doc_orientation_classifyFalse, # 检测文档方向use_doc_unwarpingFalse, # 矫正扭曲文档use…

数据结构与算法:贪心(三)

前言 感觉开始打cf了以后贪心的能力有了明显的提升,让我们谢谢cf的感觉场。 一、跳跃游戏 II class Solution { public:int jump(vector<int>& nums) {int n=nums.size();//怎么感觉这个题也在洛谷上刷过(?)int cur=0;//当前步最远位置int next=0;//多跳一步最远…

【Redis篇】数据库架构演进中Redis缓存的技术必然性—高并发场景下穿透、击穿、雪崩的体系化解决方案

&#x1f4ab;《博主主页》&#xff1a;    &#x1f50e; CSDN主页__奈斯DB    &#x1f50e; IF Club社区主页__奈斯、 &#x1f525;《擅长领域》&#xff1a;擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对…

Docker 实践与应用案例

引言 在当今的软件开发和部署领域&#xff0c;高效、可移植且一致的环境搭建与应用部署是至关重要的。Docker 作为一款轻量级的容器化技术&#xff0c;为解决这些问题提供了卓越的方案。Docker 通过容器化的方式&#xff0c;将应用及其依赖项打包成一个独立的容器&#xff0c;…

《论三生原理》以非共识路径实现技术代际跃迁‌?

AI辅助创作&#xff1a; 《论三生原理》以颠覆传统数学范式的非共识路径驱动多重技术代际跃迁&#xff0c;其突破性实践与争议并存&#xff0c;核心论证如下&#xff1a; 一、技术代际跃迁的实证突破‌ ‌芯片架构革新‌ 为华为三进制逻辑门芯片提供理论支撑&#xff0c;通过对…

一体机电脑为何热度持续上升?消费者更看重哪些功能?

一体机电脑&#xff08;AIO&#xff0c;All-in-One&#xff09;将主机硬件与显示器集成于单一机身。通常仅需连接电源线&#xff0c;配备无线键盘、鼠标即可启用。相比传统台式电脑和笔记本电脑&#xff0c;选购一体机的客户更看重一体机的以下特点。 一体机凭借其节省空间、简…

无人机载重模块技术要点分析

一、技术要点 1. 结构设计创新 双电机卷扬系统&#xff1a;采用主电机&#xff08;张力控制&#xff09;和副电机&#xff08;卷扬控制&#xff09;协同工作&#xff0c;解决绳索缠绕问题&#xff0c;支持30米绳长1.2m/s高速收放&#xff0c;重载稳定性提升。 轴双桨布局…