二、文档扫描OCR

一、思路分析

首先,拿到一张文档,我们需要对文档进行预处理操作,再进行轮廓检测,因为就算拿到文档轮廓,但是这些轮廓也有可能是歪歪扭扭的,这时候需要通过一系列的透视变换操作,将文档摆正。通过调用OCR函数库实现文档内容的识别。

二、导包及其相关函数

# 导入工具包
import numpy as np
import argparse
import cv2
# 设置参数
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"""tl   trbl   br	"""# 计算输入的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))#得到的轮廓不保障一点是个矩形,这里将两条width都计算出来,以最大的width最为最终矩形的widthheightA = 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))# 变换后对应坐标位置  这时候就需要将文档摆正,通过识别出来原始文档的width和height信息来重新摆正,放到(0,0)为左上角,形成一个矩形dst = np.array([[0, 0],[maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], dtype = "float32")# 计算变换矩阵M = cv2.getPerspectiveTransform(rect, dst)#rect为输入的原始图像的四个点,dst为最后摆正的四个点坐标;透视变换需要将原始的2维平面文档转换为3维空间中,变换之后再转回到2维平面中,调用该函数之后,此时M为3维矩阵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#后续需要对图像进行变换,这里先保留一下变换比例  shape[0]是width宽度
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)#Canny边缘检测
# 展示预处理结果
print("STEP 1: Canny边缘检测")
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)[1]#边缘检测之后再进行轮廓检测,轮廓检测这里使用的是边缘检测的结果
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]#对不同的轮廓按照面积排序,这里按面积大小找前5个轮廓
# 遍历轮廓
for c in cnts:#遍历找到的前5个轮廓# 计算轮廓近似peri = cv2.arcLength(c, True)#计算下每个轮廓的长度# C表示输入的点集# epsilon表示从原始轮廓到近似轮廓的最大距离,它是一个准确度参数# True表示封闭的approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 4个点的时候就拿出来if len(approx) == 4:#轮廓近似之后看看轮廓有几个点,若是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)
# orig为原始图像copy所得
# screenCnt.reshape(4, 2)拿到轮廓的四个坐标,但是这里是以及resize之后的四个点坐标,故需要乘以retio这个比例把四个点的坐标给还原回去
# 二值处理
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识别就是针对这个文档进行的。

四、Pycharm参数设定

对于 文档进行透视变换摆正 需要提供参数,指定图像路径
在这里插入图片描述
找到Edit Configurations

将image参数改成自己测试图像路径
--image yy.png,只需要重新指定后面的yy.png图像路径即可
在这里插入图片描述

五、OCR对文档内容进行识别

Ⅰ,工具包下载安装

tesseract工具包下载,windows就直接找个版本下载exe文件就行,直接下一步就行,需要注意一下按照的路径。

Ⅱ,配置环境变量

在这里插入图片描述
在这里插入图片描述
cmd下进行测试看看安装是否成功,tesseract -v
输出版本信息即可
在这里插入图片描述

Ⅲ,测试一下

例如在D盘下有一张图像
在这里插入图片描述

tesseract beyondyanyu.jpg yy beyondyanyu.jpg为测试图像路径,yy生成结果路径及名称
注意你存放测试图像的路径
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

报错解决方法一:

若在此处报错,需要重新新建一个系统变量

在这里插入图片描述
TESSDATA_PREFIX
C:\Program Files (x86)\Tesseract-OCR\tessdata
在这里插入图片描述
电脑关机重启一下。
再进行上述测试,看看有没有生成结果。

报错解决方法二:

G:\Anaconda3\Lib\site-packages\pytesseract
在这里插入图片描述
在这里插入图片描述
把此处的路径更改成下载的位置的全局路径即可。

Ⅳ,安装pytesseract

我用的是Anaconda,在Anaconda prompt中输入:pip install pytesseract

Ⅴ,测试

from PIL import Image
import pytesseract
import cv2
import ospreprocess = 'thresh' #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)                                   

在这里插入图片描述
控制台输出:

