《OpenCV》——图像透视转换

图像透视转换简介

  • 在 OpenCV 里,图像透视转换属于重要的几何变换,也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。

原理

在这里插入图片描述

实现步骤

  • 选取对应点:要在源图像和目标图像上分别找出至少四个对应的点。这些对应点不能共线,因为它们是计算透视变换矩阵的关键依据。
  • 计算透视变换矩阵:利用 OpenCV 的 cv2.getPerspectiveTransform 函数,依据前面选取的对应点来计算透视变换矩阵。
  • 应用透视变换:使用 cv2.warpPerspective 函数,将计算得到的透视变换矩阵应用到源图像上,从而得到透视变换后的图像。

相关函数

  • cv2.getPerspectiveTransform
    • 功能:计算透视变换矩阵。
    • 语法:cv2.getPerspectiveTransform(src, dst)
    • 参数:
      • src:源图像中四个点的坐标,数据类型为 np.float32。
      • dst:目标图像中对应的四个点的坐标,数据类型为 np.float32。
  • 返回值:返回一个 3×3 的透视变换矩阵。
  • cv2.warpPerspective
    • 功能:对图像应用透视变换。
    • 语法:cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
    • 参数:
      • src:源图像。
      • M:透视变换矩阵。
      • dsize:输出图像的大小,格式为 (width, height)。
      • dst(可选):输出图像。
      • flags(可选):插值方法,如 cv2.INTER_LINEAR 等。
      • borderMode(可选):边界填充模式。
      • borderValue(可选):边界填充值。
  • 返回值:返回透视变换后的图像。

应用场景

  • 图像校正:校正因拍摄角度倾斜而产生畸变的图像,例如校正拍摄的文档图像,使其呈现为标准的矩形。
  • 虚拟现实:在虚拟现实场景中,将二维图像转换为具有透视效果的三维场景,增强沉浸感。
  • 自动驾驶:对车载摄像头拍摄的图像进行透视变换,以获取道路的鸟瞰图,辅助车辆进行路径规划和障碍物检测。

图像透视转换实例

对以下图片进行图像透视转换:
在这里插入图片描述

实例步骤

导入所需库

import numpy as np
import cv2

写入所需函数

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):# 初始化 dim 为 None,用于存储调整后的图像尺寸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))# 使用 cv2.resize 函数根据 dim 和指定的插值方法对图像进行缩放resized = cv2.resize(image, dim, interpolation=inter)# 返回缩放后的图像return resized# 定义一个函数用于显示图像
# name: 显示窗口的名称
# img: 要显示的图像
def cv_show(name,img):# 使用cv2.imshow函数显示图像,第一个参数是窗口名称,第二个参数是要显示的图像cv2.imshow(name,img)# 使用cv2.waitKey(0)等待用户按键,参数为0表示无限等待cv2.waitKey(0)# 定义一个函数用于对输入的四个点进行排序
# pts: 输入的四个点的坐标,是一个形状为(4, 2)的numpy数组
def order_points(pts):# 创建一个形状为(4, 2)的全零数组,数据类型为float32,用于存储排序后的点rect = np.zeros((4,2),dtype="float32")# 计算每个点的x和y坐标之和s = pts.sum(axis=1)# 找到坐标和最小的点,这个点通常是左上角的点rect[0]=pts[np.argmin(s)]# 找到坐标和最大的点,这个点通常是右下角的点rect[2]=pts[np.argmax(s)]# 计算每个点的x和y坐标之差diff = np.diff(pts,axis=1)# 找到坐标差最小的点,这个点通常是右上角的点rect[1]=pts[np.argmin(diff)]# 找到坐标差最大的点,这个点通常是左下角的点rect[3]=pts[np.argmax(diff)]# 返回排序后的四个点return rect# 定义一个函数用于进行四点透视变换
# image: 输入的原始图像
# pts: 输入的四个点的坐标,是一个形状为(4, 2)的numpy数组
def four_point_transform(image,pts):# 调用order_points函数对输入的四个点进行排序rect = order_points(pts)# 解包排序后的四个点,分别赋值给左上角、右上角、右下角和左下角的点(tl,tr,br,bl) = rect# 计算新图像的宽度,通过计算右下角和左下角点之间的距离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))# 创建一个形状为(4, 2)的numpy数组,用于存储变换后的四个点的坐标dst = np.array([[0,0],[maxWidth-1,0],[maxWidth-1,maxHeight-1],[0,maxHeight-1]],dtype="float32")# 使用cv2.getPerspectiveTransform函数计算透视变换矩阵M = cv2.getPerspectiveTransform(rect,dst)# 使用cv2.warpPerspective函数进行透视变换,得到变换后的图像warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))# 返回变换后的图像return warped

