目录

  • 1.项目数据及源码
  • 2.图像预处理
  • 3.获取最优轮廓
    • 3.1.轮廓提取
    • 3.2.筛选轮廓
  • 4.原始与变换坐标计算
  • 5.显示识别结果
    • 5.1.图像处理
    • 5.2.修改图片大小,并逆时针旋转90度
    • 5.3.显示图像
  • 6.OCR识别

1.项目数据及源码

可在github下载:

https://github.com/chenshunpeng/Doc-scan

2.图像预处理

首先导入工具包

import numpy as np
import argparse
import cv2

设置命令行参数

# 构造参数解析并解析参数
# we instantiate the ArgumentParser object as ap(实例化)
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default='./images/pic.jpg', required = False, help = "Path to the image to be scanned")
args = vars(ap.parse_args())

读取输入,对图像进行缩放

图像:

# 读取输入
image = cv2.imread(args["image"])
# 图像缩放,坐标也会相同变化
ratio = image.shape[0] / 500.0
orig = image.copy()
image = resize(orig, height = 500)

这里的ratio是4.896

在此给出resize函数定义:

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

对图像进行预处理,并展示预处理结果

# 转灰度图
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()

结果:

对于一些陌生的知识(如Canny边缘检测),可以在w3cschool看OpenCV的文档的翻译进行学习

