《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析

目录

一、透视变换

1、什么是透视变换

2、操作步骤

        1)选择透视变换的源图像和目标图像

        2)确定透视变换所需的关键点

        3)计算透视变换的变换矩阵

        4)对源图像进行透视变换

        5)对变换后的图像进行插值处理

二、轮廓检测

1、什么是轮廓检测

2、操作步骤

        1)图像预处理

        2)边缘检测

        3)边缘连接

        4)轮廓筛选

        5)轮廓绘制

三、项目实施

1、定义展示图片函数

2、定义自动缩放图片大小函数

3、定义轮廓点的排序函数

4、定义透视变换函数

5、读取原图并缩放

        运行结果:

6、进行轮廓检测

        运行结果:

5、绘制最大轮廓

        运行结果:

6、对最大轮廓进行透视变换

        运行结果:

7、旋转、二值化处理

        运行结果:


一、透视变换

1、什么是透视变换

        透视变换是一种图像处理技术,用于将二维平面上的图像或物体映射三维空间中。它通过改变图像的视角和投影来创建一个具有透视效果的图像。

        透视变换通常用于计算机图像形态学计算机视觉领域,用于实现图像的透视效果立体视觉图像校正等应用。它可以模拟人眼在观察远景时的透视效果,使得远处的物体看起来比近处的物体小,同时使得平行线在远处会相交的视觉效果。

        透视变换的实现通常需要通过计算图像中各点在三维空间中的坐标,并将其映射回二维平面上,从而实现透视效果。这个过程涉及到几何变换矩阵运算投影变换等数学概念和算法。

2、操作步骤

        1)选择透视变换的源图像和目标图像

                源图像是需要进行透视变换的原始图像,目标图像是希望得到的透视变换后的图像。

        2)确定透视变换所需的关键点

                根据透视变换的要求,需要选择源图像中的四个关键点以及对应的目标图像中的四个关键点。这四个关键点共同决定了透视变换的变换矩阵。

        3)计算透视变换的变换矩阵

                通过四个关键点的对应关系,使用透视变换的数学公式计算出透视变换的变换矩阵。这个变换矩阵将源图像中的像素映射到目标图像中的像素。

        4)对源图像进行透视变换

                使用计算得到的变换矩阵,对源图像中的每个像素进行变换,计算其在目标图像中的对应像素位置。

        5)对变换后的图像进行插值处理

                由于透视变换可能会导致源图像中的像素映射到目标图像中的非整数位置,因此需要对其进行插值处理,以得到最终的目标图像。

二、轮廓检测

1、什么是轮廓检测

        轮廓检测是一种图像处理技术,用于在图像中找到物体的边界。在图像处理领域中,物体的边界通常被表示为连续的曲线,这些曲线被称为轮廓。轮廓检测算法可以识别图像中的明显变化或不连续的像素,从而确定物体的形状和结构。

        轮廓检测算法的基本原理是通过分析图像中的亮度、颜色或纹理等特征,找到物体与背景之间的显著边缘或变化。常用的轮廓检测算法包括Canny边缘检测、Sobel算子、拉普拉斯算子等

        通过轮廓检测,可以实现图像分割、目标识别、形状匹配等应用。在计算机视觉和图像处理领域中,轮廓检测是一项重要的技术,广泛应用于物体检测与跟踪、图像分析与理解、机器视觉等领域。

2、操作步骤

        1)图像预处理

                首先对输入图像进行预处理,可以包括灰度化、平滑滤波、边缘增强等操作,以减少噪声和突出边缘信息。

        2)边缘检测

                使用边缘检测算法(如Canny、Sobel、拉普拉斯等)来检测图像中的边缘。这些算法通过计算像素间的梯度或差异,找到亮度或颜色变化较大的区域。

        3)边缘连接

                将离散的边缘点连接成连续的轮廓线。常用的方法包括利用边缘点的邻域信息进行连接,或者利用轮廓线的闭合性质进行曲线追踪。

        4)轮廓筛选

                根据一定的准则对检测到的轮廓进行筛选,去除无关的轮廓。可以根据轮廓的长度、面积、形状等特征进行筛选。

        5)轮廓绘制

                最后,将筛选后的轮廓绘制在原始图像上,以便观察和分析。

具体可参考博客:

