图像旋转:getRotationMatrix2D详解--无损失旋转图片

2021-03-06 20:20:04 浏览数 (1)

使用opencv对图像进行旋转的代码随手一搜即得,但是有些旋转后图像会不完整,有些只给出代码并未解释其实现原理。本文会详细介绍如何使用opencv实现图像旋转得到完整图像,以及其中的实现原理。

最终实现效果:

test.pngtest.png
test_rotated.jpgtest_rotated.jpg

1. getRotationMatrix2D详解

opencv的getRotationMatrix2D函数可以获取旋转变换矩阵。输入中心点坐标(centerX,centerY),旋转角度theta,缩放比例,给出M变换矩阵

begin{bmatrix} costheta & -sintheta & (1-costheta)*centerX sintheta*centerY \ sintheta & costheta & (1-costheta)*centerY-sintheta*centerX \ 0 & 0 & 1 end{bmatrix}

那这个矩阵到底如何计算得到的呢?

我们先对一个点基于原点进行旋转,如下图,将V1点逆时针旋转theta角度到V2点,缩放比例我们先假定为1.

image.pngimage.png

V1点和原点连线与水平线夹角a,V2点和原点连线与水平线夹角b=a theta。计算旋转变换矩阵

V1 =(x1, y1),V2 = (x2, y2)

那么

x1 = cosa

y1 = sina

x2 = cos(a theta) = costheta*cosa - sina*sintheta

y2 = sin(a b) = sina*costheta cosa*sintheta

x1,y1带入

x2=x1costheta-y1sintheta

y2=y1costheta x1sintheta = x1sintheta y1costheta

输出矩阵形式

begin{bmatrix} x2 \ y2 end{bmatrix} = begin{bmatrix} costheta & -sintheta \ sintheta & costheta end{bmatrix} * begin{bmatrix} x1 \ y1 end{bmatrix}

但是通常我们会基于中心点进行旋转,如果是需要绕任意点(tx,ty)旋转,我们可以

1.先把旋转点平移到原点

2.然后进行以上旋转操作

3.按1的逆操作平移回去

就可以得到绕任意点旋转点变换矩阵:

以上就是旋转矩阵M的由来。

2. warpAffine操作

2.1 获取M矩阵

得到变换矩阵M,对图像每个点进行M变换就可以得到旋转后的图像,这一步可以通过opencv的warpAffine得到。但是通过以上操作,旋转后大图像会丢失信息,如下图所示:

2.2 扩大画布

画布大小不变的情况下,会有一部分图像超出,显示不全,所以我们需要将画布扩大为:

新的高由图片中两段蓝色线组合

new_H = int(w * fabs(sin(radians(angle))) h * fabs(cos(radians(angle))))

新的宽由图片中两段红色线组合

new_W = int(h * fabs(sin(radians(angle))) w * fabs(cos(radians(angle))))

新的画布扩大是基于原图左上角点扩大,显示的还是蓝色区域,同样丢失了信息。

2.3 平移图像

我们还需要将红色区域进行平移操作显示到蓝色区域

所以,在变换矩阵M上,我们可以调整平移参数:

M[0, 2] = (new_W - w) / 2

M[1, 2] = (new_H - h) / 2

通过以上操作就可以显示出文章最初到效果了。

最后附上使用opencv进行图像旋转并且不丢失信息到完整代码:

代码语言:txt复制
def opencv_rotate(img, angle):
    h, w = img.shape[:2]
    center = (w / 2, h / 2)
    scale = 1.0
    # 2.1获取M矩阵
     """
    M矩阵
    [
    cosA -sinA (1-cosA)*centerX sinA*centerY
    sinA cosA  -sinA*centerX (1-cosA)*centerY
    ]
    """
    M = cv2.getRotationMatrix2D(center, angle, scale)
    # 2.2 新的宽高,radians(angle) 把角度转为弧度 sin(弧度)
    new_H = int(w * fabs(sin(radians(angle)))   h * fabs(cos(radians(angle))))
    new_W = int(h * fabs(sin(radians(angle)))   w * fabs(cos(radians(angle))))
    # 2.3 平移
    M[0, 2]  = (new_W - w) / 2
    M[1, 2]  = (new_H - h) / 2
    rotate = cv2.warpAffine(img, M, (new_W, new_H), borderValue=(0, 0, 0))
    return rotate

0 人点赞