HOWTO · Python
OpenCV 旋轉影象
本文教你使用 OpenCV 的 rotate() 和 warpAffine() 函式旋轉影象。
本頁內容
在 Python 中,OpenCV 提供兩種旋轉影像的方法。若要旋轉直角,請使用 cv2.rotate();若要旋轉其他角度,或需要控制轉換中心與縮放比例,請搭配 cv2.getRotationMatrix2D() 使用 cv2.warpAffine()。這兩個函式都會處理影像陣列。範例會直接在程式碼中建立小型陣列,因此不需要外部影像檔。若要執行 OpenCV 範例,請安裝 OpenCV 和 NumPy。
使用 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 邊界模式參考文件,了解可用的模式。範例中的可見標示文字維持英文;程式碼和輸出區塊依原樣保留。