<button id="ssm6u"><optgroup id="ssm6u"></optgroup></button>
  • 跳轉至

    圖像旋轉

    概要

    本節講解了使用getRotationMatrix2D (內置API)與wrapAffine (矩陣運算)兩種方式完成圖像的旋轉.

    keywords: 圖像旋轉 Rotation 仿射變換

    利用getRotationMatrix2D實現旋轉

    opencv中getRotationMatrix2D函數可以直接幫我們生成M 而不需要我們在程序里計算三角函數.

    getRotationMatrix2D(center, angle, scale)
    

    參數解析

    • center 旋轉中心點 (cx, cy) 你可以隨意指定

    • angle 旋轉的角度 單位是角度 逆時針方向為正方向 , 角度為正值代表逆時針。

    • 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

    # -*- coding: utf-8 -*- 
    '''
    圍繞原點處旋轉 (圖片左上角) 正方向為逆時針
    利用getRotationMatrix2D函數生成仿射矩陣
    '''
    import numpy as np
    import cv2
    from math import cos,sin,radians
    from matplotlib import pyplot as plt
    
    img = cv2.imread('cat.jpg')
    
    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)\\ &= r*cos(\phi)*cos(\theta) - r*sin(\phi)*sin(\theta)\\ \\ y &= r * sin(\phi)\\ \\ y' &= r * sin(\phi + \theta)\\ &= r*sin(\phi)*cos(\theta) + r*cos(\phi)*sin(\theta) \end{align*}

    由此我們得出

    \begin{align*} x' = x*cos(\theta) - y*sin(\theta) \\ \\ y' = x*sin(\theta) + y*cos(\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 ]

    注意,這里我們進行公式推導的時候,參照的原點是在左下角, 而在OpenCV中圖像的原點在圖像的左上角, 所以我們在代碼里面對theta取反。

    我們可以利用math包中的三角函數。但是有一點需要注意 :三角函數輸入的角度是弧度制而不是角度制。

    我們需要使用radians(x) 函數, 將角度轉變為弧度。

    import math
    math.radians(180)
    
    3.141592653589793
    

    rotate

    源代碼

    rotate_image_v2.py

    # -*- coding: utf-8 -*- 
    '''
    圍繞原點處旋轉 (圖片左上角) 正方向為逆時針
    '''
    import numpy as np
    import cv2
    import math
    from matplotlib import pyplot as plt
    
    img = cv2.imread('cat.jpg')
    
    height, width, channel = img.shape
    
    def getRotationMatrix2D(theta):
        # 角度值轉換為弧度值
        # 因為圖像的左上角是原點 需要×-1
        theta = math.radians(-1*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

    源代碼

    rotate_image_v3.py

    # -*- coding: utf-8 -*- 
    '''
    圍繞畫面中的任意一點旋轉
    '''
    import numpy as np
    import cv2
    from math import cos,sin,radians
    from matplotlib import pyplot as plt
    
    img = cv2.imread('cat.jpg')
    
    height, width, channel = img.shape
    
    theta = 45
    
    def getRotationMatrix2D(theta, cx=0, cy=0):
        # 角度值轉換為弧度值
        # 因為圖像的左上角是原點 需要×-1
        theta = radians(-1 * 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))
    
    # 圍繞原點 逆時針旋轉45度
    M = getRotationMatrix2D(45, cx=cx, cy=cy)
    rotated_45 = cv2.warpAffine(img, M, (width, height))
    
    # 圍繞原點 逆時針旋轉60度
    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()
    

    韩国精品无码一区二区三区,精品无码一区二区三区AV,欧洲丰满美熟女乱又伦AV,亚洲午夜久久久影院伊人