affine transoform仿射变换

2020-03-16  本文已影响0人  海盗船长_coco

仿射变换矩阵公式:

仿射变换公式

python实现

python中有大量的包提供仿射变换的方法。
一、from skimage import transform:比较方便,无需知道变换矩阵。旋转中心点在图像中心

#旋转变换的实现
from skimage import transform
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

if __name__ == '__main__':
    img = np.array(Image.open('data/images/lena.jpg'))
    H, W, C = img.shape

    rotation = 20  #只需角度,不用转化为弧度
    change_img = transform.rotate(img, angle=rotation)

    imgs = [img, change_img]
    fig = plt.figure(figsize=(6, 4), dpi=100)
    axes = fig.subplots(1, 2)
    for index, ax in enumerate(axes.flatten()):
        ax.imshow(imgs[index])
    plt.show()
旋转效果
二、opencv提供了两个变换函数cv2.warpAffine cv2.warpPerspective使用这两个函数你可以实现所有类型的变换。前者接收的参数是2x3的变换矩阵,后者接收的是3x3的变换矩阵,旋转时旋转中心在左上角,且旋转角度要转化为弧度。
import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

if __name__ == '__main__':
    img = np.array(Image.open('data/images/lena.jpg')).astype(np.uint8)
    H, W, C = img.shape

    radians = np.deg2rad(20)  # 将角度转化为弧度
    rotation_matrix = np.array(
        [[np.cos(radians), np.sin(radians), 0], [-np.sin(radians), np.cos(radians), 0]])  #注意:一定要是2*3的矩阵
    change_img = cv2.warpAffine(src=img, M=rotation_matrix, dsize=img.shape[:2])

    imgs = [img, change_img]
    fig = plt.figure(figsize=(6, 4), dpi=100)
    axes = fig.subplots(1, 2)
    for index, ax in enumerate(axes.flatten()):
        ax.imshow(imgs[index])
    plt.show()
cv2.warpAffine旋转效果
三、from scipy.ndimage import affine_transform与cv2相同,旋转时,旋转中心在左上角且旋转角度要转化为弧度。不同点是变换矩阵为3x3大小。
from scipy.ndimage import affine_transform
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

if __name__ == '__main__':
    img = np.array(Image.open('data/images/lena.jpg')).astype(np.uint8)
    H, W, C = img.shape

    radians = np.deg2rad(20)  # 将角度转化为弧度
    rotation_matrix = np.array(
        [[np.cos(radians), np.sin(radians), 0], [-np.sin(radians), np.cos(radians), 0], [0, 0, 1]])
    change_img = affine_transform(img, matrix=rotation_matrix)

    imgs = [img, change_img]
    fig = plt.figure(figsize=(6, 4), dpi=100)
    axes = fig.subplots(1, 2)
    for index, ax in enumerate(axes.flatten()):
        ax.imshow(imgs[index])
    plt.show()
affine_transform旋转效果

讨论

在分类任务中,由于并没有bounding box的存在,所以在data augmentation推荐使用第一种方法比较简便。但是在检测任务中,我们不仅要知道该物体的类型,还需要用bounding box将其框出来,所以在data augmentation时,在旋转图像的同时,也要将box进行旋转,所以我们需要知道其变换矩阵,这时使用第二种或第三种方法较好。

使用cv2包对图像进行中心点旋转

若直接顺序执行则存在错误
1、将图像左上角移到中心点。2、按照弧度进行旋转。3、将原中心点返回到左上角

import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

if __name__ == '__main__':
    img = np.array(Image.open('data/images/lena.jpg')).astype(np.uint8)
    H, W, C = img.shape

    decenter_matrix = np.array([[1, 0, W / 2], [0, 1, H / 2]])
    img_1 = cv2.warpAffine(img, decenter_matrix, dsize=(H, W))
    radians = np.deg2rad(20)  # 将角度转化为弧度
    rotation_matrix = np.array(
        [[np.cos(radians), np.sin(radians), 0], [-np.sin(radians), np.cos(radians), 0]])
    img_2 = cv2.warpAffine(img_1, rotation_matrix, dsize=(H, W))

    center_matrix = np.array([[1, 0, -W / 2], [0, 1, -H / 2]])
    img_3 = cv2.warpAffine(img_2, center_matrix, dsize=(H, W))

    imgs = [img, img_1, img_2, img_3]
    fig = plt.figure(figsize=(6, 4), dpi=100)
    axes = fig.subplots(2, 2)
    for index, ax in enumerate(axes.flatten()):
        ax.imshow(imgs[index])
    plt.show()

顺序执行
将三个变换矩阵相乘,一次完成
import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