"""
Pasuze InoQuestions 12 to 15 are based on the passage you have just heard.2 Ai Moveable me1 type began to be used in privung
B) Chmese priwing technology was first introduced
C) The earliest known baok was publishedD) Metal type was imported from Korea13. A) It had more than a hundred printing pressesB) It was the bignest printer in the 16th centuryC) It helped the Geman people become lnerate
D; It produced some 20 milion volumes in total14. Aj It pushed hindwntten books out of circulation
B) It boosted the cnculation of popular works
C) It made writing a very profitable career
1) It provided readers with more choicesAj It acceterated the extinction of the Latin languageB) It sndardized the publication of grammur books
C) It turned translation into a welcome professionD) it promoted the growth of national linguagesThe earliest printed book we know today speared in China in the year 868, and metal type was
in use in Kore at the begining of the fifteenth century, but t was in Germany around the year 1450that a printing press using. movable metal type was invented. Capitalism turned printing from anmncenton into an industry. Richt from the start, book printing and publishing were organized oncapitalist fines. The biggest sinteenth-century printer, Plantin of Antwerp, had. twentfour pruing
prewes and employed more than a hundred workers. Only a small fraction of the population was
but the production of books grew at an extraordinary speed. By 1500 some twenty million
volumes hed atready been printedTheeffect of printing was to increase the circulation of works that were already
popular in a handwritten form, while less popular works went out of circulation. Publishers: were
only in books that would sell faily queldy in sufficient numbers to caver the costs of
production and make a profit. Thus, while priting enormously increased access to books by making
cheap. high- salume production possible, it also reduced choiceThe wieat cultural impact of printing was thi it ficifitared thewth of national languages
Most carly books were printed in Latin, but the market for Latin was limited. and in its pursuit of$Process finished with exit code 0
"""

六、完整代码

对文档进行透视变换摆正

# 导入工具包
import numpy as np
import argparse
import cv2# 设置参数
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"""tl   trbl   br	"""# 计算输入的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))#得到的轮廓不保障一点是个矩形,这里将两条width都计算出来,以最大的width最为最终矩形的widthheightA = 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))# 变换后对应坐标位置  这时候就需要将文档摆正,通过识别出来原始文档的width和height信息来重新摆正,放到(0,0)为左上角,形成一个矩形dst = np.array([[0, 0],[maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], dtype = "float32")# 计算变换矩阵M = cv2.getPerspectiveTransform(rect, dst)#rect为输入的原始图像的四个点,dst为最后摆正的四个点坐标;透视变换需要将原始的2维平面文档转换为3维空间中,变换之后再转回到2维平面中,调用该函数之后,此时M为3维矩阵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#后续需要对图像进行变换,这里先保留一下变换比例  shape[0]是width宽度
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)#Canny边缘检测# 展示预处理结果
print("STEP 1: Canny边缘检测")
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)[1]#边缘检测之后再进行轮廓检测,轮廓检测这里使用的是边缘检测的结果
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]#对不同的轮廓按照面积排序,这里按面积大小找前5个轮廓# 遍历轮廓
for c in cnts:#遍历找到的前5个轮廓# 计算轮廓近似peri = cv2.arcLength(c, True)#计算下每个轮廓的长度# C表示输入的点集# epsilon表示从原始轮廓到近似轮廓的最大距离,它是一个准确度参数# True表示封闭的approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 4个点的时候就拿出来if len(approx) == 4:#轮廓近似之后看看轮廓有几个点,若是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)
# orig为原始图像copy所得
# screenCnt.reshape(4, 2)拿到轮廓的四个坐标,但是这里是以及resize之后的四个点坐标,故需要乘以retio这个比例把四个点的坐标给还原回去# 二值处理
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识别

# https://digi.bib.uni-mannheim.de/tesseract/
# 配置环境变量如E:\Program Files (x86)\Tesseract-OCR
# tesseract -v进行测试
# tesseract XXX.png 得到结果 
# pip install pytesseract
# anaconda lib site-packges pytesseract pytesseract.py
# tesseract_cmd 修改为绝对路径即可
from PIL import Image
import pytesseract
import cv2
import ospreprocess = 'thresh' #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)                                   

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

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

相关文章

leetcode 77. 组合 思考分析

目录1、题目2、回溯法思路3、参考其他思路,更深入了解这个问题4、剪枝优化可能需要回顾到的知识文章:1、常用算法总结(穷举法、贪心算法、递归与分治算法、回溯算法、数值概率算法)2、回溯法初步删除vector容器中的对象元素的三种方法:pop_back, erase与…

三、全景拼接

一、项目所涉及到的一些知识点 Ⅰ,BF(Brute-Force)暴力匹配:把两张图像的特征点全部给算出来,然后使用归一化的欧氏距离比较这两张图像上特征点之间的大小关系,越小越相似。 SIFT算法 import cv2 import numpy as np import ma…

leetcode 216. 组合总和 III 思考分析

可能需要回顾的文章; leetcode 77. 组合 思考分析 1、题目 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。 说明: 所有数字都是正整数。 解集不能包含重复的组合。 2、递归 这一题和之前…

约束执行区域(CER)

受约束的执行区域 (CER) 是创作可靠托管代码的机制的一部分。CER 定义一个区域,在该区域中公共语言运行库 (CLR) 会受到约束,不能引发可使区域中的代码无法完全执行的带外异常。在该区域中,用户代码受到约束,不能执行会导致引发带…

四、模拟英语四六级答题卡识别阅卷评分

