当前位置: 首页 > 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.lryc.cn/news/579491.html

相关文章:

  • Rust方法语法:赋予结构体行为的力量
  • ConcurrentHashMap 原理
  • Linux多线程(十二)之【生产者消费者模型】
  • 汽车ECU产线烧录和检测软件怎么做?
  • Flutter 3.29+使用isar构建失败
  • HarmonyOS ArkTS卡片堆叠滑动组件实战与原理详解(含源码)
  • Java网络编程:TCP/UDP套接字通信详解
  • I/O 进程 7.2
  • 在Ubuntu 24.04主机上创建Ubuntu 14.04编译环境的完整指南
  • (一)复习(模块注入/minimal api/EF和Dapper实现CQRS)
  • Ubuntu Gnome 安装和卸载 WhiteSur-gtk-theme 类 Mac 主题的正确方法
  • Frida:配置自动补全 in VSCode
  • TCP 三次握手与四次挥手详解
  • MyBatis 之基础概念与框架原理详解
  • RabbitMQ 通过HTTP API删除队列命令
  • 【如何判断Linux系统是Ubuntu还是CentOS】
  • Centrifugo 深度解析:构建高性能实时应用的开源引擎
  • 记忆翻牌记忆力小游戏流量主微信小程序开源
  • 网创vip课程视频教程、付费网络课程以及网赚培训,学习引流、建站、赚钱。8个T的全套课程
  • 【2.3 漫画SpringSecurity - 守护应用安全的钢铁卫士】
  • ATE FT ChangeKit学习总结-20250630
  • Easy-excel监听器中对批量上传的工单做错误收集
  • Redisson使用示例
  • 请求未达服务端?iOS端HTTPS链路异常的多工具抓包排查记录
  • 【Bug Recod】更新中...
  • Day50
  • 一文详解Character AI:实用指南+ ChatGPT、Gemini对比分析
  • contenteditable网页富文本编辑无法选中图片
  • Swift 的基础设计哲学是 “通过模块化组合实现安全与效率的平衡“,就像用标准化工业零件建造摩天大楼
  • 一台香港原生ip站群服务器多少钱?