仿射变换矩阵公式:
仿射变换公式
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()
数据增强














网友评论