【Opencv入门到项目实战】(十):项目实战|文档扫描|OCR识别

所有订阅专栏的同学可以私信博主获取源码文件

文章目录

  • 1.引言
    • 1.1 什么是光学字符识别 (OCR)
    • 1.2 应用领域
  • 2.项目背景介绍
  • 3.边缘检测
    • 3.1 原始图像读取
    • 3.2 预处理
    • 3.3 结果展示
  • 3.轮廓检测
  • 4.透视变换
  • 5.OCR识别
    • 5.1 tesseract安装
    • 5.2 字符识别

1.引言

今天我们来看一个OCR相关的文档扫描项目。首先我们先来介绍一些相关理论

1.1 什么是光学字符识别 (OCR)

OCR(即光学字符识别)是识别图像中的文本并将其转换为电子形式的过程。这些图像可以是手写文本、打印文本(如文档、收据、名片等),甚至是自然场景照片。

简单来说,OCR 有两个部分。第一部分是文本检测,确定图像内的文本部分。第二部分文本识别,从图像中提取文本。 结合使用这些技术可以从任何图像中提取文本。具体的流程如下图所示

image-20230809111956152

OCR 在各个行业都有广泛的应用(主要目的是减少人工操作)。它已经融入我们的日常生活,并且有很多的应用。

1.2 应用领域

OCR 越来越多地被各行业用于数字化,以减少人工工作量。这使得从商业文档、收据、发票、护照等中提取和存储信息变得非常容易和高效,几十年前,OCR 系统的构建非常昂贵且繁琐。但计算机视觉和深度学习领域的进步使得我们现在自己就可以构建一个OCR 系统。但构建 OCR 系统需要利用到我们之前介绍的一系列方法。

2.项目背景介绍

背景:我们有一张随手拍的发票照片如下,我们希望识别出文档信息并扫描
在这里插入图片描述

思考:我们如何实现上述需求呢?

首先,我们的算法应该能够正确的对齐文档,检测图像的边界,获得目标文本图像

其次,我们能对目标文本图像的文档进行扫描

下面我们来看一下具体如何在Opencv中处理

这里一共需要四大步

第一步,边缘检测,

第二步,提取轮廓。

第三步,透视变换,使得图像对齐,从上图可以看出,我们的图片是一个倾斜的,我们需要通过各种转换方法将其放平。

第四步,OCR识别

3.边缘检测

3.1 原始图像读取

首先,我们读取要扫描的图像。

下述代码我们计算了一个ratio比例,这是因为我们后续要对图像进行resize操作,里面每一个点的坐标也会有相同的一个变化,因此,我们先算出来这样一个比例,可以推导出resize完之后图像的坐标变化,然后方便我们后续在原图上进行修改。

# 读取输入
image = cv2.imread('images/receipt.jpg')
#坐标也会相同变化
ratio = image.shape[0] / 500.0 #这里我们首先得到一个比例,方便后续操作
orig = image.copy()

3.2 预处理

下面我们对图形进行一些基本的预处理工作,包含resize、灰度处理、二值处理。

第一,我们定义了一个resize()函数,它的基本逻辑是根据输入的高度或宽度,自动的计算出宽度或高度。

第二,我们将图形进行灰度处理

第三,我们使用gaussian滤波器去除噪音点

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 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 = resize(orig, height = 500) # # 预处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 灰度处理
gray = cv2.GaussianBlur(gray, (5, 5), 0) # 高斯滤波器

3.3 结果展示

经过上述得到预处理后的图片,经过canny边缘检测。

# 展示预处理结果
edged = cv2.Canny(gray, 75, 200) # canny边缘检测,得到边缘print("STEP 1: 边缘检测")
cv2.imshow("Image", image) #原始图像
cv2.imshow("Edged", edged) #边缘结果
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20230809151054227

image-20230809150545141

现在我们得到边缘检测的结果,可以看到有很多个边缘,我们做文档扫描,需要的是最外面的结果,接下来我们来具体如何实现。

3.轮廓检测

我们先来思考一下最外面这个轮廓它有什么特点。

首先,它是最大的,因此,我们可以根据它的面积或者周长进行排序,这里我们对面积进行排序。然后我们要去找轮廓,这里我们遍历每一个轮廓,然后去计算轮廓的一个近似,因为直接算轮廓的时候不太好算,往往是一个不规则形状,我们做一个矩形近似,然后此时就只需要确定四个点就行。具体代码如下:

 # 轮廓检测
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5] #按照面积排序# 遍历轮廓
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()

image-20230809152343021

4.透视变换

透视变换(Perspective Transformation),也称为投影变换,它可以用于纠正图像畸变、实现视角变换和图像合成等应用。借助透视变换,我们可以从不同视角获得准确的图像数据,并进行更精确的分析、处理和识别。