《深度学习》OpenCV 图像轮廓检测、轮廓处理及代码演示icon-default.png?t=O83Ahttps://ahao1004.blog.csdn.net/article/details/141830045?fromshare=blogdetail&sharetype=blogdetail&sharerId=141830045&sharerefer=PC&sharesource=qq_64603703&sharefrom=from_link

三、项目实施

1、定义展示图片函数

import numpy as np
import cv2
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)

2、定义自动缩放图片大小函数

# 调整图像高宽,保持图像宽高比不变
def resize(image,width=None,height=None ,inter=cv2.INTER_AREA):  # 输入参数为图像、可选宽度、可选高度、插值方式默认为cv2.INTER_AREA,即面积插值dim = None   # 存储计算后的目标尺寸w、h(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:  # 此处表示为width不是None,即指定了宽度,与上述方法一致,计算比值r = width/float(w)dim = (width,int(h*r))resized = cv2.resize(image,dim,interpolation=inter)     # 指定图像大小为上述的dim,inter默认为cV2.INTER_AREA,即面积插值,适用于缩放图像。return resized

3、定义轮廓点的排序函数

def order_points(pts):   # 对输入的四个点按照左上、右上、右下、左下进行排序rect = np.zeros((4,2),dtype='float32')   # 创建一个4*2的数组,用来存储排序之后的坐标位置# 按顺序找到对应坐标0123分别是左上、右上、右下、左下s = pts.sum(axis=1)   # 对pts矩阵的每个点的x y相加rect[0] = pts[np.argmin(s)]    # np.argmin(s)表示数组s中最小值的索引,表示左上的点的坐标rect[2] = pts[np.argmax(s)]    # 返回最大值索引,即右下角的点坐标diff = np.diff(pts,axis=1)   # 对pts矩阵的每一行的点求差值rect[1] = pts[np.argmin(diff)]   # 差值最小的点为右上角点rect[3] = pts[np.argmax(diff)]   # 差值最大表示左下角点return rect   # 返回排序好的四个点的坐标

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)  # 根据原始点和变换后的点计算透视变换矩阵Mwarped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))  # 对原始图像,针推变换矩阵和输出图像大小进行透视变换,返回变换后的图片# 返回变换后的结果return warped

5、读取原图并缩放

# # 读取输入
image = cv2.imread('fapiao.jpg')   # 读取原图
cv_show('image',image)   # 展示原图# 图片过大,进行缩小处理
ratio = image.shape[0] / 500.0  # 计算缩小比率,[0]表示图像的高
orig = image.copy()   # 对原图复制生成副本
image = resize(orig, height=500)   # 更改图像尺寸,输入高度自动生成宽度
cv_show('1',image)   # 展示缩放后的图片
        运行结果:

6、进行轮廓检测

gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)  # 灰度图edged = cv2.threshold(gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]  # 进行二值化,cv2.THRESH_OTSU自动寻找最优全局阈值,255表示高于最优阈值时将其更改为255
cnts = cv2.findContours(edged.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)[1]  # 轮廓检测
# cv2.RETR_LIST表示检索所有轮廓,但是不建立层次关系
# cv2.CHAIN_APPROX_SIMPLE 表示只保存轮廓拐点的信息
# 总体返回处理的图像、轮廓列表、层次结构,这里返回索引为1,表示返回轮廓列表image_contours = cv2.drawContours(image.copy(),cnts,-1,(0,0,255),1)  # 绘制所有轮廓
# 在原始图像的副本上绘制了轮廓
# 绘制轮廓的位置为上述获取的拐点信息,绘制线条颜色为红色BRG(0,0,255),线条粗细为1个像素cv_show('image_contours',image_contours)  # 展示绘制好的图片
        运行结果:

5、绘制最大轮廓

screenCnt = sorted(cnts,key = cv2.contourArea,reverse=True)[0]   # 对上述获取的轮廓列表,排序依据是轮廓面积,reverse=True表示降序,[0]表示获取面积最大的轮廓
peri = cv2.arcLength(screenCnt,True)   # 计算最大轮廓的周长
screenCnt = cv2.approxPolyDP(screenCnt,0.02*peri,True)  # 轮廓近似,近似为一个多边形,表示新的轮廓与原来的轮廓最大距离不超过原始轮廓宽度的0.02倍,True表示轮廓为闭合的
image_contour = cv2.drawContours(image.copy(),[screenCnt],-1,(0,255,0),2)  # 绘制轮廓,将上述找到的轮廓绘制到原图的副本上
cv2.imshow('image_contour',image_contour)
cv2.waitKey(0)
        运行结果:

