最常见的几何变换有仿射变换和单应性变换两种,最常用的仿射变换有缩放、翻转、旋转、平移。
1. 缩放
将图像放大或缩小会得到新的图像,但是多出的像素点如何实现----插值
1.1 插值方法
最近邻插值
双线性插值
cv2.resize()
是 OpenCV 中用于调整图像大小的函数。它可以将图像缩放到指定尺寸,或按照比例进行缩放,是图像处理任务中非常常用的功能之一。
python
cv2.resize(src, dsize, dst=None, fx=0, fy=0, interpolation=cv2.INTER_LINEAR)
参数详解
-
src
(必选):- 输入图像,数据类型为 NumPy 数组。
- 形状可以是灰度图 (
H x W
) 或彩色图 (H x W x C
)。
-
dsize
(必选):- 输出图像的目标尺寸,格式为
(width, height)
。 - 如果提供了
dsize
,则会忽略fx
和fy
参数。
- 输出图像的目标尺寸,格式为
-
dst
(可选):- 输出图像(默认为
None
)。 - 通常不使用这个参数,返回值即为调整后的图像。
- 输出图像(默认为
-
fx
和fy
(可选):- 分别表示图像在宽度方向 (
x
) 和高度方向 (y
) 的缩放因子。 - 如果设置了
fx
和fy
,会按照比例缩放图像,忽略dsize
。
- 分别表示图像在宽度方向 (
-
interpolation
(可选):- 插值方法,用于在缩放过程中生成新像素值。常见选项有:
cv2.INTER_NEAREST
: 最近邻插值,速度快,质量较差。cv2.INTER_LINEAR
: 双线性插值(默认),适用于缩小图像。cv2.INTER_CUBIC
: 双三次插值,适用于放大图像,质量较高但速度较慢。cv2.INTER_LANCZOS4
: Lanczos 插值,适用于高质量缩放。cv2.INTER_AREA
: 使用像素区域关系插值,适用于缩小图像,效果较好。
- 插值方法,用于在缩放过程中生成新像素值。常见选项有:
返回值
- 返回调整大小后的图像,数据类型与输入图像相同。
2. 翻转、旋转和平移
2.1 翻转
图像的翻转是指以某条线为轴进行翻转图像得到一副新的图像,新的图像与原始图像关于翻转轴对称。
cv2.flip()
是 OpenCV 提供的一个图像翻转函数,用于按照指定的轴对图像进行镜像翻转操作。通过这个函数,可以实现水平翻转、垂直翻转或同时进行水平和垂直翻转。
python
cv2.flip(src, flipCode)
参数详解
-
src
(必选):- 输入图像,数据类型为 NumPy 数组。
- 可以是灰度图(
H x W
)或彩色图(H x W x C
)。
-
flipCode
(必选):- 控制图像的翻转方向,值的取值意义如下:
0
: 沿 x 轴(垂直翻转) 翻转。1
: 沿 y 轴(水平翻转) 翻转。-1
: 同时沿 x 轴和 y 轴(中心对称翻转) 翻转。
- 控制图像的翻转方向,值的取值意义如下:
返回值
- 返回翻转后的图像,数据类型和形状与输入图像一致。
2.2 旋转
图像的旋转是指以某一点为旋转中心旋转图像得到一副新的图像。
2.3 平移
图像的平移是指图像沿着平面内的某一方向移动一定距离得到一副新的图像。
3. 仿射变换
图像的仿射变换是将图像进行一系列的线性变换(缩放、旋转、错切)和平移变换得到新图像的操作;新图像保留了原始图像点的共线性以及线之间的平行线、线段间的长度比
cv2.warpAffine()
是 OpenCV 中用于对图像进行仿射变换的函数,可以实现平移、旋转、缩放等操作。以下是函数的详解。
python
cv2.warpAffine(src, M, dsize, dst=None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=0)
参数详解
-
src
输入图像,通常是一个二维灰度图或三维彩色图像(
numpy.ndarray
格式)。 -
M
仿射变换矩阵(2x3 矩阵)。这是图像变换的核心参数,定义了如何操作图像的像素点位置。
- 仿射变换可以表示为:
- 仿射变换可以表示为:
-
dsize
输出图像的尺寸,格式为
(width, height)
。- 决定了输出图像的大小。
-
dst
(可选)输出的目标图像,通常省略。
-
flags
插值方法,用于计算目标像素值。常见选项:
cv2.INTER_NEAREST
:最近邻插值(速度最快,质量较低)。cv2.INTER_LINEAR
:双线性插值(默认,平衡速度和质量)。cv2.INTER_CUBIC
:三次插值(质量较高,但速度慢)。cv2.INTER_LANCZOS4
:Lanczos 插值(用于缩小图像时效果最好)。
-
borderMode
(可选)定义边界像素的处理方式。常见选项:
cv2.BORDER_CONSTANT
:填充常量值(默认)。cv2.BORDER_REPLICATE
:复制边缘像素。cv2.BORDER_REFLECT
:反射边界。
-
borderValue
(可选)当
borderMode
为cv2.BORDER_CONSTANT
时,定义填充边界的值。默认是0
,即黑色。
实例代码
以下是使用 cv2.warpAffine
函数实现平移、旋转和缩放操作的 Python 代码示例。我们将通过设置不同的仿射变换矩阵实现这些操作。
完整代码示例
python
import cv2
import numpy as np
# 读取图像
image = cv2.imread("example.jpg")
(h, w) = image.shape[:2]
# 显示原始图像
cv2.imshow("Original Image", image)
# --- 平移操作 ---
# 平移矩阵: 将图像向右平移 50 像素,向下平移 30 像素
tx, ty = 50, 30
translation_matrix = np.array([[1, 0, tx], [0, 1, ty]], dtype=np.float32)
# 使用 warpAffine 应用平移
translated_image = cv2.warpAffine(image, translation_matrix, (w, h))
cv2.imshow("Translated Image", translated_image)
# --- 旋转操作 ---
# 定义旋转中心、角度和缩放比例
center = (w // 2, h // 2)
angle = 45 # 顺时针旋转 45 度
scale = 1.0
# 生成旋转矩阵
rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
# 使用 warpAffine 应用旋转
rotated_image = cv2.warpAffine(image, rotation_matrix, (w, h))
cv2.imshow("Rotated Image", rotated_image)
# --- 缩放操作 ---
# 缩放矩阵: 将图像横向和纵向分别缩放到原来的 1.5 倍
sx, sy = 1.5, 1.5
scaling_matrix = np.array([[sx, 0, 0], [0, sy, 0]], dtype=np.float32)
# 计算缩放后的尺寸
scaled_width = int(w * sx)
scaled_height = int(h * sy)
# 使用 warpAffine 应用缩放
scaled_image = cv2.warpAffine(image, scaling_matrix, (scaled_width, scaled_height))
cv2.imshow("Scaled Image", scaled_image)
# --- 组合操作: 平移 + 旋转 + 缩放 ---
# 创建一个综合仿射变换矩阵
combined_matrix = np.dot(rotation_matrix, scaling_matrix)
combined_matrix[:, 2] += np.array([tx, ty]) # 加入平移分量
# 计算最终图像尺寸
new_width = int(scaled_width)
new_height = int(scaled_height)
# 应用综合仿射变换
combined_image = cv2.warpAffine(image, combined_matrix, (new_width, new_height))
cv2.imshow("Combined Transformation Image", combined_image)
# 等待按键并释放窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明
-
平移操作
仿射变换矩阵:
M translation = [ 1 0 t x 0 1 t y ] M_{\text{translation}} = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \end{bmatrix} Mtranslation=[1001txty]将图像在 x 和 y 方向上分别平移
t_x
和t_y
个像素。 -
旋转操作
使用
cv2.getRotationMatrix2D
生成旋转矩阵,旋转角度和中心点可以自定义。 -
缩放操作
仿射变换矩阵:
M scaling = [ s x 0 0 0 s y 0 ] M_{\text{scaling}} = \begin{bmatrix} s_x & 0 & 0 \\ 0 & s_y & 0 \end{bmatrix} Mscaling=[sx00sy00]
s_x
和s_y
分别是 x 和 y 方向上的缩放比例。 -
组合操作
- 通过矩阵乘法 (
np.dot
) 将多个变换矩阵合并。 - 调整矩阵偏移量(第 3 列)以同时实现平移。
- 通过矩阵乘法 (
运行结果
- Translated Image:图像被平移。
- Rotated Image:图像被旋转。
- Scaled Image:图像被缩放。
- Combined Transformation Image:图像被平移、旋转和缩放的组合效果。
4. 单应性变换
图像的仿射变换保留了原始图像点的共线性以及线之间的平行线、线段间的长度比;但是单应性变换,只保留了共线性。广泛应用于图像校正、全景拼接、图像配准、机器人导航、增强现实领域。
cv2.findHomography
是 OpenCV 中用于计算 单应性矩阵(Homography Matrix)的函数,常用于图像配准(Image Registration)、透视变换(Perspective Transformation)等场景。它可以通过一组点对应关系计算出两幅图像之间的几何变换。
python
retval, H = cv2.findHomography(srcPoints, dstPoints, method=cv2.RANSAC, ransacReprojThreshold=3.0, mask=None, maxIters=2000, confidence=0.995)
参数详解
-
srcPoints
- 类型:
numpy.ndarray
或 类似的可迭代对象,形状为 (N \times 2) 或 (N \times 1 \times 2)。 - 描述:源点集合(图像1中的点坐标)。
这些点是已知的特征点,用于计算单应性矩阵。
- 类型:
-
dstPoints
- 类型:与
srcPoints
相同。 - 描述:目标点集合(图像2中的点坐标)。
每个源点在目标图像中的对应点。
- 类型:与
-
method
(可选)- 类型:整数(用于指定计算方法)。
- 描述:选择计算单应性矩阵的方法。
cv2.RANSAC
(默认):使用随机抽样一致性算法(RANSAC),可排除异常点。cv2.LMEDS
:最小中值算法(Least Median of Squares),对异常值更鲁棒。cv2.RHO
:一种优化方法,适合数据分布较好的情况。
-
ransacReprojThreshold
(仅当使用 RANSAC 方法时生效)- 类型:浮点数。
- 描述:RANSAC 中的重投影误差阈值(以像素为单位)。小于此值的点被视为内点。
-
mask
(可选)- 类型:布尔掩码,
numpy.ndarray
。 - 描述:用于标记内点和外点的输出掩码。
- 内点(符合几何关系的点)标记为
1
。 - 外点(不符合几何关系的点)标记为
0
。
- 内点(符合几何关系的点)标记为
- 类型:布尔掩码,
-
maxIters
(仅在 RANSAC 方法中可用)- 类型:整数。
- 描述:RANSAC 最大迭代次数。
-
confidence
(仅在 RANSAC 方法中可用)- 类型:浮点数,范围为
[0, 1]
。 - 描述:单应性矩阵估计的置信度。
- 类型:浮点数,范围为
返回值
-
retval
- 类型:布尔值。
- 描述:计算是否成功。
-
H
- 类型:3x3 单应性矩阵。
- 描述:定义了两个平面之间的透视关系,表示从源图像到目标图像的映射。
示例 1:计算单应性矩阵
python
import cv2
import numpy as np
# 定义源点和目标点
src_points = np.array([[10, 10], [200, 10], [200, 200], [10, 200]], dtype=np.float32)
dst_points = np.array([[20, 30], [220, 50], [210, 220], [30, 230]], dtype=np.float32)
# 计算单应性矩阵
H, mask = cv2.findHomography(src_points, dst_points, method=cv2.RANSAC)
print("Homography Matrix:")
print(H)
print("Mask of inliers:")
print(mask)
示例 2:图像透视变换
python
import cv2
import numpy as np
# 读取图像
image = cv2.imread("example.jpg")
(h, w) = image.shape[:2]
# 定义源点和目标点
src_points = np.array([[100, 100], [400, 100], [400, 400], [100, 400]], dtype=np.float32)
dst_points = np.array([[50, 150], [450, 100], [400, 450], [100, 400]], dtype=np.float32)
# 计算单应性矩阵
H, _ = cv2.findHomography(src_points, dst_points)
# 应用透视变换
warped_image = cv2.warpPerspective(image, H, (w, h))
# 显示结果
cv2.imshow("Original Image", image)
cv2.imshow("Warped Image", warped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()