opencv中有两种方式来对图像进行旋转操作:
- 使用
rotate
函数,通过rotateCode来控制图像的旋转角度,而rotateCode的取值只有90/180/270三种,自由度不够高。 - 使用仿射变换
warpAffine
来以任意角度的旋转图片。但旋转后的图片会被裁切,丢失了部分信息,代码与效果图如下所示:
import numpy as np
import cv2 as cv
img = cv.imread("lena.png", cv.IMREAD_UNCHANGED)
h, w, c = img.shape
m = cv.getRotationMatrix2D(center=(w / 2, h / 2), angle=45, scale=1)
ret = cv.warpAffine(img, m, img.shape[1::-1])
cv.imwrite("wrapAffine.png", ret)
为解决上述问题,就有了如下代码
import numpy as np
import cv2 as cv
from typing import Tuple
def rotate(img: np.ndarray, angle: float, center: Tuple[float, float] = None) -> np.ndarray:
h, w, c = img.shape
# Defining the center point of rotation as the center of the image if center is not provided
center = (w / 2, h / 2) if center is None else center
# Ensuring that the center point lies within the image dimensions
assert 0 <= center[0] <= w and 0 <= center[1] <= h
# Adding a border of zeros around the input image to avoid cropping after rotation
top, bottom, left, right = h, h, w, w
bordered = cv.copyMakeBorder(img, top, bottom, left, right,
borderType=cv.BORDER_CONSTANT, value=cv.BORDER_TRANSPARENT)
# Computing the rotation matrix with respect to the center point of the image
m = cv.getRotationMatrix2D(center=(center[0] + left, center[1] + top), angle=angle, scale=1)
# Applying the rotation to the bordered image using the computed rotation matrix
ret = cv.warpAffine(bordered, m, bordered.shape[1::-1], borderMode=cv.BORDER_TRANSPARENT)
# Removing the zero-padded border from the rotated image
x, y = np.where(ret[..., -1] != 0)
return ret[x.min():x.max(), y.min():y.max(), :]
使用rotate
函数绕中心旋转45°的图片如下: