仿射变换(Affine Transformation)详解与OpenCV实现
一、前言
在计算机视觉与图像处理领域,图像的几何变换是非常基础而重要的内容。其中,仿射变换(Affine Transformation) 是一种保持"直线性和平行性"的线性几何变换方法。它能实现图像的旋转、平移、缩放、剪切和翻转等多种变换形式,同时仍然保持物体形状的整体结构不变。
本文将从仿射变换的数学原理 、变换矩阵构建 、OpenCV实现方式等角度进行全面讲解,并通过完整的 Python + OpenCV 实例演示整个过程。
二、仿射变换的数学原理
1. 基本概念
仿射变换是一种线性变换与平移的组合。对于任意二维空间点 ((x, y)),经过仿射变换后得到的新坐标 ((x', y')) 可表示为:
其中:
- 
为 线性变换矩阵,控制旋转、缩放、剪切等; - 
为 平移向量; - 
整个式子称为 二维仿射变换矩阵。
 
在 OpenCV 中,仿射矩阵通常写成如下形式(2×3矩阵):

2. 仿射变换的几何特性
仿射变换具有以下特性:
| 特性 | 含义 | 
|---|---|
| 保持直线性 | 直线仍为直线,不会弯曲。 | 
| 保持平行性 | 平行线仍保持平行。 | 
| 不保持长度 | 变换后长度可能变化。 | 
| 不保持角度 | 变换后角度可能改变。 | 
| 保持比例性 | 同一直线上的比例关系保持不变。 | 
正因为这些性质,仿射变换常用于:
- 
图像校正与矫正(例如将倾斜的图片恢复正位)
 - 
图像增强与配准
 - 
摄像头视角变换
 - 
人脸对齐、姿态变换等任务
 
三、OpenCV中的仿射变换函数
在 OpenCV 中,主要涉及两个核心函数:
- 
cv2.getAffineTransform()
 - 
cv2.warpAffine()
 
下面分别讲解其作用与使用方法。
1. cv2.getAffineTransform(src, dst)
该函数根据原始图像与目标图像上对应的三个点坐标 ,计算出一个 2×3 的仿射变换矩阵。
函数原型:
cv2.getAffineTransform(src, dst)
        参数说明:
- 
src:原图上的三个点坐标(类型为 np.float32)。 - 
dst:目标图上的对应三个点坐标。 - 
返回:2×3 的仿射变换矩阵 M。
 
注意:需要提供 恰好三个非共线点 才能唯一确定仿射变换。
2. cv2.warpAffine(src, M, dsize, flags=None, borderMode=None, borderValue=None)
该函数根据计算好的仿射矩阵 M 对图像进行几何变换。
函数原型:
cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)
        参数说明:
| 参数 | 含义 | 
|---|---|
src | 
输入图像 | 
M | 
2×3 仿射变换矩阵 | 
dsize | 
输出图像的尺寸 (width, height) | 
flags | 
插值方式(如 cv2.INTER_LINEAR, cv2.INTER_CUBIC 等) | 
borderMode | 
边界像素的处理方式(如 cv2.BORDER_CONSTANT, cv2.BORDER_REFLECT) | 
borderValue | 
当 borderMode 为恒定边框时使用的填充值 | 
四、仿射变换实例讲解
下面我们通过一段完整的 Python 代码演示仿射变换的全过程。
import cv2
import numpy as np
"""---------------------仿射变换---------------------"""
img = cv2.imread('face1.jpg')
height, width = img.shape[:2]
# 在原图像和目标图像上各选择三个点
mat_src = np.float32([[0, 0], [0, height - 1], [width - 1, 0]])
mat_dst = np.float32([[0, 0], [100, height - 100], [width - 100, 100]])
M = cv2.getAffineTransform(mat_src, mat_dst)  # 得到变换矩阵
# warpAffine(src, M, dsize, ...)
dst = cv2.warpAffine(img, M, dsize=(width, height))
# 拼接显示
imgs = np.hstack([img, dst])
cv2.namedWindow('imgs', cv2.WINDOW_NORMAL)
cv2.imshow("imgs", imgs)
cv2.waitKey(0)
        1. 代码解读
(1)读取图像与尺寸信息
img = cv2.imread('face1.jpg')
height, width = img.shape[:2]
        shape[:2] 返回图像的高和宽,后续用于设定目标变换范围。
(2)定义对应点
mat_src = np.float32([[0, 0], [0, height - 1], [width - 1, 0]])
mat_dst = np.float32([[0, 0], [100, height - 100], [width - 100, 100]])
        这里定义了两组三点:
