OpenCV(二十二):图像的翻转与旋转
图像翻转(Image Flip)
1. 原理
图像翻转是指相对于某个轴对图像进行镜像反射。
常见翻转类型:
| 类型 | 操作说明 | 变换公式 |
|---|---|---|
| 水平翻转 | 左右镜像 | (x’, y’) = (w − 1 − x, y) |
| 垂直翻转 | 上下镜像 | (x’, y’) = (x, h − 1 − y) |
| 水平 + 垂直翻转 | 180° 旋转 | (x’, y’) = (w − 1 − x, h − 1 − y) |
解释:
假设图像宽度为 w,高度为 h,那么:
- 水平翻转时,像素
(0,0)会映射到(w-1,0); - 垂直翻转时,像素
(0,0)会映射到(0,h-1)。
2. 关键技术
- 操作本质: 像素位置的重新映射 (Remapping),不会改变图像的尺寸。
- 数学模型:
- 设原图像像素坐标为 (x, y),宽度为 W,高度为H。
- 水平翻转 (X轴,
flipCode=1): 新坐标 (x’, y’) 为 (W - 1 - x, y)。 - 垂直翻转 (Y轴,
flipCode=0): 新坐标 (x’, y’) 为 (x, H - 1 - y)。 - 水平+垂直翻转 (
flipCode=-1): 新坐标 (x’, y’) 为 (W - 1 - x, H - 1 - y)。
- 性能优化 (内存操作):
cv::flip()的实现通常是极度高效的。对于单通道图像,它直接操作内存。- 对于水平翻转,它可以利用SIMD指令(如SSE/AVX)按行进行逆序拷贝,或者在内存中原地交换(In-place Swapping)像素对,从而避免额外的内存分配和复杂计算。
- 对于垂直翻转,则可以按行进行内存块交换。
3. OpenCV 实现
OpenCV 提供 cv2.flip() 函数:
flipped = cv2.flip(src, flipCode)
| 参数 | 含义 |
|---|---|
flipCode = 0 | 垂直翻转(上下) |
flipCode = 1 | 水平翻转(左右) |
flipCode = -1 | 水平 + 垂直翻转(180°) |
4. Python 示例
import cv2
import matplotlib.pyplot as plt# 中文支持(避免乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 读取图像
img = cv2.imread("example.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 翻转操作
flip_h = cv2.flip(img, 1) # 水平翻转
flip_v = cv2.flip(img, 0) # 垂直翻转
flip_hv = cv2.flip(img, -1) # 水平+垂直翻转# 显示结果
titles = ['原图', '水平翻转', '垂直翻转', '水平+垂直翻转']
images = [img, flip_h, flip_v, flip_hv]plt.figure(figsize=(10, 6))
for i in range(4):plt.subplot(1, 4, i+1)plt.imshow(images[i])plt.title(titles[i])plt.axis('off')
plt.tight_layout()
plt.show()
执行效果:

图像旋转(Image Rotation)
1. 原理
图像旋转是绕某个点(通常是图像中心)按一定角度旋转。
每个像素的新坐标通过旋转矩阵计算得到:

其中:
- θ 是旋转角度;
- (tx, ty) 是平移量,用于保证图像旋转后仍在画布内。
2. 关键技术
任意角度旋转 (通过仿射变换)
OpenCV中通过 cv::getRotationMatrix2D() 生成旋转矩阵,再通过 cv::warpAffine() 应用变换。
关键原理与底层技术:
-
确定旋转中心与缩放 (Scaling):
- 通常以图像中心作为旋转中心 (Cx, Cy)。
cv::getRotationMatrix2D()允许定义旋转中心、角度和可选的缩放因子。
-
生成 2x3 仿射变换矩阵 (Affine Matrix):
-
旋转操作包括三个步骤的矩阵组合:
- 平移 (Translation):将旋转中心移到原点。
- 旋转 (Rotation):绕原点旋转 θ\thetaθ 角度。
- 平移 (Translation):将原点移回旋转中心。
-
最终的仿射矩阵 M 为:

其中

-
-
应用变换与插值 (Warping and Interpolation):
cv::warpAffine()使用逆向映射 (Inverse Mapping) 来填充目标图像的每个像素。- 对于目标图像中的每个像素 (x’, y’),通过 M-1 计算其在原图中的浮点坐标 (x, y)。
- 由于 (x, y) 通常不是整数,需要通过插值(如双线性插值
INTER_LINEAR或三次样条插值INTER_CUBIC)来计算其像素值。 - 关键技术: 插值是决定旋转后图像质量(平滑度、锐度)和计算耗时的核心。
-
计算新尺寸:
- 旋转后图像的尺寸通常会增大,以容纳所有原图像的像素,避免裁剪。新尺寸由原图像的四个角点经过仿射变换后所形成的新边界框决定。
特殊角度旋转 (90°/180°/270°/整倍数)
OpenCV中通过 cv::rotate() 函数实现,速度比仿射变换快得多。
关键原理与底层技术:
- 操作本质: 简单的坐标置换和翻转,不需要复杂的矩阵乘法和插值。
- 数学模型 (以 90° 顺时针旋转为例):
- 原坐标 (x, y),尺寸 (W, H)。
- 新坐标 (x’, y’) 为 (H - 1 - y, x)。
- 新尺寸变为 (H, W) (宽变高,高变宽)。
- 性能优化 (内存操作):
- 无插值: 这是其速度快的核心原因。
cv::rotate()是一个直接映射操作,不涉及浮点运算和插值。 - 内存块操作: 它的实现通常优化为对内存块进行高效的读写和重排。对于 180° 旋转,其性能可以接近于简单的翻转操作。
- 无插值: 这是其速度快的核心原因。
3. OpenCV 实现方式
(1)90/180/270° 整角旋转
使用内置函数 cv2.rotate():
rot90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
rot180 = cv2.rotate(img, cv2.ROTATE_180)
rot270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
⚡ 这种方式速度最快,因为只是像素索引重新排列。
(2)任意角度旋转
使用 cv2.getRotationMatrix2D() + cv2.warpAffine()。
import numpy as np(h, w) = img.shape[:2]
center = (w // 2, h // 2)# 旋转 45°
angle = 45
scale = 1.0# 1. 获取旋转矩阵
M = cv2.getRotationMatrix2D(center, angle, scale)
# 2. 仿射变换
rotated = cv2.warpAffine(img, M, (w, h))
说明:
getRotationMatrix2D(center, angle, scale)返回一个 2×3 仿射矩阵;warpAffine()根据该矩阵完成像素映射;- 默认旋转方向:逆时针。
4. 完整 Python 示例(翻转 + 旋转)
import cv2
import numpy as np
import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 读取图像
img = cv2.imread("example.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 翻转
flip_h = cv2.flip(img, 1)
flip_v = cv2.flip(img, 0)# 旋转 45°、90°、180°
h, w = img.shape[:2]
center = (w // 2, h // 2)
M45 = cv2.getRotationMatrix2D(center, 45, 1.0)
M90 = cv2.getRotationMatrix2D(center, 90, 1.0)
M180 = cv2.getRotationMatrix2D(center, 180, 1.0)rot45 = cv2.warpAffine(img, M45, (w, h))
rot90 = cv2.warpAffine(img, M90, (w, h))
rot180 = cv2.warpAffine(img, M180, (w, h))# 显示结果
titles = ['原图', '水平翻转', '垂直翻转', '旋转45°', '旋转90°', '旋转180°']
images = [img, flip_h, flip_v, rot45, rot90, rot180]plt.figure(figsize=(12, 8))
for i in range(6):plt.subplot(2, 3, i+1)plt.imshow(images[i])plt.title(titles[i])plt.axis('off')
plt.tight_layout()
plt.show()
执行效果:

关键技术对比总结
| 特性 | 图像翻转 (cv::flip) | 任意角度旋转 (cv::warpAffine) | 特殊角度旋转 (cv::rotate) |
|---|---|---|---|
| 数学基础 | 简单坐标映射 | 仿射变换矩阵 | 简单坐标置换 |
| 尺寸变化 | 不变 | 通常增大 | 90°/270°时:宽高互换 |
| 核心挑战 | 内存高效存取/交换 | 插值运算(决定质量) | 内存块重排 |
| 性能 | 极快 (通常利用SIMD/原地操作) | 慢 (涉及浮点/插值) | 快 (直接映射,无插值) |
| 适用场景 | 镜像、180°旋转 | 任意角度、缩放、斜切等 | 严格的 90°/180°/270° 旋转 |
