21.4 仿射变换

仿射变换是指图像实现平移、旋转等操作。

要先设置一个2×3变换矩阵M,然后使用cv2.warpAffine()函数对原图像和变换矩阵M进行仿射操作。

变换矩阵M可通过cv2.getAffineTransfrom(points1, points2)函数获得。

原理

一个任意的仿射变换都能表示为 乘以一个矩阵 A (线性变换) 接着再 加上一个向量 B (平移)。

我们能够用仿射变换来表示:

  • 旋转 (线性变换)
  • 平移 (向量加)
  • 缩放操作 (线性变换)

事实上, 仿射变换代表的是两幅图之间的 关系

通常使用2×3矩阵M 来表示仿射变换。


考虑到我们要使用矩阵 AB 对二维向量  做变换, 所以也能表示为下列形式:


如何求得一个仿射变换?

仿射变换基本表示的就是两幅图片之间的 联系 . 关于这种联系的信息大致可从以下两种场景获得:

  1. 我们已知 XT 而且我们知道他们是有联系的. 接下来我们的工作就是求出矩阵M
  2. 我们已知 M  和X . 要想求得T . 我们只要应用算式 T=MX 即可。对于这种联系的信息可以用矩阵M 清晰的表达 (即给出明确的2×3矩阵) 或者也可以用两幅图片点之间几何关系来表达.

因为矩阵M 联系着两幅图片, 我们以其表示两图中各三点直接的联系为例. 见下图:

点1, 2 和 3 (在图一中形成一个三角形) 与图二中三个点一一映射, 仍然形成三角形, 但形状已经大大改变. 如果我们能通过这样两组三点求出仿射变换 (你能选择自己喜欢的点), 接下来我们就能把仿射变换应用到图像中所有的点.

cv2.warpAffine()函数

原型:

cv2.warpAffine(src, M, dsize[,dst[,interpolation [,borderMode[, borderValue]]]]) --> dst

参数

  1. src:输入图像    
  2. M:2×3的变换矩阵
  3. dsize:变换后输出图像尺寸
  4. dst:输出图像。默认为None
  5. interpolation:采用的插值方法。支持的插值算法有:INTER_NEAREST-最近邻插值、INTER_LINEAR   -双线性插值(默认值)、INTER_CUBIC     -双S三次样条插值(4x4像素领域内的双三次插值)、INTER_LANCZOS4     - Lanczos插值(8x8像素领域内的Lanczos插值)
  6. borderMode:边界像素外扩方式。
  7. borderValue:边界像素插值,默认用0填充

返回值:dst

cv2.getAffineTransform() 获取仿射变换矩阵

变换矩阵的获取需要至少三组变换前后对应的点坐标,设取原图上的三个点组成矩阵points1,变换后的三个点组成的矩阵points2

原型:cv2. getAffineTransform (points1,pointts2) --> M

参数

  1. points1:原图像上的3个点 。3x2阶矩阵。np.float32([[x1,y1],[x2,y2],[x3,y3]]
  2. points2:变换后的3个对应点。3x2阶矩阵。np.float32([[x1,y1],[x2,y2],[x3,y3]]

返回值:为2x3阶的仿射变换矩阵。

cv2.getRotationMatrix2D() 获取仿射变换矩阵

原型:cv2. getRotationMatrix2D(center,angle,scale) --> M

参数

  1. center:也是旋转中心(默认是图片的左上角) ,二元组(x,y)
  2. angle:旋转角度。正数表示顺时针旋转,负数表示逆时针旋转。
  3. scale:缩放比例。float。1表示进行等比列的缩放

返回值:为2x3阶的仿射变换矩阵。

平移变换矩阵

平移的变换矩阵M= ,其中∆x 为在宽度方向上的平移量(正数向右,负数向左);其中∆y 为在高度方向上的平移量(正数向下,负数向上)。

旋转变换矩阵

使用函数cv2.getRotationMatrix2D()获得转移矩阵M,然后使用函数cv2.warpAffine()进行仿射旋转变换。

图像的旋转矩阵一般为:


但是单纯的这个矩阵是在原点处进行变换的,为了能够在任意位置进行旋转变换,opencv采用了另一种方式:


其中θ 为旋转角度(正数为逆时针旋转,负数为顺时针旋转);旋转中心默认为图片的左上角。

平移示例

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('C:\\Users\\xxx\\Downloads\\lena.jpg')
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 【构建平移矩阵】
#  [1,0,100]的意思是宽右移距离100, 
#  [0,1,200]的意思是⾼下移200
shiftMat = np.float32([[1,0,100],[0,1,200]])
# 【平移】
dst = cv2.warpAffine(img,shiftMat,(width,height))
# 【显示图像】
plt.figure(figsize=(12.8,4.8))
plt.subplot(121),plt.imshow(img),plt.title('Oringinal',fontSize=24),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(dst), plt.title('translation',fontSize=24),plt.xticks([]),plt.yticks([])

旋转示例

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 【解决plt显示汉字乱码的临时设置】
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 【读原始图】
img = cv2.imread('C:\\Users\\xxx\\Downloads\\lena.jpg')
rows, cols = img.shape[:2]

# 【获取仿射变换矩阵】
#    第一个参数旋转中心,
#    第二个参数旋转角度,
#    第三个参数:缩放比例
M1 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 1)
M2 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 2)

# 【执行仿射变换】
# 得到矩阵后得用到图像的仿射变换函数才可以进行最终图像的变化
dst1 = cv2.warpAffine(img, M1, (cols, rows))
dst2 = cv2.warpAffine(img, M2, (cols, rows))

# 【画图】
plt.figure(figsize=(19.2,4.8))
plt.subplot(131),plt.imshow(img),plt.title('原始图像',fontSize=24),plt.xticks([]),plt.yticks([])
plt.subplot(132),plt.imshow(dst1), plt.title('围绕中心旋转45度',fontSize=24),plt.xticks([]),plt.yticks([])
plt.subplot(133),plt.imshow(dst2), plt.title('围绕中心旋转45度,放大2倍',fontSize=24),plt.xticks([]),plt.yticks([])

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