获取图片信息并处理图片

import cv2# 读取指定路径的图片,返回一个表示图像的多维数组
image = cv2.imread('dan_zi.jpg')
# 调用自定义的cv_show函数展示原始图像,窗口名为'image'
cv_show('image', image)# 计算原始图像高度与500像素的比例,后续用于恢复尺寸
ration = image.shape[0] / 500.0
# 复制原始图像,避免后续操作修改原始数据
orig = image.copy()
# 调用resize函数将图像高度调整为500像素,保持宽高比
image = resize(orig, height=500)
# 调用cv_show函数展示调整大小后的图像,窗口名为'1'
cv_show('1', image)# 打印提示信息,表明进入轮廓检测步骤
print("STEP 1: 轮廓检测")
# 将调整大小后的图像从BGR颜色空间转换为灰度颜色空间
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 运用Otsu's算法进行二值化处理,得到二值化后的图像
edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 在二值化图像的副本上查找轮廓,使用RETR_LIST检索模式和CHAIN_APPROX_SIMPLE近似方法
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
# 在图像副本上绘制所有检测到的轮廓,颜色为红色,线条宽度为1像素
image_contours = cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 1)
# 调用cv_show函数展示绘制了所有轮廓的图像,窗口名为'image_contours'
cv_show("image_contours", image_contours)# 打印提示信息,表明进入获取最大轮廓步骤
print("STEP 2:获取最大轮廓")
# 按轮廓面积从大到小对检测到的轮廓进行排序,选取面积最大的轮廓
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]# 计算最大轮廓的周长,参数True表示轮廓是封闭的
peri = cv2.arcLength(screenCnt, True)
# 对最大轮廓进行多边形逼近,以减少轮廓上的点数,第二个参数为逼近精度
screenCnt = cv2.approxPolyDP(screenCnt, 0.02 * peri, True)
# 打印逼近后轮廓的形状信息
print(screenCnt.shape)# 在图像副本上绘制逼近后的最大轮廓,颜色为绿色,线条宽度为2像素
image_contour = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 255, 0), 2)# 展示绘制了最大逼近轮廓的图像,窗口名为'image_contour'
cv2.imshow("image_contour", image_contour)
# 等待用户按键,防止窗口立即关闭
cv2.waitKey(0)

进行透视转换

# 调用之前定义的 four_point_transform 函数对原始图像进行四点透视变换
# screenCnt.reshape(4, 2) * ration 是将之前获取的轮廓点恢复到原始图像的尺寸
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ration)
# 将透视变换后的图像保存为 invoice_new.jpg
cv2.imwrite("invoice_new.jpg", warped)
# 创建一个名为 "xxxxx" 的窗口,并且该窗口大小可以调整
cv2.namedWindow("xxxxx", cv2.WINDOW_NORMAL)
# 在 "xxxxx" 窗口中显示透视变换后的图像
cv2.imshow("xxxxx", warped)
# 等待用户按键,防止窗口立即关闭
cv2.waitKey(0)# 将透视变换后的图像从 BGR 颜色空间转换为灰度颜色空间
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
# 调用 resize 函数将灰度图像的宽度调整为 400 像素
warped = resize(warped, 400)
# 对调整大小后的灰度图像使用 Otsu's 算法进行二值化处理
warped = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 调用自定义的 cv_show 函数显示二值化后的图像,窗口名为 "1111"
cv_show("1111", warped)# 创建一个 1x1 的矩形结构元素,用于形态学操作
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
# 对二值化后的图像进行闭运算,填充小孔和连接相邻物体
closeX = cv2.morphologyEx(warped, cv2.MORPH_CLOSE, rectKernel)
# 调用自定义的 cv_show 函数显示闭运算后的图像,窗口名为 'gradX'
cv_show('gradX', closeX)