6、对最大轮廓进行透视变换

warped = four_point_transform(orig,screenCnt.reshape(4,2)*ratio)  # 输入参数原图,将最大轮廓图形状改变为4*2的格式,即四个点,然后乘以上述定义的比率来缩放轮廓
cv2.imwrite('invoice_new.jpg',warped)   # 将经过透视变换处理的图片存入本地
cv2.namedWindow('xx',cv2.WINDOW_NORMAL)  # 设置一个窗口,名称为xx,这个窗口大小用户可通过拖动随意调节大小
cv2.imshow('xx',warped)  # 展示经过透视变换处理的图片
cv2.waitKey(0)
        运行结果:

7、旋转、二值化处理

# 二值处理
warped = cv2.cvtColor(warped,cv2.COLOR_BGR2GRAY)   # 导入新的图片的灰度图
ref = cv2.threshold(warped,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]  # 对灰度图进行二值化处理kernel = np.ones((2,2),np.uint8)   # 设置一个单位矩阵,大小为2*2,表示设置核kernel的大小
ref_new = cv2.morphologyEx(ref,cv2.MORPH_CLOSE,kernel)   # 闭运算,先膨胀再腐蚀
ref_new = resize(ref_new.copy(),width=500)   # 对闭运算处理完的图像重置大小
cv_show('yy',ref_new)
rotated_image = cv2.rotate(ref_new,cv2.ROTATE_90_COUNTERCLOCKWISE)  # 对图像逆时针旋转90度
cv2.imshow('result',rotated_image)
cv2.waitKey(0)
        运行结果:

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

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

相关文章

Python | Leetcode Python题解之第454题四数相加II

题目: 题解: class Solution:def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:countAB collections.Counter(u v for u in A for v in B)ans 0for u in C:for v in D:if -u - v in countAB:ans countAB…

网约班车升级手机端退票

背景 作为老古董程序员,不,应该叫互联网人员,因为我现在做的所有的事情,都是处于爱好,更多的时间是在和各行各业的朋友聊市场,聊需求,聊怎么通过IT互联网 改变实体行业的现状,准确的…

k8s实战-2

k8s实战-2 一、Deployment1.多副本2.扩缩容3.自愈&故障转移4.滚动更新5.版本回退 二、Service1.ClusterIP2.NodePort 总结 一、Deployment Deployment 是 k8s 中的一个资源对象,用于管理应用的副本(Pods)。它的主要作用是确保集群中运行…

二分查找一>山脉数组的峰顶索引

