【图像处理】数据增广-平移变换

几何变换

一、简介

在目标检测深度学习中,经常出现数据量较少的情况,常用的扩大数据集的方式分为两种,一种为传统图像算法增广,另一种为深度学习数据增广。这里只记录下传统图像的数据增广。
传统图像算法中,常用几何变换来进行数据增广,其中常用方法有:缩放,平移,旋转,仿射等。

二、平移

从字面意思可以看出来,平移只限于图像在水平或者垂直的方向上移动一段距离。在图像处理中平移变换也是这样。图像可以看做为像素点组成,图像平移可以看做像素点在指定方向上的移动。
若要沿着 ( x , y ) (x,y) x,y),方向移动一段距离 ( t x , t y ) ​ (t_x,t_y)​ (tx,ty),可以构建如下移动矩阵(在python中使用numpy来构建)

M = [ 1 0 t x 0 1 t y ] ​ M = \begin{bmatrix} 1 & 0 &t_x \\ 0 & 1&t_y \end{bmatrix}​ M=[1001txty]

# -*- coding:utf-8 -*-
import os
import cv2
import numpy as np

if __name__ == '__main__':
	img = cv2.imread("img.jpg")
	h,w,n = img.shape
	print(h,w,n)   #252 250 3
	#使用numpy构建移动矩阵
	M = np.float32([[1,0,20],[0,1,30]])
    #第一个参数为原图像,第二个参数为移动矩阵,可以自定义,第三个参数为输出图像大小
	res = cv2.warpAffine(img,M,(h,w))
	cv2.imshow("img",res)
	cv2.waitKey(0)
	cv2.destroyAllWindows()

原图:【图像处理】数据增广-平移变换_第1张图片
变换后:【图像处理】数据增广-平移变换_第2张图片

三、旋转

旋转是将图像按照一定的角度进行所有像素都参与的旋转操作,和平移一样,需要预先设定一个旋转矩阵,旋转角度的选择也十分重要。

旋转矩阵格式如下:
M = [ α β ( 1 − α ) ∗ c e n t e r x − β ∗ c e r t e r y − β α β ∗ c e n t e r x − ( 1 − α ) ∗ c e r t e r y ] M = \begin{bmatrix} \alpha & \beta &(1-\alpha)*center_x-\beta*certer_y \\ -\beta & \alpha & \beta*center_x-(1-\alpha)*certer_y \end{bmatrix} M=[αββα(1α)centerxβcerteryβcenterx(1α)certery]

# -*- coding:utf-8 -*-
import os
import cv2
import numpy as np

if __name__ == '__main__':
	img = cv2.imread("img.jpg")
	h,w,n = img.shape
	print(h,w,n)   #252 250 3
	#使用opencv自带的方法构建旋转矩阵,第一个参数为旋转中心,
	#第二个参数为旋转角度,逆时针旋转,第三个参数为缩放比例,防止出界
	M = cv2.getRotationMatrix2D((w/2,h/2),-30,0.5)
	#第三个参数为
	res = cv2.warpAffine(img,M,(h,w))
	cv2.imshow("img",res)
	# cv2.imwrite("affine.jpg",res)
	cv2.waitKey(0)
	cv2.destroyAllWindows()

原图:【图像处理】数据增广-平移变换_第3张图片
效果图:【图像处理】数据增广-平移变换_第4张图片

四、仿射变换

仿射变换是一种二维坐标(x,y)到二维坐标(u,v)的线性变换
{ u = a 1 x + b 1 y + c 1 v = a 2 x + b 2 y + c 2 \begin{cases} u = a_1x+b_1y+c_1\\ v = a_2x+b_2y+c_2 \end{cases} {u=a1x+b1y+c1v=a2x+b2y+c2
对应的齐次坐标矩阵表示形式为:
[ u v 1 ] = [ a 1 b 1 c 1 a 1 b 2 c 2 0 0 1 ] [ x y 1 ] \begin{bmatrix} u\\v\\1\end{bmatrix} = \begin{bmatrix} a_1 & b_1&c_1\\a_1&b_2&c_2\\0&0&1\end{bmatrix}\begin{bmatrix} x\\y\\1\end{bmatrix} uv1=a1a10b1b20c1c21xy1
仿射变换保持了二维图形的“平直性”(直线经仿射变换后依然为直线)和“平行性”(直线之间的相对位置关系保持不变,平行线经仿射变换后依然为平行线,且直线上点的位置顺序不会发生变化)。非共线的三对对应点确定一个唯一的仿射变换。

三个不共线的点可以得到一个平面,在仿射变换中,给定图片上的三个点对应的变换位置,可以得到整个图像的仿射变换结果。由于从是三个点求得矩阵的困难度较大,所以opencv支持给出三个点坐标和变换后的坐标,直接得到整个图像的结果。

# -*- coding:utf-8 -*-
import os
import cv2
import numpy as np

if __name__ == '__main__':
	img = cv2.imread("img.jpg")
	h,w,n = img.shape
	
	# 给出变换前后三个点的坐标值
	pts1 = np.float32([[10,20],[30,50],[50,100]])
	pts2 = np.float32([[20,40],[60,80],[100,150]])
	M = cv2.getAffineTransform(pts1,pts2)
	# 第三个参数依然是结果图的大小,防止变换后出界
	res = cv2.warpAffine(img,M,(h*2,w*2))
	cv2.imshow("img",res)
	cv2.imwrite("affine.jpg",res)
	cv2.waitKey(0)
	cv2.destroyAllWindows()

原图:【图像处理】数据增广-平移变换_第5张图片

结果图:【图像处理】数据增广-平移变换_第6张图片

五、总结

传统的数据增广方式多种多样,可以采取以上一种,也可以多种并用。在目标检测训练中,不仅要对图像进行增广扩充,更需要将其标注结果也进行一定的变换,使结果能够使用变换后的数据,这样才能达到数据增广的目的。标注框的变换其实和图像的变换一致,图像怎么变换,标注坐标就怎么变换,需要注意的时在变换构成中适当的对框进行一定的扩充,才能达到效果。
随着深度学习的发展,越来越多的数据增广方式被提出来,比如cutmix,cutout,mixout等针对像素级的变换,不对图像进行延伸,也能达到增广的效果。GAN网络也常用来进行数据增强的操作。

你可能感兴趣的:(opencv)