结果显示

在这里插入图片描述

invoice_new.jpg
在这里插入图片描述

在这里插入图片描述

如果不想使用这张照片,换其他图片也是可以的,处理步骤都是相同的

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

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

相关文章

第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

第十五届的题目在规定时间内做出了前5道,还有2道找时间再磨一磨。现在把做的一些思路总结如下: 题1:握手问题 问题描述 小蓝组织了一场算法交流会议,总共有 50人参加了本次会议。在会议上,大家进行了握手交流。按照惯例…

2025年最新深度学习环境搭建:Win11+ cuDNN + CUDA + Pytorch +深度学习环境配置保姆级教程

本文目录 一、查看驱动版本1.1 查看显卡驱动1.2 显卡驱动和CUDA对应版本1.3 Pytorch和Python对应的版本1.4 Pytorch和CUDA对应的版本 二、安装CUDA三、安装cuDANN四、安装pytorch五、验证是否安装成功 一、查看驱动版本 1.1 查看显卡驱动 输入命令nvidia-smi可以查看对应的驱…

unity插件Excel转换Proto插件-ExcelToProtobufferTool

unity插件Excel转换Proto插件-ExcelToProtobufferTool **ExcelToProtobufTool 插件文档****1. 插件概述****2. 默认配置类:DefaultIProtoPathConfig****属性说明** **3. 自定义配置类****定义规则****示例代码** **4. 使用方式****4.1 默认路径****4.2 自定义路径**…

Web3 与数据隐私:如何让用户掌控个人信息

随着数字化时代的快速发展,互联网已经渗透到我们生活的方方面面,个人数据的收集与使用也变得越来越普遍。与此同时,数据隐私问题逐渐成为全球关注的焦点。传统的互联网平台通常将用户的数据存储在中心化的服务器上,这意味着平台拥…

SQL Server 建立每日自动log备份的维护计划

SQLServer数据库可以使用维护计划完成数据库的自动备份,下面以在SQL Server 2012为例说明具体配置方法。 1.启动SQL Server Management Studio,在【对象资源管理器】窗格中选择数据库实例,然后依次选择【管理】→【维护计划】选项&#xff0…

C++—21、C++ 中构造函数Constructors

一、什么是构造函数? 构造函数是一个特殊的方法,它在类每次实例化创建对象的时侯自动调用,用于初始化对象。 构造函数的名字必须与类名完全相同,并且没有返回类型,甚至连void也没有。 构造函数的目的是确保对象在创…

Tensor 基本操作1 unsqueeze, squeeze, softmax | PyTorch 深度学习实战

本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 目录 创建 Tensor常用操作unsqueezesqueezeSoftmax代码1代码2代码3 argmaxitem 创建 Tensor 使用 Torch 接口创建 Tensor import torch参考:https://pytorch.org/tutorials/beginn…

C# HTTP/HTTPS 请求测试小工具

这是一个使用 C# 语言开发的实用小工具,旨在帮助用户轻松测试 HTTP 和 HTTPS 请求。 该工具可以发送各种 HTTP 和 HTTPS 请求,包括但不限于 GET、POST、PUT、DELETE 等常见的请求类型。通过简洁明了的界面或命令行操作,用户可以方便地输入目…

Kyligence AI 数据智能体:首批亮相神州数码 DC·AI 生态创新中心!

近日,跬智信息(Kyligence)长期合作伙伴神州数码,其 DCAI 生态创新中心正式启幕。 作为首批生态伙伴,Kyligence AI 数据智能体也正式入驻,在这里首次亮相。 Kyligence 是国内最早推出 AI 用数产品的厂商&a…

Vue基础(2)

19、组件之间传递数据 组件与组件之间不是完全独立的&#xff0c;而是有交集的&#xff0c;那就是组件与组 件之间是可以传递数据的 传递数据的解决方案就是 props ComponentA.vue <template><!-- 使用ComponentB组件&#xff0c;并传递title属性 --><h3>…

STM32_SD卡的SDIO通信_基础读写