1.题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; public int peakIndexInMountainArray(int[] arr) {int left 1, right arr.length-2;while(left < right) {int mid left (right-left1) / 2;if(arr[mid] > arr[mid-1]) left mid;else right mid-1;}ret…

软件测试:postman详解

一、Postman背景介绍 用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的&#xff0c;用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的css、html、脚本等简单的网…

更新C语言题目

1.以下程序输出结果是() int main() {int a 1, b 2, c 2, t;while (a < b < c) {t a;a b;b t;c--;}printf("%d %d %d", a, b, c); } 解析:a1 b2 c2 a<b 成立 ,等于一个真值1 1<2 执行循环体 t被赋值为1 a被赋值2 b赋值1 c-- c变成1 a<b 不成立…

如何搭建自己的域名邮箱服务器?Poste.io邮箱服务器搭建教程,Linux+Docker搭建邮件服务器的教程

Linux系统Docker搭建Poste.io电子邮件服务器&#xff0c;搭建属于自己的域名邮箱服务器&#xff0c;可以无限收发电子邮件&#xff08;Email&#xff09;&#xff01; 视频教程&#xff1a;https://www.bilibili.com/video/BV11p1mYaEpM/ 前言 什么是域名邮箱&#xff1f; …

各省份-产业链现代化水平(2001-2022年)

产业链现代化水平是一个综合性指标&#xff0c;它为我们提供了一个多维度的视角来评估各省份在产业链现代化进程中的发展水平。这个指标涵盖了技术创新、产业升级、生产效率、产业结构优化等多个方面&#xff0c;包含原始数据、测算结果以及参考文献。 2001年-2022年各省份-产…

论文翻译 | Generated Knowledge Prompting for Commonsense Reasoning

摘要 整合外部知识是否有利于常识推理&#xff0c;同时保持预训练序列模型的灵活性&#xff0c;这仍然是一个悬而未决的问题。为了研究这个问题&#xff0c;我们开发了生成知识提示&#xff0c;它包括从语言模型生成知识&#xff0c;然后在回答问题时提供知识作为附加输入。我们…

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…

如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue

TOC ssm779基于SSM的宠物服务平台的设计与实现vue 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#x…

安全帽头盔检测数据集 3类 12000张 安全帽数据集 voc yolo

安全帽头盔检测数据集 3类 12000张 安全帽数据集 voc yolo 安全帽头盔检测数据集介绍 数据集名称 安全帽头盔检测数据集 (Safety Helmet and Person Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型&#xff08;包括YOLOv5、YOLOv6、YOLOv7…

【C++ STL】手撕vector,深入理解vector的底层

vector的模拟实现 前言一.默认成员函数1.1常用的构造函数1.1.1默认构造函数1.1.2 n个 val值的构造函数1.1.3 迭代器区间构造1.1.4 initializer_list 的构造 1.2析构函数1.3拷贝构造函数1.4赋值运算符重载 二.元素的插入,删除,查找操作2.1 operator[]重载函数2.2 push_back函数:…

Redis篇(面试题 - 连环16炮)(持续更新迭代)

目录 目录 目录 &#xff08;第一炮&#xff09;一、Redis&#xff1f;常用数据结构&#xff1f; 1. 项目里面到了Redis&#xff0c;为什么选用Redis&#xff1f; 2. Redis 是什么&#xff1f; 3. Redis和关系型数据库的本质区别有哪些&#xff1f; 4. Redis 的线程模型…

4 思科模拟器的介绍和使用

4 思科模拟器的介绍和使用 思科的IOS给我们提供了三大模式 设备开机后&#xff0c;进入的模式是【用户模式】 Router表示设备的名称 “>”表示用户模式 在用户模式输入"?" 可列出在用户模式可以使用的命令 第二种模式是特权模式,输入enable进入特权模式&…

【C++】入门基础介绍(上)C++的发展历史与命名空间

文章目录 1. 前言2. C发展历史2. 1 C版本更新特性一览2. 2 关于C23的一个小故事: 3. C的重要性3. 1 编程语言排行榜3. 2 C在工作领域中的应用 4. C学习建议和书籍推荐4. 1 C学习难度4. 2 学习书籍推荐 5. C的第一个程序6. 命名空间6. 1 namespace的价值6. 2 namespace的定义6. …

如何解决 MySQL ERROR 1040 (08004): Too many connections ?

MySQL 是最流行的开源关系数据库管理系统之一&#xff0c;它也是开发人员中非常常用的数据库。即便它高度健壮和可伸缩性极强&#xff0c;像任何软件一样&#xff0c;它也可能出现错误。我们会经常遇到一个错误&#xff0c;特别是在高流量系统中&#xff0c;error 1040 (08004)…

DenseNet算法:口腔癌识别

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 DenseNet算法结构 其基本思路与ResNet一致&#xff0c;但是它建立的是前面所有层和后面层的密集连接&#xff0c;它的另一大特色是通过特征在channel上的连接来实现特征重用。 二 设计理念 三…

XSP16受电端取电快充协议芯片的应用及工作原理

受电端取电快充协议芯片XSP16是一款集成PD2.0/3.0、PD3.1、QC2.0/3.0、华为FCP/SCP、三星AFC等全协议芯片&#xff0c;这使得它能够适应不同品牌和设备的需求。支持大电流、大功率140W28V/5A给设备快速供电&#xff0c;该芯片采用小 QFN16_3*3mm封装&#xff0c;芯片支持电压向…

【网络篇】计算机网络——应用层详述(笔记)

目录 一、应用层协议原理 1. 进入应用层 2. 网络应用程序体系结构 &#xff08;1&#xff09;客户-服务器体系结构&#xff08;client-server architecture&#xff09; &#xff08;2&#xff09; P2P 体系结构&#xff08;P2P architecture&#xff09; 3. 进程间通讯 …