Skip to content

Latest commit

 

History

History
454 lines (332 loc) · 8.13 KB

File metadata and controls

454 lines (332 loc) · 8.13 KB

旋转(rotation)

利用getRotationMatrix2D实现旋转

opencv中getRotationMatrix2D函数可以直接帮我们生成M 而不需要我们在程序里计算三角函数.

getRotationMatrix2D(center, angle, scale)

参数解析

  • center 旋转中心点 (cx, cy) 你可以随意指定

  • angle 旋转的角度 单位是角度 顺时针方向为正方向

    counter-clock-direction.png

  • scale 缩放倍数. 值等于1.0 代表尺寸不变

该函数返回的就是仿射变换矩阵M

import cv2
import numpy as np

# 获取旋转矩阵
rotateMatrix = cv2.getRotationMatrix2D((100, 200), 90, 1.0)

#设置numpy矩阵的打印格式
np.set_printoptions(precision=2,suppress=True)
print(rotateMatrix)

OUTPUT

[[   0.    1. -100.]
 [  -1.    0.  300.]]

为了使用方便, 你也可以封装一下旋转过程

def rotate(image, angle, center = None, scale = 1.0):

    (h, w) = image.shape[:2]

    if center is None:
        center = (w / 2, h / 2)
    
    M = cv2.getRotationMatrix2D(center, angle, scale)
    rotated = cv2.warpAffine(image, M, (w, h))

    return rotated

201802191617

'''
围绕原点处旋转 (图片左上角) 正方向为逆时针
'''
import numpy as np
import cv2
from math import cos,sin,radians
from matplotlib import pyplot as plt

img = cv2.imread('cat.png')

height, width, channel = img.shape

# 求得图片中心点, 作为旋转的轴心
cx = int(width / 2)
cy = int(height / 2)
# 旋转的中心
center = (cx, cy)

new_dim = (width, height)

# 进行2D 仿射变换
# 围绕原点 顺时针旋转30度
M = cv2.getRotationMatrix2D(center=center,angle=30, scale=1.0)
rotated_30 = cv2.warpAffine(img, M, new_dim)

# 围绕原点 顺时针旋转30度
M = cv2.getRotationMatrix2D(center=center,angle=45, scale=1.0)
rotated_45 = cv2.warpAffine(img, M, new_dim)

# 围绕原点 顺时针旋转30度
M = cv2.getRotationMatrix2D(center=center,angle=60, scale=1.0)
rotated_60 = cv2.warpAffine(img, M, new_dim)

plt.subplot(221)
plt.title("Src Image")
plt.imshow(img[:,:,::-1])

plt.subplot(222)
plt.title("Rotated 30 Degree")
plt.imshow(rotated_30[:,:,::-1])

plt.subplot(223)
plt.title("Rotated 45 Degree")
plt.imshow(rotated_45[:,:,::-1])

plt.subplot(224)
plt.title("Rotated 60 Degree")
plt.imshow(rotated_60[:,:,::-1])

plt.show()

学霸分割线 如果你对图像旋转的数学原理不感兴趣的话,就不需要往下看了.


利用wrapAffine实现缩放

围绕原点进行旋转

20170323174605746.png

$$ \begin{align*} x &= r * cos(\phi)\ \ x' &= r * cos(\phi + \theta)\ &= rcos(\phi)cos(\theta) - rsin(\phi)sin(\theta)\ \ y &= r * sin(\phi)\ \ y' &= r * sin(\phi + \theta)\ &= rsin(\phi)cos(\theta) + rcos(\phi)sin(\theta) \end{align} $$ 由此我们得出 $$ \begin{align} x' = xcos(\theta) - ysin(\theta) \ \ y' = xsin(\theta) + ycos(\theta) \end{align*} $$ 所以对应的变换矩阵为 $$ \begin{equation} { \left[ \begin{array}{c} x'\ y'\ \end{array} \right ]}= { \left[ \begin{array}{cc} cos(\theta) & -sin(\theta)\ sin(\theta) & cos(\theta)\ \end{array} \right ]}\times { \left[\begin{array}{c} x\ y\ \end{array} \right] }+ { \left[\begin{array}{c} 0\ 0\ \end{array} \right] } \end{equation} $$

$$ M =\left[ \begin{array}{c} cos(\theta) &-sin(\theta) & 0\\ sin(\theta) & cos(\theta)& 0\\ \end{array} \right ] $$

我们可以利用math包中的三角函数。但是有一点需要注意 :三角函数输入的角度是弧度制而不是角度制

我们需要使用radians(x) 函数, 将角度转变为弧度。

import math
math.radians(180)
3.141592653589793

201802191558

从图中我们可以观察出来, 角度正方向为顺时针。

counter-clock-direction.png

源代码

'''
围绕原点处旋转 (图片左上角) 正方向为顺时针
'''
import numpy as np
import cv2
import math
from matplotlib import pyplot as plt

img = cv2.imread('cat.png')

height, width, channel = img.shape

theta = 45

def getRotationMatrix2D(theta):
    # 角度值转换为弧度值
    theta = math.radians(theta)

    M = np.float32([
        [math.cos(theta), -math.sin(theta), 0],
        [math.sin(theta), math.cos(theta), 0]])
    return M

