OpenCV 透视变换

article/2025/10/3 21:26:28

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://chatgpt.dhexx.cn/article/oSuDbu4y.shtml

相关文章

深入探索透视投影变换

深入探索透视投影变换 最近更新:2013年11月22日 -Twinsen编写 -本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教 -email: popyynetease.com -B站专栏: https://b23.tv/oWsl6PD 透视投影是3D固定流水线的重要组…

图像透视变换原理及实现

上篇博客讲解了图像的仿射变换原理及实现,这篇博客讲讲透视变换的原理和实现,透视变换也叫投影变换,仿射变换是透视变换的特例。主要是透视变换能保持“直线性”,即原图像里面的直线,经透视变换后仍为直线。下面给出数…

(十四)透视变换

透视变换(Perspective Transformation) 一 图像变换与平面坐标系的关系 1、旋转: 2、平移: 3、刚体变换 4、仿射变换 5、投影变换(单应性变换) 6 总结一下: 1、刚体变换:平移旋转,只改变物体…

图像畸变矫正——透视变换

图像畸变矫正——透视变换 由于相机制造精度以及组装工艺的偏差引入的畸变,或者由于照片拍摄时的角度、旋转、缩放等问题, 可能会导致原始图像的失真,如果要修复这些失真,我们可以通过透视变换,对图像进行畸变矫正。 …

透视变换原理实例代码详解

导读 在上篇文章中,我们介绍了仿射变换,我们只需要通过一个两行三列的变换矩阵M就能够对图像实现平移、缩放、翻转、旋转操作。我们发现这些变换其实都属于平面变换,如果我们想要进行空间变换呢? 将上图的扑克牌单独提取出来&am…

[解疑]图像、矩阵的二维空间变换

本文经过参考多个文章整理而成,感谢各位博主的无私分享。 综述 图像(2维平面)到图像(2维平面)的四种变换包括:等距变换,相似变换,仿射变换,投影变换。对图像的几何变换…

数字图像处理(入门篇)十四 透视变换

目录 一 透视变换 二 实践 (1)代码 (2)结果图 一 透视变换 现实生活中的空间是三维的,图像中的物体存在近大远小的特征,这种畸变仿射变换不能矫正。因此,我们需要使用到三维空间的变化&…

【图像理论】透视变换

透视变换: 定义:本质是将图像投影到一个新的视平面。仿射变换可以理解为透视变换的特殊形式。利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某…

Python图像处理之透视变换

1 引言 如果你想对图像进行校准,那么透视变换是非常有效的变换手段。透视变换的定义为将图像投影到一个新的视平面,通常也被称之为投影映射。 2 公式 一般来说,通用的图像变换公式如下所示: 上述公式中,u,v代表原…

维特比算法 python_维特比算法理解与实现(Python)

前言 写这篇文章就是想以通俗易懂的方式解析维特比算法,最后给出Python代码的实现。下面的公式和原理均出自《统计学习方法》。 算法的原理 算法的原理1.PNG 算法的原理2.PNG 上面写了一大堆,意思就是:每个时刻选择出概率最大的路径&#xf…

viterbi-algorithm 维特比算法的例子解析

维特比算法的目的: 寻找最可能的隐藏状态序列(Finding most probable sequence of hidden states) 关于原理的讲解可以参考下面两篇文章,讲的比较清楚 小白给小白详解维特比算法1. 小白给小白详解维特比算法2. 本文通过分析维特比算法的例子&#xff0c…

维特比算法代码

维特比算法实现python语言版 本文主要写一个关于维特比算法的代码,具体理论请参考一文搞懂HMM(隐马尔可夫模型): HMM(隐马尔可夫模型)是用来描述隐含未知参数的统计模型,举一个经典的例子&…

维特比算法学习

参考文章1: 简直不要太通俗易懂,这篇文章,很值得看 参考文章2: 解释一些概念性的问题,我把他的一些内容写下来 维特比(Viterbi)算法的核心是动态规划。 对于 HMM 而言,其中一个重要的任务就是要找出最有…

5分钟理解维特比算法

安德鲁维特比老人家发明了维特比算法,用非常巧妙的方法简化了隐马尔可夫第二个问题运算过程。维特比先生后来发明了CDMA技术并与人一起创办了高通公司,高通现在是通信巨头,不生产产品却每年收取大量的专利费。 下面我们用简单的例子&#xff…

Viterbi-Algorithm(维特比算法)

Viterbi-Algorithm 维特比算法是一个特殊但应用最广的动态规划算法。利用动态规划,可以解决任何一个图中的最短路径问题。而维特比算法是针对一个特殊的图-篱笆网了(Lattice)的有向图最短路径问题而提出来的。它之所以重要,是因为…

NLP学习笔记06-维特比算法

一序 本文属于NLP学习笔记系列。 上一篇整理了前向最大匹配算法与所有组合算法缺点(时间复杂度太高了)。 二 维特比算法 log(x*y*z) log(x)log(y)log(z) 概率上为了避免小数练乘出现的超范围溢出,改用log,改用-log,使得原来求概…

HMM-维特比算法

HMM-维特比算法(viterbi) HMM回顾隐马科夫链解法:维特比算法(Viterbi) HMM回顾 最终的公式可以解释主要分为两个部分: P(xi|yi),发射概率,字面意思是从一个词性中发射/生成出某一个…

Viterbi算法(维特比算法)

维特比算法背景: 安德鲁维特比(Andrew J. Viterbi),CDMA之父,IEEE Fellow,高通公司创始人之一,高通首席科学家。他开发了卷积码编码的最大似然算法而享誉全球。1991年香农奖(Claude …

HMM+维特比算法

一、简介 Viterbi 算法 考虑到穷举方法的缺点,可以采用:Viterbi 算法: 动态搜索最优状态序列,这样每个节点保存的是到当前节点的局部最优概率;依据最后一个时刻中概率最高的状态,逆向找其路径中的上一个最大部分最优路…

维特比算法的java实现_原创:维特比算法

看了宗成庆博士的《统计自然语言处理(中文信息处理)》的第六章,对维特比算法有着非常精辟的讲解。把其中的讲解上传上来,个人感觉比较正统。 今天用Java实现了这个算法,也可以转换为C代码: package com.nlp.hmm.algorithm.viterbi…