它的基本原理是基于相机的投影模型,通过处理图像中的四个控制点,将原始图像上的任意四边形区域映射到新的位置和形状上,我们需要得到四个输入坐标和四个输出坐标。通常情况下,透视变换会改变图像中的视角、缩放和旋转等属性。它有几个关键步骤如下:

  • 控制点选择:为了进行透视变换,我们需要选择原始图像中的四个控制点(例如四个角点),以定义目标区域的形状和位置。这些控制点应该在原始图像和目标图像之间有明确的对应关系,然后通过高度和宽度信息,我们计算出目标图像的四个控制点

  • 透视变换矩阵:通过使用控制点的坐标,可以计算出透视变换矩阵,透视变换矩阵是一个3x3的矩阵。它包含了图像变换所需的所有信息。这里需要输入坐标和输出坐标,然后利用cv2.getPerspectiveTransform函数获取变换矩阵。通过将透视变换矩阵应用于原始图像上的点,可以得到它们在目标图像中的对应位置。

接下来我们来看一下具体是如何实现的,首先我们定义了一个ordr_points()函数来获取坐标点,然后我们定义four_point_transform函数来实现透视变换。具体代码如下,

# 获取坐标点
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) #通过输入和输出坐标,可以计算出M矩阵warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))# 返回变换后结果return warped

定义好上述函数之后,接下来看一下经过同时变换之后的结果,为了方便展示,我们再进行二值化处理

# 透视变换
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio) #这里乘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("Scanned", resize(ref, height = 650))
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20230809155008797

可以看到我们现在就得到了扫描之后得到的结果,并且我们保存为scan.jpg操作

5.OCR识别

得到扫描后的文档之后,我们需要对其中的字符进行识别,这里我们要用到tesseract工具包,我们先来看一下如何安装相关环境。

5.1 tesseract安装

安装地址:https://digi.bib.uni-mannheim.de/tesseract/

image-20230809165235000

首先选择一个合适的版本进行安装就行,我这里选择最新的w64版本,如何安装时一直点击下一步就行,但是我们要记住安装的路径。

注意:我们需要进行环境变量配置

把刚刚安装的路径添加到环境变量中即可

image-20230809165515720

接下来我们希望在python中使用它,因此要下载对应的python工具包。

安装命令如下:pip install pytesseract

5.2 字符识别

我们刚刚已经得到了扫描后的图像,并保存为scan.jpg如下所示

image-20230809165828358

接下来我们希望把其中的文本字符全部提取出来,我们来看一下具体代码吧

from PIL import Image
import pytesseract
import cv2
import os# 读取图片
image = cv2.imread('scan.jpg')# 灰度处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 二值处理
gray = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]    filename = "{}.png".format(os.getpid())
cv2.imwrite(filename, gray)
# OCR识别,提取字符    
text = pytesseract.image_to_string(Image.open(filename))
print(text)
x * KK KK K KR KH KR RK KKWHOLE
FOODS
TM AR K CE T)WHOLE FOODS MARKET ~ WESTPORT, CT 06880
399 POST RD WEST - (203) 227-6858365 BACUN LS NP 499
$65 BACON LS NP 4.99365 BACON LS NP 4.99365 BACON LS NP 4.99
BROTH CHTC NP 2.19FLOUR ALMUND NP 11.99CHKN BRST BNLSS SK NP 18.80
HEAVY CREAM NP 3.39BALSMC REDUCT NP 6.49BEEF GRND 85/15 NP 5.04
JUICE COF CASHEW L NP = 8.99
DOCS PINT ORGANIC NF 14.49
HNY ALMOND BUTTER NP 9.99
xeee TAX = 00 9 BAL 101.33TTA AATDA ABH HH oy

对比一下可以看到识别的字符都比较准确。

🔎本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、订阅支持!!《Opencv入门到项目实战》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1381264.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Python3爬取东方财富十大股东及题材/同花顺参股控股公司及题材

爬取东方财富十大股东及题材/同花顺、参股控股公司及题材 东方财富网同花顺 Python后台抓取,C#客户端展示 待抓取网站及数据内容如下 : 东方财富网 http://emweb.securities.eastmoney.com/CoreConception/Index?typeweb&codesh601390 下的核心题…

《Kubernetes知识篇:常见面试题汇总》

正在不断地完善中,预计1个月的时间完成,覆盖整个Kubernetes知识面总结! 一、概述 1、简述什么是 Kubernetes? kubernetes(常简称k8s),是一个 为容器化应用提供自动化部署、扩展和管理的开源平台…

Python实现调用百度翻译的API

import requests import hashlib import random import jsondef translate(text, from_lang, to_lang):app_id XXXXX # 替换为你的App IDsecret_key XXXXX # 替换为你的Secret Key# 生成随机数salt random.randint(32768, 65536)# 计算签名sign app_id text str(salt) …

机器学习的相关软件框架下载安装

文章目录 一、Anaconda1. Anaconda 的下载2. Anaconda 的安装3. Anaconda Navigator 打不开问题(不适用所有) 二、PyTorch-CPU1. PyTorch 环境创建2. PyTorch 下载3. Jupyter 中使用 PyTorch 三、Python 版本升级与包的维护1. 更新 Anaconda2. 查看与更新…

在线学习功能