# 进行2D 仿射变换
# 围绕原点 顺时针旋转30度
M = getRotationMatrix2D(30)
rotated_30 = cv2.warpAffine(img, M, (width, height))

# 围绕原点 顺时针旋转45度
M = getRotationMatrix2D(45)
rotated_45 = cv2.warpAffine(img, M, (width, height))

# 围绕原点 顺时针旋转60度
M = getRotationMatrix2D(60)
rotated_60 = cv2.warpAffine(img, M, (width, height))

plt.subplot(221)
plt.title("Src Image")
plt.imshow(img[:,:,::-1])

plt.subplot(222)
plt.title("Rotated 30 Degree")
plt.imshow(rotated_30[:,:,::-1])

plt.subplot(223)
plt.title("Rotated 45 Degree")
plt.imshow(rotated_45[:,:,::-1])

plt.subplot(224)
plt.title("Rotated 60 Degree")
plt.imshow(rotated_60[:,:,::-1])

plt.show()

围绕任意点进行旋转

那么如何围绕任意点进行旋转呢?

可以先把当前的旋转中心点平移到原点处, 在原点处旋转后再平移回去。

假定旋转中心为 $$(c_x, c_y)$$

$$M_{translation}$$ 为平移矩阵 $$M_{translation}^{-1}$$ 为平移矩阵的逆矩阵 $$M_{rotation}$$ 为原点旋转矩阵

$$ { \left[ \begin{array}{c} x'\\ y'\\ 0\\ \end{array} \right ]} =M_{translation}^{-1}( M_{rotation} * (M_{translation} * { \left[ \begin{array}{c} x\\ y\\ 0\\ \end{array} \right ]}) ) $$

其中 $$ M_{translation} = { \left[ \begin{array}{c} 1 &0 & -c_x\ 0& 1& -c_y\ 0 & 0 & 1\ \end{array} \right ] }\

M_{translation}^{-1} = { \left[ \begin{array}{c} 1 &0 & c_x\ 0& 1& c_y\ 0 & 0 & 1\ \end{array} \right ] }\

M_{rotation} = { \left[ \begin{array}{c} cos(\theta) &-sin(\theta) & 0\ sin(\theta) & cos(\theta)& 0\ 0 & 0 & 1\ \end{array} \right ] } $$

所以 $$ \begin{align*} M &= M_{translation}^{-1} \times M_{rotation} \times M_{translation}\ &= { \left[ \begin{array}{c} 1 &0 & c_x\ 0& 1& c_y\ 0 & 0 & 1\ \end{array} \right ] } \times { \left[ \begin{array}{c} cos(\theta) &-sin(\theta) & 0\ sin(\theta) & cos(\theta)& 0\ 0 & 0 & 1\ \end{array} \right ] } \times { \left[ \begin{array}{c} 1 &0 &-c_x\ 0& 1& -c_y\ 0 & 0 & 1\ \end{array} \right ] }\ &= { \left[ \begin{array}{c} cos(\theta) &-sin(\theta) & (1-cos(\theta))*c_{x} + sin(\theta)*c_{y}\ sin(\theta) & cos(\theta)& -sin(\theta)*c_{x} + (1-cos(\theta))*c_{y}\ 0 & 0 & 1\ \end{array} \right ] }

\end{align*} $$ 完美.

旋转效果

围绕图片中心点旋转30度至60度。

201802191617

源代码

import numpy as np
import cv2
from math import cos,sin,radians
from matplotlib import pyplot as plt

img = cv2.imread('cat.png')

height, width, channel = img.shape

theta = 45

def getRotationMatrix2D(theta, cx=0, cy=0):
    # 角度值转换为弧度值
    theta = radians(theta)

    M = np.float32([
        [cos(theta), -sin(theta), (1-cos(theta))*cx + sin(theta)*cy],
        [sin(theta), cos(theta), -sin(theta)*cx + (1-cos(theta))*cy]])
    return M

# 求得图片中心点, 作为旋转的轴心
cx = int(width / 2)
cy = int(height / 2)

# 进行2D 仿射变换
# 围绕原点 顺时针旋转30度
M = getRotationMatrix2D(30, cx=cx, cy=cy)
rotated_30 = cv2.warpAffine(img, M, (width, height))

# 围绕原点 顺时针旋转30度
M = getRotationMatrix2D(45, cx=cx, cy=cy)
rotated_45 = cv2.warpAffine(img, M, (width, height))

# 围绕原点 顺时针旋转30度
M = getRotationMatrix2D(60, cx=cx, cy=cy)
rotated_60 = cv2.warpAffine(img, M, (width, height))

plt.subplot(221)
plt.title("Src Image")
plt.imshow(img[:,:,::-1])

plt.subplot(222)
plt.title("Rotated 30 Degree")
plt.imshow(rotated_30[:,:,::-1])

plt.subplot(223)
plt.title("Rotated 45 Degree")
plt.imshow(rotated_45[:,:,::-1])

plt.subplot(224)
plt.title("Rotated 60 Degree")
plt.imshow(rotated_60[:,:,::-1])

plt.show()