OpenCV 透视变换

news2024/9/21 20:45:50

OpenCV 透视变换

  • 1. 简介
  • 2. 仿射变换
    • 2.1. 平移
    • 2.2. 旋转
    • 2.3. 放缩
    • 2.4. 错切
    • 2.5. 仿射变换
  • 3. 透视变换


1. 简介

汽车的360度全景影像,从拍照视角变成鸟瞰图

在这里插入图片描述
这种变换常常用到透视变换
在了解透视变换前,需要了解一下其他的变换,包括 平移,旋转,放缩,错切,以及仿射变换


2. 仿射变换


2.1. 平移

对每一个像素点坐标平移
可以让每一个像素点的 x , y x, y x,y 坐标都加一个变量 T T T

矩阵形式表示:
[ 1 0 T x 0 1 T y 0 0 1 ] [ X Y 1 ] = [ X + T x Y + T y 1 ] \left[ \begin{matrix} 1 &0 &T_x \\ 0 &1 &T_y\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1 \end{matrix} \right] = \left[\begin{matrix} X+ T_x \\ Y + T_y \\ 1 \end{matrix} \right] 100010TxTy1XY1=X+TxY+Ty1

等式左边 [ X , Y , 1 ] [X,Y,1] [X,Y,1]是像素坐标的齐次形式
等式右边是平移之后的坐标


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 平移变量
T_x, T_y = 10, 20 

# 构造移动矩阵H 2*3
H = np.float32([[1, 0, T_x],
                [0, 1, T_y]])

# 平移变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Translate img', new_img)
cv2.waitKey(0)

2.2. 旋转

对每一个像素点坐标旋转
假设初始旋转角度为 ϕ \phi ϕ,可以用 ( 1 , 0 ) (1, 0) (1,0) ( 0 , 1 ) (0, 1) (0,1)基向量旋转理解
在这里插入图片描述

矩阵形式表示:
[ c o s ϕ − s i n ϕ 0 s i n ϕ c o s ϕ 0 0 0 1 ] [ X Y 1 ] = [ c o s ϕ X − s i n ϕ Y s i n ϕ X + c o s ϕ Y 1 ] \left[ \begin{matrix} cos\phi & -sin\phi &0 \\ sin\phi & cos\phi & 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1\end{matrix} \right] = \left[ \begin{matrix} cos\phi X-sin\phi Y \\ sin\phi X+cos\phi Y \\ 1 \end{matrix} \right] cosϕsinϕ0sinϕcosϕ0001XY1=cosϕXsinϕYsinϕX+cosϕY1


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 旋转变量 30°
sin_phi, cos_phi = 0.5, 0.866

# 构造旋转矩阵H 2*3
H = np.float32([[cos_phi, -sin_phi, 0],
                [sin_phi, cos_phi, 0]])

# 平移变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Rotate img', new_img)
cv2.waitKey(0)

2.3. 放缩

进行放缩,就是将矩形(图像)放缩n倍,也就是长宽各乘一个变量

矩阵形式表示:
[ N x 0 0 0 N y 0 0 0 1 ] [ X Y 1 ] = [ N x X N y Y 1 ] \left[ \begin{matrix} N_x &0 &0 \\ 0 &N_y & 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1 \end{matrix} \right] = \left[\begin{matrix} N_x X\\N_y Y \\ 1 \end{matrix} \right] Nx000Ny0001XY1=NxXNyY1


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 缩放变量
N_x, N_y = 0.9, 0.8

# 构造缩放矩阵H 2*3
H = np.float32([[N_x, 0, 0],
                [0, N_y, 0]])

# 缩放变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Scale img', new_img)
cv2.waitKey(0)

2.4. 错切

错切是在某方向上,按照一定的比例对图形的每个点到某条平行于该方向的直线的有向距离做放缩得到的平面图形