一、需求描述 学生登录进入学习中心即可在线学习: 1、学生可以在windows浏览器上在线观看视频(录播课程)。 2、播放器具有快进、快退、暂停等基本功能。 3、学生可以方便切换章节进行学习。 什么是录播课程? 录播课程就是提供录制…

Vue组件库

Vue组件库 ViteVue3TypescriptTSX 1、项目搭建 1.1、创建项目(yarn) D:\WebstromProject>yarn create vite yarn create v1.22.19 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh pa…

计算机网络:网络字节序

目录 一、字节序1.字节序概念2.字节序的理解(1)大端模式存储数据(2)小端模式存储数据 二、网络字节序 一、字节序 1.字节序概念 字节序:内存中存储多字节数据的顺序。 难道存储数据还要看顺序吗? yes。内…

Gartner数据库魔力象限2022:阿里领先、腾讯再次进入、华为退出

上周,Gartner正式发布了2022年数据库魔力象限,先睹为快: (图片来源:链接参考在文末参考) 1. 关于Gartner的数据库魔力象限 Gartner数据库魔力象限(参考,后面简称MQ)一直…

远古魔力 | 在Windows 10和Azure App Service里跑上世纪的ASP

ASP(没有.NET) 即 Active Server Pages (动态服务器页面)是一项由微软公司在1996年推出的技术,能够在IIS中运行动态网站。也许许多90后及千禧一代程序员并没有听说过它,但很多老程序员曾经用ASP编写了诸如D…

文件上传以及yml的配置

目录 一、存储本地 二、存储到阿里云 三、配置文件信息 一、存储本地 MultipartFile 常见方法: String getOriginalFilename(); //获取原始文件名 void transferTo(File dest); //将接收的文件转存到磁盘文件中 long getSize(); //获取文件的大小,单…

未来混合动力汽车的发展:技术探索与前景展望

随着环境保护意识的增强和对能源消耗的关注,混合动力汽车成为了汽车行业的研发热点。混合动力汽车融合了传统燃油动力和电力动力系统,通过优化能源利用效率,既降低了燃油消耗和排放,又提供了更长的续航里程。本文将探讨混合动力汽…

【雕爷学编程】Arduino动手做(202)---热释电效应、热释电元件与HC-SR505运动传感器模块

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…

「卷轴」iPhone 有戏?苹果新专利曝光,果粉激动:终于要变了!

整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 回顾近几年的 iPhone 进化史,相信不少人都会发出一句感慨:太无趣了……除了外观上的些许变化,技术更新并不大,而最令人印象深刻的,或许是去…

ios刺激战场连接服务器没有响应,问题解决 | 《刺激战场》官方适配苹果篇

原标题:问题解决 | 《刺激战场》官方适配苹果篇 昨天我们发布了针对苹果客户端,《刺激战场》官方正式接入HandJoy外设的消息,因此有小伙伴留言咨询安卓客户端问题。现在需要明确告知大家的是,安卓客户端目前是测试版本&#xff0c…

刺激战场android ios,绝地求生刺激战场ios和安卓数据互通吗 安卓苹果可以添加好友一起玩吗...

绝地求生刺激战场安卓和IOS可以互相添加好友么,ios和安卓数据互通吗,安卓苹果可以联机一起玩吗?刺激战场ios和安卓是两个不同的系统,能不能在一起玩呢?毕竟游戏重在和朋友一起开黑才有意思,下面…

yolo-nas对自定义数据集进行训练,测试详解 香烟数据集 处理损坏的图片数据 对网络摄像头,视频,图片预测

yolov5格式的香烟数据集 https://download.csdn.net/download/qq_42864343/88110620?spm1001.2014.3001.5503 创建yolo-nas的运行环境 进入Pycharm的terminal,输入如下命令 conda create -n yolonas python3.8pip install super-gradients使用自定义数据训练Yo…

Linux —— 基础I/O(二)

目录 一,FILE 二,缓冲区 三,重定向 系统调用dup2 一,FILE FILE结构体内部包括 变量_fileno,即对应的文件描述符下标fd;应用层C语言提供的缓冲区数据;其IO相关函数与系统调用接口对应&#…

SpringBoot使用自定义事件监听器的demo

记录一下SpringBoot自定义事件监听器的使用方法 案例源码:SpringBoot使用自定义事件监听器的demo 使用的SpringBoot2.0.x版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><…

bat批处理文件 - win10桌面图标白标修复(图标变为白色方块)

前言 当你桌面应用变成如图所示白标时(正常运行)&#xff0c;那么这个批处理文件可以帮助你。 其中&#xff0c;IconCache.db就是图标缓存文件&#xff0c;把他删除重新构建即可。 一、新建文本文件.txt 复制以下代码 echo offtaskkill /f /im explorer.exeCD /d %userprof…

Win10系统任务栏图标显示白色方块的解决方法

时间&#xff1a;2022-07-30 问题&#xff1a;Win10系统任务栏图标显示白色方块 解决后&#xff1a; 原因&#xff1a;Windows对于图标的缓存 解决方法&#xff1a; 1.进入C盘的用户家目录下的AppData目录&#xff0c;再进入Local目录 1.1 WinR 然后运行 %localappdata% 直…