- 
mat_src:原始图像中的三个参考点; - 
mat_dst:目标图像中这三个点的新位置。 
仿射矩阵由这三组对应关系自动计算。
(3)计算仿射矩阵
M = cv2.getAffineTransform(mat_src, mat_dst)
        假设我们输出的矩阵为:

这表明图像被同时进行了平移、旋转与剪切。
(4)执行仿射变换
dst = cv2.warpAffine(img, M, dsize=(width, height))
        此时,OpenCV 对每个像素执行坐标映射与插值计算,生成新的变换图像。
(5)可视化对比
imgs = np.hstack([img, dst])
cv2.namedWindow('imgs', cv2.WINDOW_NORMAL)
cv2.imshow("imgs", imgs)
cv2.waitKey(0)
        np.hstack() 将两张图像横向拼接展示,方便观察效果差异。
结果中左边是原图,右边是经过仿射变换后的图像。
五、仿射矩阵的物理意义
仿射矩阵中的参数可以分解为若干几何操作的组合。
若将矩阵写作:

则其几何意义如下:
| 参数 | 作用 | 数学意义 | 
|---|---|---|
| a, d | 控制缩放 | 大于1放大,小于1缩小 | 
| b, c | 控制旋转与剪切 | 产生倾斜效果 | 
| t_x, t_y | 控制平移 | 水平或垂直移动图像 | 
例如:

因此,仿射变换实际上是旋转、缩放、平移、剪切的复合操作。
六、仿射变换的常见应用
- 
人脸对齐(Face Alignment)
通过仿射变换将两眼与嘴的位置对齐,便于后续特征提取。
 - 
图像几何校正
修正倾斜的文档或场景图像。
 - 
摄像头角度变换(视角矫正)
将摄像机不同角度拍摄的图像对齐到统一视角。
 - 
数据增强(Data Augmentation)
在深度学习中,通过随机仿射变换生成更多训练样本。
 - 
仿射配准(Affine Registration)
在医学影像、卫星遥感中,用于对齐不同时间的图像。
 
七、与透视变换的区别
| 特征 | 仿射变换 | 透视变换 | 
|---|---|---|
| 输入点数 | 3 对点 | 4 对点 | 
| 矩阵维度 | 2×3 | 3×3 | 
| 是否保持平行性 | 是 | 否 | 
| 是否支持透视深度 | 否 | 是 | 
| 常见用途 | 平移、旋转、缩放、剪切 | 投影校正、角度变化、场景变换 | 
简言之,仿射变换不能产生"透视效果" ,而透视变换(cv2.warpPerspective)可以让平面产生三维投影的视觉变化。
八、插值与边界处理
1. 插值方式(flags)
- 
cv2.INTER_NEAREST:最近邻插值,速度快但锯齿多; - 
cv2.INTER_LINEAR:双线性插值,常用; - 
cv2.INTER_CUBIC:三次插值,质量更高但计算量大。 
2. 边界模式(borderMode)
- 
cv2.BORDER_CONSTANT:填充常数(默认0); - 
cv2.BORDER_REFLECT:镜像填充; - 
cv2.BORDER_REPLICATE:复制边缘像素。 
例如:
dst = cv2.warpAffine(img, M, (width, height), borderMode=cv2.BORDER_REFLECT)
        可以避免边缘出现黑色区域。
九、实验拓展:随机仿射数据增强
我们还可以用仿射矩阵实现随机旋转和平移,增强数据集:
rows, cols = img.shape[:2]
angle = np.random.uniform(-15, 15)
scale = np.random.uniform(0.9, 1.1)
M = cv2.getRotationMatrix2D((cols/2, rows/2), angle, scale)
dst = cv2.warpAffine(img, M, (cols, rows))
        这段代码让图片在 ±15° 范围内随机旋转并随机缩放,有助于提高模型泛化能力。
十、总结
仿射变换是图像几何变换中最常用的技术之一,兼具数学的优雅与工程实用性。它通过三点对应法求出变换矩阵,实现平移、旋转、缩放、剪切等多种操作,同时保持图像的几何直线关系。
在 OpenCV 中:
- 
cv2.getAffineTransform()用于计算仿射矩阵; - 
cv2.warpAffine()用于执行变换。 
通过理解其数学原理与参数意义,我们可以更灵活地控制图像几何结构,实现从视觉校正到数据增强的各种应用。
✅ 总结要点回顾:
- 
仿射变换矩阵是 2×3;
 - 
需提供 3 对非共线点;
 - 
warpAffine实现平移、旋转、缩放、剪切; - 
可搭配不同插值与边界模式;
 - 
广泛应用于人脸对齐、文档矫正、数据增强等领域。
 