在这里插入图片描述
X轴上的错切:
[ 1 t a n θ 0 0 1 0 0 0 1 ] [ X Y 1 ] = [ X + t a n θ Y Y 1 ] \left[ \begin{matrix} 1 &tan\theta &0 \\ 0 &1 & 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1 \end{matrix} \right] = \left[\begin{matrix} X + tan\theta Y\\ Y \\ 1 \end{matrix} \right] 100tanθ10001XY1=X+tanθYY1
Y轴上的错切:
[ 1 0 0 t a n φ 1 0 0 0 1 ] [ X Y 1 ] = [ X Y + t a n φ X 1 ] \left[ \begin{matrix} 1 & 0 &0 \\ tan\varphi & 1 & 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1 \end{matrix} \right] = \left[\begin{matrix} X \\ Y +tan\varphi X \\ 1 \end{matrix} \right] 1tanφ0010001XY1=XY+tanφX1
整合起来即:
[ 1 t a n θ 0 t a n φ 1 0 0 0 1 ] [ X Y 1 ] = [ X + t a n θ Y Y + t a n φ X 1 ] \left[ \begin{matrix} 1 & tan\theta &0 \\ tan\varphi & 1& 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1 \end{matrix} \right] = \left[\begin{matrix} X+ tan\theta Y \\ Y +tan\varphi X \\ 1 \end{matrix} \right] 1tanφ0tanθ10001XY1=X+tanθYY+tanφX1


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 错切变量 10° 20°
tan_theta, tan_varphi = 0.176, 0.364

# 构造错切矩阵H 2*3
H = np.float32([[1, tan_theta, 0],
                [tan_varphi, 1, 0]])

# 错切变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Scale img', new_img)
cv2.waitKey(0)

2.5. 仿射变换

在这里插入图片描述
[ a 0 a 1 b 0 a 2 a 3 b 1 0 0 1 ] [ X Y 1 ] = [ X t Y t 1 ] \left[ \begin{matrix} a_0 &a_1 &b_0 \\ a_2 & a_3& b_1\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} X \\ Y\\ 1 \end{matrix} \right] = \left[\begin{matrix} X_t\\ Y_t \\ 1 \end{matrix} \right] a0a20a1a30b0b11XY1=XtYt1

仿射变换矩阵,是由原图像平移,旋转,放缩,错切之后得来的,即

如果用2*2的矩阵和2D坐标表示,无法将平移和其他操作一起运算,那么需要“升维”
引入“齐次坐标”,将图像从平面2D坐标变成3D坐标
把缩放,旋转,平移等变换都统一起来,都表示成一连串的矩阵相乘的形式,保证了形式上的线性一致性
目的主要是合并矩阵运算中的乘法和加法

[ 1 t a n θ 0 t a n φ 1 0 0 0 1 ] [ N x 0 0 0 N y 0 0 0 1 ] [ c o s ϕ − s i n ϕ 0 s i n ϕ c o s ϕ 0 0 0 1 ] [ 1 0 T x 0 1 T y 0 0 1 ] = [ a 0 a 1 b 0 a 2 a 3 b 1 0 0 1 ] \left[ \begin{matrix} 1 & tan\theta &0 \\ tan\varphi & 1& 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} N_x &0 &0 \\ 0 &N_y & 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} cos\phi & -sin\phi &0 \\ sin\phi & cos\phi & 0\\ 0 &0 &1 \end{matrix} \right] \left[ \begin{matrix} 1 &0 &T_x \\ 0 &1 &T_y\\ 0 &0 &1 \end{matrix} \right] = \left[ \begin{matrix} a_0 &a_1 &b_0 \\ a_2 & a_3& b_1\\ 0 &0 &1 \end{matrix} \right] 1tanφ0tanθ10001Nx000Ny0001cosϕsinϕ0sinϕcosϕ0001100010TxTy1=a0a20a1a30b0b11


将矩形变换成平行四边形(即变换后各边依旧平行)
在这里插入图片描述

上面公式里有六个变量,因此自然需要至少列六个等式才可计算出该矩阵
所以需要输入至少三对点集

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)


# 定义对应的点 原始1(书本的3个角落坐标)、变换2
pts1 = np.float32([[290, 9], [6, 348], [328, 353]])
pts2 = np.float32([[280, 0], [0, 350], [280, 350]])