(https://www.w3cschool.cn/opencv)

推荐有一定英语水平的直接看OpenCV官方文档(https://docs.opencv.org/3.4/index.html):

3.获取最优轮廓

3.1.轮廓提取

# cv.findContours()函数中有三个参数,第一个是源图像,第二个是轮廓检索模式,第三个是轮廓近似方法。
# 它输出轮廓和层次结构。Contours是图像中所有轮廓的Python列表。每个单独的轮廓都是对象边界点的 (x,y) 坐标的 Numpy 数组
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]
# 对轮廓按照面积从大到小排序,取前5个(先从小到大排序,之后取reverse翻转)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]

在 Opencv4中,cv2.findContour()仅返回 2 个值:contours, hierachy,所以在这里用[0]得到第一个值

具体阅读这个网址:https://docs.opencv.org/4.x/d4/d73/tutorial_py_contours_begin.html

排序前有493个轮廓:

排序后取面积最大的5个轮廓(最外边的框架面积一定最大,所以周长也较大,点数也较多):

3.2.筛选轮廓

进行遍历轮廓,寻找最优轮廓

# 对screenCnt初始化,不然可能会有警告
screenCnt = [[0,0], [255,0], [255,255], [0,255]]for c in cnts:# 计算轮廓近似peri = cv2.arcLength(c, True)# cv2.approxPolyDP()的主要功能是把一个连续光滑曲线折线化,之后多边形逼近# c表示输入的点集# 其中第二个参数epsilon的作用:double epsilon:判断点到相对应的line segment的距离的阈值# (距离大于此阈值则舍弃,小于此阈值则保留,epsilon越小,折线的形状越“接近”曲线。)# True表示封闭的approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 因为是文本行,返回的框至少应该是个四边形,只要找到那个最大的四边形,就可以退出了if len(approx) == 4:screenCnt = approxbreak

v2.approxPolyDP函数了解可看:

Google:Contour Features(OpenCV官网教程)

这种函数类的知识推荐 Google 搜索,可以直接搜索到官方文档,权威一些

最优轮廓如下:

我们发现最优轮廓的确是那个面积最大的轮廓,但点数最不是最多的(1009<1042)

screenCnt的值:

4.原始与变换坐标计算

通过screenCnt.reshape(4, 2)将其变为4x2的矩阵,之后* ratio得到的pts矩阵为:

即:
{t1(2222.784,151.776)t1(93.024,876.384)t1(685.44,2291.328)t1(2624.256,1439.424)\begin{cases}t_{1}\left( 2222.784,151.776\right) \\ t_{1}\left( 93.024, 876.384\right) \\ t_{1}\left(685.44,2291.328\right) \\ t_{1}(2624.256,1439.424) \end{cases}⎩⎨⎧​t1​(2222.784,151.776)t1​(93.024,876.384)t1​(685.44,2291.328)t1​(2624.256,1439.424)​

这里4个点用 t1−4t_{1-4}t1−4​ 表示是因为这4个点的前后顺序不能代表其相对位置关系,两者没有任何关联

之后通过order_points函数获取输入坐标点

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 rect

过程如下:

之后进行位置变换,给出函数four_point_transform

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

中间变量如下:


给出(tl, tr, br, bl)变换前)的表达:
{Atl(93.024,876.384)Btr(2222.784,151.776)Cbr(2624.256,1439.424)Dbl(685.44,2291.328)\begin{cases}A_{tl}\left( 93.024, 876.384\right) \\ B_{tr}\left( 2222.784,151.776\right) \\ C_{br}\left(2624.256,1439.424\right) \\ D_{bl}(685.44,2291.328) \end{cases}⎩⎨⎧​Atl​(93.024,876.384)Btr​(2222.784,151.776)Cbr​(2624.256,1439.424)Dbl​(685.44,2291.328)​

给出dst变换后)的表达:
{A(0.,0.)B(2248.,0.)C(2248.,1532.)D(0.,1532.)\begin{cases}A\left(0.,0.\right) \\ B\left( 2248. , 0.\right) \\ C\left(2248. ,1532.\right) \\ D(0. ,1532.) \end{cases}⎩⎨⎧​A(0.,0.)B(2248.,0.)C(2248.,1532.)D(0.,1532.)​

画个图大概是这样:

其中通过cv2.getPerspectiveTransform(rect, dst)函数求解变换矩阵

原理可看b站视频:透视变换矩阵求解推导(通俗易懂)

5.显示识别结果

5.1.图像处理

之后依次灰度化,二值化处理:

# 灰度,二值处理
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1]# 把ref写入scan.jpg
cv2.imwrite('scan.jpg', ref)

5.2.修改图片大小,并逆时针旋转90度

借鉴博客:

opencv-python 图片旋转90度

cv2.getRotationMatrix2D()

# 修改图片大小,同时图像逆时针旋转90度# 获取图片,修改一下图片的大小
img = cv2.imread("scan.jpg")
# 注意需要制定返回值为img2,不能没有返回值
img2 = cv2.resize(img, (900, 600))
cv2.imshow("temp", img2)
cv2.waitKey(0)
# 对图片进行旋转
# 方法一
# img90 = np.rot90(img2)
# 方法二
# 绕任意点旋转
# 第一个参数旋转中心,第二个参数旋转角度,第三个参数:缩放比例
M = cv2.getRotationMatrix2D((450, 450), 90, 1)
# 仿射变化
# 第三个参数:输入图像的大小
img90 = cv2.warpAffine(img2, M, img2.shape[:2])
# (600, 900)与img2.shape[:2]等价
# img90 = cv2.warpAffine(img2, M, (600, 900))
cv2.imwrite('scan.jpg', img90)
# cv2.imshow("rotate", img90)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

5.3.显示图像

print("STEP 3: 变换")
# cv2.imshow("Original", resize(orig, height = 650))
cv2.imshow("Scanned", resize(img90, height = 650))
cv2.waitKey(0)

旋转前:


旋转后:

6.OCR识别

在这里用github开源OCR软件tesseract,可看:

https://github.com/tesseract-ocr/tesseract

下载地址:

https://digi.bib.uni-mannheim.de/tesseract/

我的安装路径是:F:\soft_f\Tesseract-OCR,安装完记得配一下环境变量(我只配了用户变量),之后输入tesseract -v有(版本可高可低,我安装的是高版本):

在python中pytesseract与安装在本地的tesseract-ocr.exe文件是一起使用的,因此需要pip install pytesseract,我的python环境在F:\F_software\Anaconda,安装如下:

在执行text = pytesseract.image_to_string(Image.open(filename))时发生了报错:

发现即使是配置了环境变量,也找不到tesseract的路径(原因未知QAQ),解决办法:打开F:\F_software\Anaconda\Lib\site-packages\pytesseract

修改一下tesseract_cmd = 'F:/soft_f/Tesseract-OCR/tesseract.exe'

如果还是报错就重启一下电脑(有时候有些配置需要重启电脑才能生效)

这样就可以识别了,代码如下:

from PIL import Image
import pytesseract
import cv2
import ospreprocess = 'blur' #thresh# 读入scan.py的输出结果图像:scan.jpg
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)                                   

识别结果:

=Ce ee ee ee eeWHOLE FOODS MARKE)
399 POST RD WEST - (203) 227-6858WHOLE
FOODS
(mM AR KE T)WESTPORT.CT 06880Seb BALUN LS NP 4
$65 BACUN LS NP 499$65 BREON LS NP 4305 BACUN iS fi 4
BROTH CHIL ae é 19
HLQUR ALMUND NP ol 99CHKN BRST BNLSS SK 8 18 80
HEAVY CREAM $.39
BALSMC REODUCT 6.49BEEF GRND 85/15 5.04JUICE COF CASHEW 8
DOCS PINI ORGAile NP 14.49
HNY ALMOND bulithk NP 9eee TAX 00 Rat 101.33

