仿射变换 与 透视变换

仿射变换 与 透视变换

几种变换之间的关系


1、缩放 Rescale

1)变换矩阵

缩放变换矩阵,形为 : , 其中: 为 x轴 和 y轴的缩放因子,即 宽高的缩放因子

图像中的每一个像素点 (x, y),经过矩阵变换(如下公式),会落到的新的位置

2)举例

比如,一张图像尺寸为, 经过变换矩阵 变换之后 :

  • 其右下角点(,),落在新的位置 (

  • 图像中的其他点,也会经历同样的变换

  • 对于图像原点 (0, 0),缩放之后,仍为原点 (0, 0)

3)代码演示

注意: 图像默认的原点位置为图像的左上角点

复制代码
import cv2
import numpy as np

src_img = cv2.imread("img.jpg")
height, width = src_img.shape[:2]

M = np.eye(2, 3)
M[0, 0] = 0.8
M[1, 1] = 0.6

dst_img = cv2.warpAffine(src_img, M, (width, height))

cv2.imshow("src_img", src_img)
cv2.imshow("dst_img", dst_img)
cv2.waitKey()
cv2.destroyAllWindows()

2、旋转 Rotation

1)变换矩阵

旋转变换矩阵,形为 : , 其中: 为顺时针旋转角度

图像中的每一个像素点 (x, y),经过矩阵变换(如下公式),会落到的新的位置 ()

2)举例

比如,一张图像尺寸为 , 旋转 ,变换矩阵为: , 变换之后 :

  • 其右上角点(),落在新的位置

  • 图像中的其他点,也会经历同样的变换

  • 对于图像原点 (0, 0), 旋转之后,仍为原点 (0, 0)

3)代码演示

复制代码
import cv2
import numpy as np

src_img = cv2.imread("img.jpg")
height, width = src_img.shape[:2]

M = np.eye(2, 3)
M[0, 0] = np.cos(np.pi / 12)
M[0, 1] = -np.sin(np.pi / 12)
M[1, 0] = np.sin(np.pi / 12)
M[1, 1] = np.cos(np.pi / 12)

dst_img = cv2.warpAffine(src_img, M, (width, height))

cv2.imshow("src_img", src_img)
cv2.imshow("dst_img", dst_img)
cv2.waitKey()
cv2.destroyAllWindows()

3、切变 Shear

1)变换矩阵

切变(Shear):切变通过在坐标系中,斜向拉伸对象来改变其形状 ,但不会改变对象的大小或旋转它,也不会改变原点位置。

切变矩阵如下图所示:

2)举例

比如,一张图像尺寸为 ,沿x轴拉伸,沿y轴不拉伸,则变换矩阵为 ,变换之后 :

  • 其右下角点 ,落在新的位置

  • 图像中的其他点,也会经历同样的变换

  • 对于图像原点 (0, 0), 切变之后,仍为原点 (0, 0)

3)代码演示

复制代码
import cv2
import numpy as np

src_img = cv2.imread("img.jpg")
height, width = src_img.shape[:2]

M = np.eye(2, 3)
M[0, 1] = np.tan(np.pi / 12)

dst_img = cv2.warpAffine(src_img, M, (width, height))

cv2.imshow("src_img", src_img)
cv2.imshow("dst_img", dst_img)
cv2.waitKey()
cv2.destroyAllWindows()

总结一 : 线性变换

1、缩放、旋转、切变 都属于线性变换,他们的特点有以下:

  • 变换之前的原点(0, 0),在变换之后,仍为原点(0, 0)

  • 平直性 : 变换之前的直线,在变换之后 仍为直线

  • 平行性:变换之前的平行线,在变换之后,仍为平行线

2、在二维空间内,线性变换(缩放、旋转、切变)都可以通过 2x2 的变换矩阵,来实现相关的变换计算


4、平移 Translation

1)变换矩阵

之前我们介绍的 缩放、旋转、切变 都可以通过 2x2 的变换矩阵 直接计算得到,而平移则不行。

平移如果用公式表示的话,如下 :

齐次坐标 (Homogeneous Coordinates)

由上可知,平移变换 不能通过 2x2 的转换矩阵 直接进行矩阵乘法得到,所以,我们引入了 "齐次坐标 (Homogeneous Coordinates)"。 在二维情况下,齐次坐标通常由三个值表示,即(x,y,w),其中:

  • x 和 y 是普通的笛卡尔坐标

  • w是一个额外的参数,通常设置为 1 。 也可以理解为,增加了一个维度 z,只不过对象(图像)在这个维度上的值恒为1,也就是在 z=1 这个平面上。

这样,我们就可以将平移变换,写成如下公式表达 :

缩放、旋转、切变 的变换矩阵 也可以拓展为2x3矩阵,比如,旋转变换可以表示为 :

2)代码演示

复制代码
import cv2
import numpy as np

src_img = cv2.imread("img.jpg")
height, width = src_img.shape[:2]

M = np.eye(2, 3)
M[0, 2] = 20
M[1, 2] = 40

dst_img = cv2.warpAffine(src_img, M, (width, height))

cv2.imshow("src_img", src_img)
cv2.imshow("dst_img", dst_img)
cv2.waitKey()
cv2.destroyAllWindows()

5、仿射变换

1)仿射变换

仿射变换为 缩放、旋转、切变、平移 4种变换的任意组合

