计算机视觉(opencv)——仿射变换(Affine Transformation)
仿射变换(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
实现平移、旋转、缩放、剪切;可搭配不同插值与边界模式;
广泛应用于人脸对齐、文档矫正、数据增强等领域。