一、思路分析 首先拿到答题卡照片的时候,需要对照片进行一系列预处理操作,通过透视变换将图像摆正方便后续的操作。每一道题五个选项,有五道题,通过字典存放准确答案。没有依次对答题卡进行轮廓检测,这里采用的是正方…

leetcode 17. 电话号码的字母组合 思考分析

题目 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 思考与递归程序 解空间树的宽度是输入数字对应的字符的个数,深度是输入的数字的个数…

BHMS的完整形式是什么?

BHMS:顺势疗法医学和外科学士 (BHMS: Bachelor of Homeopathic Medicine and Surgery) BHMS is an abbreviation of Bachelor of Homeopathic Medicine and Surgery. It is a medical degree program for under graduation in Homeopathy; an alternative move towa…

WordPress Event Easy Calendar插件多个跨站请求伪造漏洞

漏洞名称:WordPress Event Easy Calendar插件多个跨站请求伪造漏洞CNNVD编号:CNNVD-201309-083发布时间:2013-09-11更新时间:2013-09-11危害等级: 漏洞类型:跨站请求伪造威胁类型:远程CVE编号&…

XML转txt格式脚本

一、东北大学老师收集的钢材缺陷数据集是XML格式的&#xff0c;但是YOLOv5只允许使用txt文件标签 例如其中一种缺陷图片所对应的标签&#xff1a;crazing_1.xml <annotation><folder>cr</folder><filename>crazing_1.jpg</filename><source&…

python程序生成exe_使用Python程序生成QR代码的Python程序

python程序生成exeQR code is a short form of the quick response code. It is a type of matrix barcode that contains some information like some specific link, important message, email-id, etc. In Python, the qrcode module is used to generate the QR code of so…

leetcode 242. 有效的字母异位词 思考分析

题目 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 我们先考虑低阶版本&#xff0c;认为字符只有26种可能&#xff0c;然后将a ~ z的字符映射到数组的索引0 ~ 25&#xff0c;数组中存放的则是该索引出现的频次。 记录下s的频次和t的频次…

js \n直接显示字符串_显示N个字符的最短时间

js \n直接显示字符串Problem statement: 问题陈述&#xff1a; You need to display N similar characters on a screen. You are allowed to do three types of operation each time. 您需要在屏幕上显示N个相似的字符。 每次允许您执行三种类型的操作。 You can insert a c…

三、标签准备

所有操作均在anaconda中的自己配置的环境下进行 一、安装labelimg 因为YOLO模型所需要的样本标签必须是txt类型&#xff0c;本人使用labelimg软件进行对图像进行打标签操作。 pip install pycocotools-windows pip install pyqt5 pip install labelimg 通过labelimg命令打…

leetcode 39. 组合总和 思考分析

目录1、题目2、思考分析3、未经优化代码4、剪枝优化1、题目 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 2、思考分析 解空间树宽度部分即数…

一、机器学习概念

一、何为机器学习(Mechine Learning)&#xff1f; 答&#xff1a;利用已有数据(经验)&#xff0c;来训练某种模型&#xff0c;利用此模型来预测未来。机器学习是人工智能的核心Mechine Learning。 例如&#xff1a;你和狗蛋儿7点在老槐树下集合&#xff0c;如何一块约去开黑&a…

Java线程新特征——Java并发库

一、线程池 Sun在Java5中&#xff0c;对Java线程的类库做了大量的扩展&#xff0c;其中线程池就是Java5的新特征之一&#xff0c;除了线程池之外&#xff0c;还有很多多线程相关的内容&#xff0c;为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序&#xff0c;…

leetcode 40. 组合总和 II 思考分析

题目 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 思考以及代码 如果我们直接套用39题的思路&#xff0c;那么就会出现重复的组合。 重复组合的…

二、线性回归

一、回归 可以拿正态分布为例&#xff0c;比如身高&#xff0c;若平均身高为1.78m&#xff0c;绝大多数人都是1.78m左右&#xff0c;超过2m的很少&#xff0c;低于1m的也不多。 很多事情都会回归到一定的区间之内&#xff0c;即回归到平均值。 机器学习没有完美解&#xff0c…

【转】HMM学习最佳范例五:前向算法1 .

五、前向算法&#xff08;Forward Algorithm&#xff09; 计算观察序列的概率&#xff08;Finding the probability of an observed sequence&#xff09; 1.穷举搜索&#xff08; Exhaustive search for solution&#xff09;  给定隐马尔科夫模型&#xff0c;也就是在模型参…

leetcode 349. 两个数组的交集 思考分析

题目 给定两个数组&#xff0c;编写一个函数来计算它们的交集。 1、暴力双for循环 class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {vector<int> result;vector<int> res;if(nums1.siz…