比如,下面就是 "缩放 + 旋转 + 平移" 的组合,因为 缩放、旋转 都是相对于 原点坐标来操作的,为了保证图像增强中,不会出现意外的结果,一般会将 平移操作放在最后, 即 先线性后平移

仿射变换有以下特点:

  • 变换之前的直线,在变换之后 仍为直线

  • 变换之前的平行线,在变换之后,仍为平行线

2)举例

我们以"缩放 + 旋转 + 平移" 的组合为例,对图像中的点 进行连续变换:

  • 先做 缩放变换,缩放变换矩阵 记为 S

  • 再做 旋转变换,旋转变换矩阵记为 R

  • 最后做 平移变换,平移变换矩阵记为 T

变换后 P点的新位置为P' ,整体的变换表达公式为 :

1)为了使 可以矩阵连乘,S、R、T 都要拓展为 3x3 的变换矩阵:

  • S 形为:

  • R 形为:

  • T形为:

2)因为矩阵乘法满足 乘法结合律 ,所以,上面的变换公式 可写为:

我们令 ,即 为整体的变换矩阵,

3)变换矩阵的位置不可更换 (因为矩阵乘法不满足交换律 $),变换矩阵的顺序决定着 变换的操作顺序

尤其是 平移变换,因为 平移变换始终都是最后做,所以,平移变换矩阵的位置始终都在第一个位置

yolov5 中相关代码示例 :(其中 C 表示将坐标原点 从图像左上角点转换到图像中心点)

2)代码演示

复制代码
import cv2
import numpy as np

src_img = cv2.imread("img.jpg")
height, width = src_img.shape[:2]

# 旋转矩阵
S = np.eye(3, 3)
S[0, 0] = 0.8
S[1, 1] = 0.6

# 旋转矩阵
R = np.eye(3, 3)
R[0, 0] = np.cos(np.pi / 12)
R[0, 1] = -np.sin(np.pi / 12)
R[1, 0] = np.sin(np.pi / 12)
R[1, 1] = np.cos(np.pi / 12)

# 平移矩阵
T = np.eye(3, 3)
T[0, 2] = 40
T[1, 2] = 20

# 仿射变换矩阵
M = T @ R @ S

# 操作变换
dst_img = cv2.warpAffine(src_img, M[:2], (width, height))

cv2.imshow("src_img", src_img)
cv2.imshow("dst_img", dst_img)
cv2.waitKey()
cv2.destroyAllWindows()


6、透视变换 Perspective

仿射变换可以将矩形图片映射为平行四边形 ,而 透视变换 可以将矩形图片映射为任意四边形

1)变换矩阵

透视变换矩阵,形为 :

透视变换分为 2 步 :

对于透视变换 以上2步的理解 :

对于齐次坐标 (x, y, z) ,我们是增加了一个维度 z (这时,z = 1),原始图像是在 z = 1 这个平面上的

  • 第一步,我们将图像,根据变换矩阵,投射到了三维空间中,黄色图像为结果图像,图像中像素点的坐标为

  • 第二步,再将三维空间上的点,给映射回 平面上。 这种映射是基于视觉原理的映射,这时人的视线为 z轴,将第1步得到的结果图像,往 平面上进行映射,示意图如下:

2)代码演示

复制代码
import cv2
import numpy as np

src_img = cv2.imread("img.jpg")
height, width = src_img.shape[:2]

M = np.eye(3, 3)
M[2, 0] = 0.0002
M[2, 1] = 0.0002

dst_img = cv2.warpPerspective(src_img, M, (width, height))

cv2.imshow("src_img", src_img)
cv2.imshow("dst_img", dst_img)
cv2.waitKey()
cv2.destroyAllWindows()

总结二 :变换矩阵

对于 变换矩阵 M,其中的每一个部分,都控制着不同的变换 :

操作顺序一般为 : 先做透视变换、最后做平移变换, 如 yolov5 数据增强中的代码,也是先做透视变换,最后做平移变换 (C 为将原点位置调整到图片中心)

相关推荐
MARS_AI_6 分钟前
云蝠智能VoiceAgent:AI赋能售后服务场景的创新实践
人工智能·语言模型·自然语言处理·人机交互·信息与通信
全星0076 分钟前
从合规到卓越:全星QMS如何成为制造企业的质量战略引擎
人工智能
桃源学社(接毕设)11 分钟前
基于人工智能和物联网融合跌倒监控系统(LW+源码+讲解+部署)
人工智能·python·单片机·yolov8
sp4211 分钟前
白话 LRU 缓存及链表的数据结构讲解(一)
算法
CCF_NOI.19 分钟前
解锁聚变密码:从微观世界到能源新未来
大数据·人工智能·计算机·聚变
张3蜂21 分钟前
深度解读 Browser-Use:让 AI 驱动浏览器自动化成为可能
运维·人工智能·自动化
yunhuibin24 分钟前
pycharm2025导入anaconda创建的各个AI环境
人工智能·python
学术小白人24 分钟前
会议征稿2025年能源互联网与电气工程国际学术会议(EIEE 2025)
人工智能·机器人·能源
2502_927161281 小时前
DAY 40 训练和测试的规范写法
人工智能·深度学习·机器学习
_不会dp不改名_1 小时前
leetcode_42 接雨水
算法·leetcode·职场和发展