# 计算得到转换矩阵 2*2
H = cv2.getAffineTransform(pts1, pts2)

# 错切变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Scale img', new_img)
cv2.waitKey(0)

3. 透视变换

在这里插入图片描述

常见的有文档矫正和汽车摄像头转成鸟瞰图,因为视角的原因,近处宽远处窄,呈不规则的四边形

在这里插入图片描述

仿射变换是单纯对图片进行平移,缩放,错切(倾斜)和旋转,而这几个操作都不会改变图片线之间的平行关系
仿射变换是在二维空间中,而透视变换则是在三维空间中视角的变化

在这里插入图片描述
T1为线性变换完成旋转,错切和放缩,T2完成平移操作,T3就是设了两个变量来表示映射关系


需要选取原图上的四个点以上的点集,并计算出该点集变换后的位置
在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 定义对应的点 原始1(书本的4个角落坐标)、变换2
pts1 = np.float32([[49, 14], [290, 9], [6, 348], [328, 353]])
pts2 = np.float32([[0, 0], [280, 0], [0, 350], [280, 350]])

# 计算得到转换矩阵 3*3
M = cv2.getPerspectiveTransform(pts1, pts2)

# 透视变换
new_img = cv2.warpPerspective(img, M, (280, 350))

cv2.imshow('perspective img', new_img)
cv2.waitKey(0)

谢谢

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

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

相关文章

小白必知必会的几个IP协议知识

小白必知必会的几个IP协议知识1.IP地址属于网络层协议2.路由控制3.数据链路的抽象化4.IP属于面向无连接型1.IP地址属于网络层协议 在计算机通信中,为了识别通信对端,必须要有一个类似于地址的识别码进行标识。 MAC地址是用来标识同一个链路中不同计算机…

【C++泛型学习笔记】函数模板

提到C的程序设计方法,最先想到的便是两种:面向过程和面向对象编程。但是当我们去阅读一些优秀的C库源码时(比如CGAL),就会直接被其的泛型编程劝退。泛型编程也是C程序设计方法中的一种,不同于上述两种设计方…

一文教你从Linux内核角度探秘JDK NIO文件读写本质(下)

接上文一文教你从Linux内核角度探秘JDK NIO文件读写本质(上) 10. JDK NIO 对普通文件的写入 FileChannel fileChannel new RandomAccessFile(new File("file-read-write.txt"), "rw").getChannel();ByteBuffer heapByteBuffer B…

LRU和FIFO页面置换算法模拟实战

Introduction 本文将介绍如何使用LRU和FIFO实现页面置换的模拟(Python实现),并使用缺页率进行算法的评价。 Requirement 先附上具体的要求: 【实验目的】 (1)了解内存分页管理策略 (2)掌握…

[附源码]JAVA毕业设计昆明市人民医院血库管理系统(系统+LW)

[附源码]JAVA毕业设计昆明市人民医院血库管理系统(系统LW) 目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。…

SSM框架-SpringMVC(一)

目录 1 SpringMVC简介 1.1 什么是mvc 1.2 什么是SpringMVC 1.3 SpringMVC的特点 2 入门案例 2.1 开发环境 2.2 创建maven工程 2.3 配置web.xml 2.4 创建请求控制器 2.5 创建SpringMVC配置文件 2.6 测试HelloWorld 2.7 优化配置 3 RequestMapping注解 3.1 RequestM…

3. 递归

3.1 递归 假设你在祖母的阁楼中翻箱倒柜,发现了一个上锁的神秘手提箱。 祖母告诉你,钥匙很可能在下面这个盒子里。 这个盒子里有盒子,而盒子里的盒子又有盒子。钥匙就在某个盒子中。 为找到钥匙,你将使用什么算法? 第一种&…

c++ word 不依赖软件操作

1、Duck 可以提取word的内容与表格,新建工程直接复制源码就可以得到库 使用实例如下所示: using namespace duckx; duckx::Document doc("file.docx"); doc.open(); //获取当前word中所有的表格 for (auto p doc.tabl…