if __name__ == '__main__':
    img = np.array(Image.open('data/images/lena.jpg')).astype(np.uint8)
    H, W, C = img.shape

    decenter_matrix = np.array([[1, 0, W / 2], [0, 1, H / 2]])
    img_1 = cv2.warpAffine(img, decenter_matrix, dsize=(H, W))
    radians = np.deg2rad(20)  # 将角度转化为弧度
    rotation_matrix = np.array(
        [[np.cos(radians), np.sin(radians), 0], [-np.sin(radians), np.cos(radians), 0]])
    img_2 = cv2.warpAffine(img_1, rotation_matrix, dsize=(H, W))

    center_matrix = np.array([[1, 0, -W / 2], [0, 1, -H / 2]])
    img_3 = cv2.warpAffine(img_2, center_matrix, dsize=(H, W))

    decenter_matrix = np.array([[1, 0, W / 2], [0, 1, H / 2], [0, 0, 1]])
    rotation_matrix = np.array(
        [[np.cos(radians), np.sin(radians), 0], [-np.sin(radians), np.cos(radians), 0], [0, 0, 1]])
    center_matrix = np.array([[1, 0, -W / 2], [0, 1, -H / 2], [0, 0, 1]])
    final_matrix = np.dot(np.dot(decenter_matrix, rotation_matrix), center_matrix)[:2, :]
    final_img = cv2.warpAffine(img, final_matrix, dsize=(H, W))

    imgs = [img, img_1, img_2, img_3, final_img, None]
    fig = plt.figure(figsize=(6, 4), dpi=100)
    axes = fig.subplots(2, 3)
    for index, ax in enumerate(axes.flatten()):
        ax.axis('off')
        if index != 5:
            ax.imshow(imgs[index])
    plt.show()

矩阵相乘完成变换

data augmentation

当图片进行一系列变换时(旋转、平移、错切等操作),bounding box也要进行相应的变换,用到的是变化矩阵的逆矩阵。由于最终的bounding box还是方形,所以旋转,错切的程度不能太大,旋转的角度一般在(-5,5)之间。

import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import patches
from numpy.linalg import inv as mat_inv

if __name__ == '__main__':
    img = np.array(Image.open('data/images/lena.jpg')).astype(np.uint8)
    ori_box = [(200, 180), (350, 380)]
    H, W, C = img.shape
    ration = np.deg2rad(5)  # 角度转为弧度
    shear = np.deg2rad(5)
    height_shift, width_shift = 0.02 * img.shape[0], 0.03 * img.shape[1]  # 平移距离
    height_zoom, width_zoom = 0.95, 0.9  # 缩放比例
    decenter_matrix = np.array([[1, 0, W / 2], [0, 1, H / 2], [0, 0, 1]])
    rotation_matrix = np.array(
        [[np.cos(ration), np.sin(ration), 0], [-np.sin(ration), np.cos(ration), 0], [0, 0, 1]])  # 旋转
    shift_matrix = np.array([[1, 0, -height_shift], [0, 1, -width_shift], [0, 0, 1]])  # 位移
    zoom_matrix = np.array([[1.0 / height_zoom, 0, 0], [0, 1.0 / width_zoom, 0], [0, 0, 1]])  # 缩放
    shear_matrix = np.array([[1, np.sin(shear), 0], [0, np.cos(shear), 0], [0, 0, 1]])  # 错切
    center_matrix = np.array([[1, 0, -W / 2], [0, 1, -H / 2], [0, 0, 1]])
    final_matrix = np.dot(np.dot(np.dot(decenter_matrix, rotation_matrix), np.dot(shift_matrix, zoom_matrix)),
                          np.dot(shear_matrix, center_matrix))
    final_img = cv2.warpAffine(img, final_matrix[:2, :], dsize=(H, W))

    inv_trans=mat_inv(final_matrix)
    change_box = []
    for x, y in ori_box:
        y, x, _ = np.dot(inv_trans, [y, x, 1]).astype(np.int)
        change_box.append((x, y))

    imgs = [img, final_img]
    fig = plt.figure(figsize=(6, 4), dpi=100)
    axes = fig.subplots(1, 2)
    for index, ax in enumerate(axes.flatten()):
        ax.axis('off')
        if index == 0:
            bbox = patches.Rectangle(ori_box[0],
                                     ori_box[1][0] - ori_box[0][0], ori_box[1][1] - ori_box[0][1],
                                     linewidth=2, facecolor='none', edgecolor='r')
        if index == 1:
            bbox = patches.Rectangle(change_box[0],
                                     change_box[1][0] - change_box[0][0], change_box[1][1] - change_box[0][1],
                                     linewidth=2, facecolor='none', edgecolor='r')
        ax.add_patch(bbox)
        ax.imshow(imgs[index])
    plt.show()
数据增强
上一篇 下一篇

猜你喜欢

热点阅读