图像的仿射变换涉及到图像的形状位置角度的变化,是深度学习预处理中常到的功能,仿射变换主要是对图像的缩放,旋转,翻转和平移等操作的组合。

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

可以用仿射变换来表示:

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

图像的仿射变换,如下图所示,图1中的点1, 2 和 3 与图二中三个点一一映射, 仍然形成三角形, 但形状已经大大改变,通过这样两组三点(感兴趣点)求出仿射变换, 接下来我们就能把仿射变换应用到图像中所有的点中,就完成了图像的仿射变换。

OpenCV 仿射变换_坐标轴
OpenCV 仿射变换_仿射变换_02
需要注意的是,对于图像而言,宽度方向是x,高度方向是y,坐标的顺序和图像像素对应下标一致。所以原点的位置不是左下角而是右上角,y的方向也不是向上,而是向下。

在仿射变换中,原图中所有的平行线在结果图像中同样平行。为了创建这个矩阵需要从原图像中找到三个点以及他们在输出图像中的位置。然后cv2.getAffineTransform 会创建一个 2x3 的矩阵,最后这个矩阵会被传给函数 cv2.warpAffine。

getAffineTransform(InputArray src,InputArray DST)

参数:

  • InputArray src: 表示输入的三个点
  • InputArray dstL: 表示输出的三个点
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

# 1 图像读取
img = cv.imread("1.png")

# 2 仿射变换
rows, cols = img.shape[:2]

# 2.1 创建变换矩阵
#src 3->dst 3 (左上角 左下角 右上角)
src1 = np.float32([[0, 0], [0, cols], [rows, 0]]) # 左上角 左下角 右上角
dst2 = np.float32([[0, 0], [0, cols], [rows, 0]]) # 左上角 左下角 右上角

src3 = np.float32([[50, 50], [200, 50], [50, 200]]) #获取原图像三个角坐标
dst4 = np.float32([[100, 100], [300, 50], [200, 400]]) #变换后图像角坐标

#获取原图像三个角坐标 正数在坐标轴中向上运动 负数在坐标轴中向下运动
src5 = np.float32([[-200, -200], [-200, cols], [rows, -500]])

#变换后图像角坐标 正数在坐标轴中向下运动, 负数在坐标轴中向上运动
dst6 = np.float32([[0, 0], [0, cols], [rows, -240]])

M = cv.getAffineTransform(src1, dst2)

# 2.2 完成仿射变换
dst1 = cv.warpAffine(img, M, (cols * 2, rows * 2)) # 画布大小乘以2

M = cv.getAffineTransform(src3, dst4)
dst2 = cv.warpAffine(img, M, (cols * 2, rows * 2)) # 画布大小乘以2

M = cv.getAffineTransform(src5, dst6)
dst3 = cv.warpAffine(img, M, (cols * 2, rows * 2)) # 画布大小乘以2

# 3 图像显示
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8), dpi=100)
axes[0, 0].imshow(img[:, :, ::-1])
axes[0, 0].set_title("原图")
axes[0, 1].imshow(dst1[:, :, ::-1])
axes[0, 1].set_title("将原图转化仿射变换的表示方法")
axes[1, 0].imshow(dst2[:, :, ::-1])
axes[1, 0].set_title("改变仿射中的数值结果")
axes[1, 1].imshow(dst3[:, :, ::-1])
axes[1, 1].set_title("改变仿射中的数值结果")
plt.show()

OpenCV 仿射变换_线性变换_03