本篇将使用CubeMXKeil, 创建一个SD卡读写的工程。 目录 一、SD卡要点速读 二、SDIO要点速读 三、SD卡座接线原理图 四、CubeMX新建工程 五、CubeMX 生成 SD卡的SDIO通信部分 六、Keil 编辑工程代码 七、实验效果 实现效果&#xff0c;如下图&#xff1a; 一、SD卡 速读…

【深度学习】2.视觉问题与得分函数

计算机视觉任务 可以通过神经网络搜索是什么类别的动物。 图像实际就是含有数值的三维矩阵。 像素值从0-255可以表示亮度递增的参数。数字越大&#xff0c;像素点越亮。 最后的3表示三个颜色通道&#xff0c;常见的如JPG、RGB等。 现实场景容易发生各种遮蔽现象。 计算机判断…

JVM面试题解,垃圾回收之“分代回收理论”剖析

一、什么是分代回收 我们会把堆内存中的对象间隔一段时间做一次GC&#xff08;即垃圾回收&#xff09;&#xff0c;但是堆内存很大一块&#xff0c;内存布局分为新生代和老年代、其对象的特点不一样&#xff0c;所以回收的策略也应该各不相同 对于“刚出生”的新对象&#xf…

单片机-STM32 IIC通信(OLED屏幕)(十一)

一、屏幕的分类 1、LED屏幕&#xff1a; 由无数个发光的LED灯珠按照一定的顺序排列而成&#xff0c;当需要显示内容的时候&#xff0c;点亮相关的LED灯即可&#xff0c;市场占有率很高&#xff0c;主要是用于户外&#xff0c;广告屏幕&#xff0c;成本低。 LED屏是一种用发光…

Windows cmd常用命令

文章目录 Windows cmd常用命令一、引言二、文件和目录操作1、查看和切换目录2、文件和目录的创建与删除 三、系统信息与网络配置1、系统信息2、网络配置 四、使用示例五、总结 Windows cmd常用命令 一、引言 Windows 命令提示符&#xff08;cmd&#xff09;是一个强大的工具&a…

snippets router pinia axios mock

文章目录 补充VS Code 代码片段注册自定义组件vue routerpinia删除vite创建项目时默认的文件axiosmock3.0.x版本的 viteMockServe 补充 为文章做补充&#xff1a;https://blog.csdn.net/yavlgloss/article/details/140063387 VS Code 代码片段 为当前项目创建 Snippets {&quo…

神经网络基础 | 给定条件下推导对应的卷积层参数

神经网络基础 | 给定条件下推导对应的卷积层参数 按照 PyTorch 文档中 给定的设置&#xff1a; H o u t ⌊ H i n 2 padding [ 0 ] − dilation [ 0 ] ( kernel_size [ 0 ] − 1 ) − 1 stride [ 0 ] 1 ⌋ H_{out} \left\lfloor\frac{H_{in} 2 \times \text{padding}[0]…

欧拉(Euler 22.03)安装ProxySQL

下载离线安装包 proxysql-2.0.8-1-centos7.x86_64.rpm 链接: https://pan.baidu.com/s/1R-SJiVUEu24oNnPFlm9wRw 提取码: sa2w离线安装proxysql yum localinstall -y proxysql-2.0.8-1-centos7.x86_64.rpm 启动proxysql并检查状态 systemctl start proxysql 启动proxysql syste…

Sharding-JDBC 5.4.1+SpringBoot3.4.1+MySQL8.4.1 使用案例

最近在升级 SpringBoot 项目&#xff0c;原版本是 2.7.16&#xff0c;要升级到 3.4.0 &#xff0c;JDK 版本要从 JDK8 升级 JDK21&#xff0c;原项目中使用了 Sharding-JDBC&#xff0c;版本 4.0.0-RC1&#xff0c;在升级 SpringBoot 版本到 3.4.0 之后&#xff0c;服务启动失败…

WPS计算机二级•幻灯片的基础操作

听说这是目录哦 PPT的正确制作步骤&#x1f6e3;️认识PPT界面布局&#x1f3dc;️PPT基础操作 快捷键&#x1f3de;️制作PPT时 常用的快捷技巧&#x1f3d9;️快速替换PPT的 文本字体&#x1f303;快速替换PPT 指定文本内容&#x1f305;能量站&#x1f61a; PPT的正确制作步…