计算机毕业论文java毕业设计选题源代码基于SSM的会议室预约系统

💖💖更多项目资源,最下方联系我们✨✨✨✨✨✨ 目录 Java项目介绍 资料获取 Java项目介绍 《SSM会议室预约系统》该项目主要解决了会议室预约日常工作中的一些问题,采用技术的技术是jsp springmvcspringmybatis cssjs等。 项目…

ARM 汇编写启动代码之设置栈和调用C语言

一、C语言运行时需要和栈的意义 “C语言运行时(runtime)”需要一定的条件,这些条件由汇编来提供。C语言运行时主要是需要栈。 C语言与栈的关系:C语言中的局部变量都是用栈来实现的。如果我们汇编部分没有给 C 部分预先设置合理合…

PAT甲级考试知识点总结和一些看法

0 引言 本人今年PAT甲级考了95分,平时力扣也有再刷(大概有360题),感觉PAT主要还是面向考研党的,里面的题目其实难度是小于力扣的,但这种难度的题目浙大去年考研机试居然有20%的0分我其实不是很理解。 PAT…

【计算机网络】计算机网络复习总结 ------ 物理层

计算机网络 内容管理物理层 physical layer相关概念术语信息数据 data信号 signal码元 code cell 【波特率B --- 信号v】比特率R ---- 数据v基带信号 baseband带通(频带)信号单工 simplex 半双工 全双工失真理想信道奈奎斯特定理 (理想&#…

[附源码]Python计算机毕业设计Django求职招聘网站

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

室内温度控制仿真(Simulink+PLC)

本篇博客将会和大家一起一步步解读Simulink自带的仿真模型(Thermal Model of a House),之后再讨论PLC控制系统控制室内环境温度的一些经验方法。温度控制的大部分控制方法都是采用PID控制,有关PLC的PID控制相关内容可以参看专栏的其它文章,链接如下: 博途PLC 1200/1500P…

CN_计算机网络性能指标@信道利用率@信道吞吐率

文章目录性能指标带宽(Bandwidth)🎈时延(Dely)发送时延🎈传播时延处理时延排队时延时延带宽积往返时延(Round-Trip Time,RTT)吞吐量(Throughput)速率(Speed)带宽(Bandwidth)信道利用率补充利用率信道利用率发送周期发送时间(传输时间)信道利用率计算&…

(附源码)springboot《升学日》日本大学信息及院校推荐网站 毕业设计 251949

基于springboot《升学日》日本大学信息及院校推荐网站 摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于《升学日》日本大学信息及院校推荐网站当然也不能排除在外,随着网络…

面向对象中的继承

面向对象中的继承 封装 低耦合,高内聚 多态 重载&重写 重载 其实这是后台的知识,这么做的原因是:涉及到服务器的承压能力。减轻并发数 重写 子类重写父类中的方法 怎么理解面向对象? 一切皆对象……学院派的答法,尽…

Some App Tech Support 一些应用技术支持

Some App Tech Support 一些应用技术支持 Getting Support: mail: qiudi7323gmail.com or leave comment below. 获得支持: 邮件:qiudi7323gmail.com 或者在下面留下评论。

深入理解Nginx线程池【内附原理讲解以及源码分析】

文章目录🚀前言❓什么是并发编程⭐多进程和多线程并发编程的比较🍎线程池⭐线程池组成⭐线程池的核心组件⭐源码分享⭐线程池关键结构体刨析⭐线程池关键函数刨析🌰总结🚀前言 因为前段时间项目需要所以阅读分析了Nginx线程池源码…

[每周一更]-(第23期):Docker 逻辑图及常用命令汇总

Docker是一种轻量级的虚拟化技术,同时是一个开源的应用容器运行环境搭建平台,可以让开发者以便捷方式打包应用到一个可移植的容器中,然后安装至任何运行Linux或Windows等系统的服务器上。相较于传统虚拟机,Docker容器提供轻量化的…