HOWTO · Python
OpenCV 旋转图像
本文教你使用 OpenCV 的 rotate() 和 warpAffine() 函数旋转图像。
本页内容
在 Python 中,OpenCV 提供两种旋转图像的方法。旋转 90°、180° 或 270° 时使用 cv2.rotate();需要其他角度,或需要控制变换中心和缩放比例时,使用 cv2.warpAffine() 与 cv2.getRotationMatrix2D()。这两个函数都处理图像数组。示例会在代码中创建小型数组,因此不依赖外部图像文件。运行 OpenCV 示例前,请安装 OpenCV 和 NumPy。本文中的 OpenCV 示例尚未执行,因为缺少所需的软件包。
使用 OpenCV rotate() 旋转 90°、180° 和 270°
cv2.rotate() 接收图像数组和三个方向常量之一。顺时针旋转四分之一圈时使用 cv2.ROTATE_90_CLOCKWISE;逆时针旋转四分之一圈时使用 cv2.ROTATE_90_COUNTERCLOCKWISE(方向等同于顺时针旋转 270°);旋转半圈时使用 cv2.ROTATE_180。旋转四分之一圈会交换宽度和高度,旋转半圈则保持两者不变。示例会对小型图像数组分别应用这三种方向,并打印每个结果的形状。如果尚未安装 OpenCV 或 NumPy,示例会改为打印安装提示。代码和输出块按原样保留,其中面向读者显示的标签仍为英文;旁边的说明会解释其含义。
try:
import cv2
import numpy as np
except ImportError:
print("Install opencv-python and numpy to run this example.")
else:
image = np.zeros((2, 3, 3), dtype=np.uint8) # 2 rows, 3 columns, 3 color channels
rotations = {
"clockwise": cv2.ROTATE_90_CLOCKWISE,
"counterclockwise": cv2.ROTATE_90_COUNTERCLOCKWISE,
"half-turn": cv2.ROTATE_180,
}
for name, orientation in rotations.items():
rotated = cv2.rotate(image, orientation)
print(f"{name}: {rotated.shape[1]}x{rotated.shape[0]}")
下面的列表示例单独演示坐标如何重新排列。运行此示例:
image = [["A", "B", "C"], ["D", "E", "F"]]
rotated = [list(row) for row in zip(*image[::-1])]
print(f"original: {len(image[0])}x{len(image)}")
print(f"rotated: {len(rotated[0])}x{len(rotated)}")
print("rows:", rotated)
original: 3x2
rotated: 2x3
rows: [['D', 'A'], ['E', 'B'], ['F', 'C']]
带有标记的单元格无需打开显示窗口,就能直观看出旋转方向和尺寸变化。OpenCV 示例按宽度、高度的顺序报告尺寸,而 NumPy 保存的图像形状顺序则是高度、宽度和通道数。处理图像文件时,先检查 cv2.imread() 是否成功读取,再将返回的数组传给 cv2.rotate()。cv2.rotate() 仅支持这些直角旋转方向,不能用于任意角度。示例代码及其输出块中的可见标签保持英文。
使用 OpenCV warpAffine() 旋转任意角度
cv2.getRotationMatrix2D(center, angle, scale) 会返回一个 2×3 的仿射矩阵。center 是 (x, y) 坐标点,angle 的单位是度(在 OpenCV 的图像坐标系中,正角度表示逆时针旋转),scale 用于缩放图像:1.0 保持原尺寸,小于 1.0 会缩小图像,大于 1.0 会放大图像。cv2.warpAffine(image, matrix, (width, height)) 会将矩阵应用到目标画布上;尺寸参数的顺序是宽度在前、高度在后。此示例以图像中心为旋转中心,将 120×80 的图像旋转 30°,并保留原画布尺寸,因此边角可能被裁切。如果缺少所需的软件包,示例会打印安装提示。代码和输出块按原样保留,其中面向读者显示的标签仍为英文。
try:
import cv2
import numpy as np
except ImportError:
print("Install opencv-python and numpy to run this example.")
else:
height, width = 80, 120
image = np.zeros((height, width, 3), dtype=np.uint8)
center = (width / 2, height / 2)
angle = 30
scale = 1.0
matrix = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(image, matrix, (width, height))
print(f"input canvas: {width}x{height}")
print(f"rotated canvas: {rotated.shape[1]}x{rotated.shape[0]}")
示例刻意保留原始 (width, height) 目标尺寸,因此输出尺寸不变,超出画布范围的旋转边角会被裁切。若要保留完整图像,请根据旋转后的边界计算更大的目标画布,并调整矩阵的平移量,使变换后的中心移到新画布的中心;如果只增大目标尺寸,变换仍会以原坐标为基准。
warpAffine() 会填充无法映射到源图像像素的目标像素。默认的 cv2.BORDER_CONSTANT 使用固定颜色填充(默认是黑色);可通过 borderValue 选择其他颜色。cv2.BORDER_REPLICATE 会延伸最近的源图像边缘像素。cv2.BORDER_TRANSPARENT 会让对应的目标像素保持不变,因此使用它时应先初始化目标图像;此模式不会自动还原源图像的边框。可参阅 OpenCV 边界模式参考 了解可用模式。