深度学习图像处理基础工具——opencv 实战2 文档扫描OCR

输入一个文档,怎么进行文档扫描,输出扫描后的图片呢?

今天学习了  opencv实战项目 文档扫描OCR

问题重构:输入图像 是一个含有文档的图像——> 目标是将其转化为 规则的扫描图片

 那么怎么实现呢?

问题分解:

1 边缘检测 

2 获取轮廓

3 对获取到的轮廓进行透视变换

4 OCR

如何边缘检测?

1 把图片读入——预处理(计算坐标缩放比例以便以后使用原图的时候使用,copy原图,

2.获取灰度图——高斯滤波去除噪声,边缘检测)

如何获取需要扫描的轮廓?

1.轮廓检测 检测出所有轮廓,对检测出的所有轮廓按照面积大小分类

2遍历所有轮廓(计算轮廓近似使用到了

cv2.approxPolyDP 是一个用于多边形逼近的函数。它使用Douglas-Peucker算法来减少多边形的点数。 返回的是多边形的顶点坐标数组 详细解释opencv python中的 cv.approxPolyDP_cv::approxpolydp-CSDN博客

 当坐标数组数是4的时候(是四边形的)  把返回结果拿出来

如何进行透视变换?

使用到了四点transformer函数(见后文) 变换  输入 image 原图 和上一步返回的坐标点 输出是变换后的结果

输入的坐标点可能是乱序的,怎么进行上下左右排序?

使用了 order_points 函数  思路:四个坐标 (a,b) a+b 最大的 是右下的点 最小的是左上 b-a  z最小的是右上 最大的是左下 (假设h >w)  返回的是 排序好的rect 

回到 四点transformer函数 

怎么计算透视变换的变换矩阵M  ?需要得到原坐标点 和变换后的坐标点

如何将四边形转化为 矩形?计算上w 和下w 的值 方法 两点间距离公式 取最大,同理 取左h 右h  取最大的高和宽 得到变换后坐标位置

计算变换矩阵  

用到了cv2.getPerspectiveTransform

opencv透视变换:GetPerspectiveTransform、warpPerspective函数的使用-CSDN博客

得到了变换矩阵,怎么进行透视变换?

使用到了cv2.warpPerspective函数,warpPerspective():对图像进行透视变换。简单来说,就是有这么一副图像,它的拍摄视角不是从正面拍摄的,而是带有一定的角度,我们希望能得到从正面观察的视角。 【Python+OpenCV 图像透视变换 warpPerspective函数】-CSDN博客

返回变换后结果warped

得到的warped 是这样的

还要进行二值处理、结果保存

warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('scan.jpg', ref)

最后得到的输出结果如下

代码:

# 导入工具包
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 rect

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

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 image
	if 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)[0]
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 = approx
		break

# 展示结果
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.imshow("warped", resize(warped, height = 650))
cv2.waitKey(0)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

量子城域网系列(三):搭建一个点对点量子保密通信网络

各位小伙伴周末愉快呀,今天是4月14日世界量子日,至于为今天是世界量子日可以围观我之前的文章:关于世界量子日。 之前的文章中我们讨论了量子密钥在通信系统各层协议中的应用,那在实际工程中如何真正落地一个量子加密网络呢&a…

【Linux】序列化与反序列化{服客编程/守护进程/JSON}

文章目录 1.引入2. 静态成员函数3.TCP:传输控制协议4.守护进程4.0前台进程4.1介绍4.2认识4.3会话4.3ps axj4.4理解4.5/dev/null4.6守护进程和孤儿进程 5.JSON6.完整代码6.1Makefile6.2Socket.hpp6.3Protocol.hpp6.4Log.hpp6.5Daemon.hpp6.6TcpServer.hpp6.7Client.c…

2024年DTC的回顾与思考

刚结束了2024的数据库技术嘉年华 这是我从2017年开始就参加的技术大会。中途因为疫情的耽误。正常来说我是连续的。知道我的朋友都知道我习惯炫耀一下。 按照惯例,此时此刻群友都在写大会回顾。只是有几个不讲武德的人已经发送了。下面有主观和客观的分析。 主观上…

HTML图片

图片标签: ~img图片标签 ~是自结束标签 ~属性 ~src表示要引入图片的位置 ~src需要一个路径作为参数 ~alt是对图片的描述 ~帮助搜索引擎来识别图片 ~如果不写alt则搜索引擎不会收录图片 ~width与height只有一个时是同步改变的,但两者同时存在时则是两者按…

AI来了,Spring还会远吗?(Spring AI初体验)