倾斜文档扫描与ocr识别(opencv,坐标变换)相关推荐

  1. 深入学习OpenCV文档扫描OCR识别及答题卡识别判卷(文档扫描,图像矫正,透视变换,OCR识别)

    人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力.FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台.每周免费提供 ...

  2. opencv项目实战(2)——文档扫描OCR识别

    文章目录 思路 文档扫描 代码 运行结果 文字识别 预处理 代码 运行结果 Debug 记录 思路 STEP 1: 边缘检测 STEP 2: 获取轮廓 STEP 3: 变换 文档扫描 代码 scan. ...

  3. OpenCV计算机视觉实战(Python)| 10、项目实战:文档扫描OCR识别

    文章目录 简介 总结 1. 介绍 2. 流程 3. 程序 4. 知识点总结 简介 本节为<OpenCV计算机视觉实战(Python)>版第10讲,项目实战:文档扫描OCR识别,的总结. 总 ...

  4. 计算机视觉-OpenCV(文档扫描OCR识别)

    一.边缘检测 二.获取轮廓 三.变换 四.OCR识别 import cv2 import numpy as np import argparse import pytesseract import o ...

  5. opencv项目实战(二)——文档扫描OCR识别

    一.项目描述 二.代码详解 2.1 预定义参数 2.2 辅助函数 2.3 文档矫正 2.4 文档识别 三.项目完整代码 一.项目描述 目的 将图片中的文档矫正,并识别文档内容 输入与输出 方法流程 核 ...

  6. OpenCV OCR实战 文档扫描与文字检测

    本文讲述使用OpenCV- python以及easyocr库实现文档扫描与文字检测的思路和具体实现过程. 目录 知识准备 项目概述 实现过程 代码讲解 1.读入图片并进行预处理(灰度转换,高斯滤波) ...

  7. Opencv实战——OCR文档扫描

    文章目录 前言 一.安装Tesseract-OCR 二.文档扫描 1.需要透视变换的图像 2.直接Tesseract-OCR 总结 前言 这里实现文档扫描主要是依靠Tesseract,Tesserac ...

  8. 文档扫描OCR识别-2

    凯哥英语视频 文档扫描OCR识别-2 凯哥英语视频 1.现有资源梳理 2.实现方案规划 预处理 预测 3.代码实现 注意点 模型安装和其他 结语 1.现有资源梳理 文档扫描OCR识别-1 中处理好的图 ...

  9. 项目实战——文档扫描OCR识别

    扫描全能王的实现,maybe 目录 一.文档扫描 1.引入所需要的库 2.图像的读取与预处理 读取图像 图像reszie, 图像灰度化.滤波.边缘检测. 3.轮廓检测 4.透视与二值变换 二.文字识别 ...

最新文章

  1. 云创大会来了!全行业关心的热点都在这里
  2. CNN卷积层图像和矩阵转换函数
  3. windows和linux主机名,windows和linux下如何远程获取操作系统版本和主机名
  4. python 合并excel 自动更新_手把手教你4种方法用Python批量实现多Excel多Sheet合并
  5. IDEA创建工程时 报错 Initialization failed for 'https://start.spring.io'
  6. 数据结构(线性表)——神奇的幻方
  7. 笔记-配置博客园客户端代码高亮(2016.08.20)
  8. 模板题——单链表双链表,数组模拟的栈和队列,单调栈和单调队列
  9. Go 语言的垃圾回收算法被吹过头?与Java比如何?
  10. java运用jsp_JSP:JAVA Bean在JSP中的运用
  11. opencv矩阵转eigen_矩阵迹运算介绍及C++/OpenCV/Eigen的三种实现
  12. c语言 两个文件相似度比较,比较两文件的相似度(比较中文)
  13. 詹姆斯•高斯林/关于Java的故事
  14. OpenCV Mat::ones()用法及注意事项
  15. python 点云重建_点云 表面重建
  16. 计算机导论课后总结3
  17. No387FirstUniqueCharacterInAString
  18. 带你薅“云”羊毛:定个小目标,先薅他一年
  19. 阿里云视频点播(vod)踩过的坑
  20. 令人惊叹的概念手机--“福田杯”中国手机设计大赛的作品系列

热门文章

  1. 汽车改装贴膜小程序开发制作功能介绍
  2. (BAT批处理)批处理命令怎么校验文件MD5哈希值?
  3. 从Java 8 到 Java 14,几个令人印象深刻的新特性
  4. 学习中用到的python脚本记录
  5. IDA7.0 MacOS报错Oops,IDA has almost crashed!解决方案
  6. IOS ANE的坑爹之路二
  7. 三十六、moved异常说明及操作
  8. (8.1.5.4)Android Testing Support Library翻译之Espresso 备忘录
  9. 共享经济跨界创新,共享办公掀起风潮
  10. 华为在全球500强排名跃升,因拥中国市场