目录 一、创建项目二、first demo1、application.properties2、ChatController3、结果 三、个人思考 一、创建项目 官方文档的Getting Started 最低要求:JDK17 阿里云的Server URL(https://start.aliyun.com/)搜不到Spring AI,…

秒杀优化-Redis完成秒杀资格判断

6.2 秒杀优化-Redis完成秒杀资格判断 需求: 新增秒杀优惠券的同时,将优惠券信息保存到Redis中 基于Lua脚本,判断秒杀库存、一人一单,决定用户是否抢购成功 如果抢购成功,将优惠券id和用户id封装后存入阻塞队列 开启…

五月收到返稿意见,提示语言太差,需要润色

五月收到返稿意见,提示语言太差,需要润色,于是向周围伙伴们打听了是给润色公司还是别的润色软件润色比较好。得出的结论是,如果需要稳妥一点,还是找专门的润色机构,在返稿的时候,附上润色证明&a…

XTTS数据迁移

文章目录 一、全量迁移1、源端和目标端都需要配置XTTS脚本(源库和目标库都需要进行下列配置)2、源端调用 xttdriver.pl -p做迁移准备3、将源端的数据文件副本和rmanconvert.cmd传到目标端4、在目标端对数据文件拷贝进行字节序的转换 二、XTTS 第1~n次增量…

MES实施优势有哪些?MES制造执行系统的主要内容

各个行业之间也开始进入到了激烈的竞争当中,很多企业为了能够有效提升企业竞争力,都会通过提升自身实力的方式来提升竞争力。一些制造业也会在经营过程当中使用到MES系统,那么,mes系统的优势有哪些呢? 1、优化企业现场…

leetcode不同路径

. - 力扣(LeetCode) 62. 不同路径 中等 相关标签 相关企业 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下…

欧姆龙61F系列液位开关使用教程(补水和排水)

欧姆龙61F系列液位开关使用教程(补水和排水) 本文以61F-LS-CP11-NRA型号的液位开关为例进行说明: 具体的选型文档可参考以下链接中的内容: OMRON欧姆龙-无浮标开关(紧凑插入型)61F-LS液位开关-选型样本说明 补水功能(供水) 如下图所示, 电机电源为3相AC220V; 控制电…

单例模式以及常见的两种实现模式

单例模式是校招中最常考的设计模式之一. 设计模式其实就是类似于“规章制度”,按照这个套路来进行操作。 单例模式能保证某个类在程序中只存在唯一 一份实例。而不会创建出多个实例,如果创建出了多个实例,就会编译报错。而不会创建出多个实…

MySQL优化慢SQL的6种方式

⛰️个人主页: 蒾酒 🔥系列专栏:《mysql经验总结》 🌊山高路远,行路漫漫,终有归途 目录 写在前面 优化思路 优化方法 1.避免查询不必要的列 2.分页优化 3.索引优化 4.JOIN优化 5.排序优化 6.UNION 优化…

今天掏心窝子!聊聊35岁了程序员何去何从?

今天的内容不聊技术,聊聊轻松的话题,脑子高速转了好几周,停下来思考一下人生…… 不对,关于35岁的问题好像也不轻松,些许有点沉重,反正不是技术,不用高速转动脑细胞了,哈哈。 兄弟…

牛客 NC36 在两个长度相等的排序数组中找到上中位数【中等 模拟 Java,Go,PHP】

题目 题目链接: https://www.nowcoder.com/practice/6fbe70f3a51d44fa9395cfc49694404f 思路 直接模拟2个数组有顺序放到一个数组中,然后返回中间的数参考答案java import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 pu…

图文教程 | 2024Typora最新版免费激活使用教程(新旧版可用)

一、打开官网下载最新版Typora Typora 官网下载 安装: Typora中文官网:https://typoraio.cn/ Typora官网:https://typora.io/releases/all 官网长这个样子 下面这个不是官网!!!!注意&#x…

【ArcGIS 脚本工具】在ArcPro中实现mdb转gdb

ArcGIS Pro作为主力使用很久了,但是ArcMap也从来没有卸载过。 要问为什么,就是还需要ArcMap来读写mdb数据库,Pro是不支持读写mdb数据库的。 我之前尝试过不借助ArcMap把mdb转成gdb,奈何技术太菜搞不定。 直到我看到了公众号【G…

基于springboot实现洗衣店订单管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现洗衣店订单管理系统演示 摘要 随着信息互联网信息的飞速发展,无纸化作业变成了一种趋势,针对这个问题开发一个专门适应洗衣店业务新的交流形式的网站。本文介绍了洗衣店订单管理系统的开发全过程。通过分析企业对于洗衣店订单管理系统…

JD抓包 | 安卓app抓包

去年11月份左右搞过一次安卓抓包, 搞了很久试了很多方法, 才弄好. 时隔半年, 安卓抓包依然是令我头疼的问题 这次简单记录一下过程(细节太多我也说不清) JD的有效信息接口通常是以下这样的, 其他的接口并没有返回太多"有用"的信息 https://api.m.jd.com/client.act…

快速入门深度学习9.1(用时20min)——GRU

速通《动手学深度学习》9.1 写在最前面九、现代循环神经网络9.1 门控循环单元(GRU)9.1.1. 门控隐状态9.1.1.1. 重置门和更新门9.1.1.2. 候选隐状态9.1.1.3. 隐状态 9.1.3 API简洁实现小结 🌈你好呀!我是 是Yu欸 🌌 20…