数据增广:旋转,缩放,平移以及错切
Posted 太阳花的小绿豆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据增广:旋转,缩放,平移以及错切相关的知识,希望对你有一定的参考价值。
在深度学习(图像领域)中,为了提升训练样本数量数据增广是非常常见的手段。比如:
- 随机水平翻转
- 随机色调(H)、饱和度(S)、明度(V)调整
- 随机旋转,缩放,平移以及错切
- 还有近几年常用的mixup,mosaic等等。
今天简单讲讲随机旋转,缩放,平移以及错切方法,因为在之前yolov3 spp
项目的数据读取部分有涉及到相关知识。本文会结合opencv来进行演示。
仿射变换
仿射变换的原理不在这里赘述,变换前后满足平直性(变换前是直线变换后还是直线)和平行性(变换前平行的线变换后依旧平行),参考博文。在opencv中可以通过仿射变换来实现旋转,缩放,平移以及错切等一系列操作。仿射变换的矩阵乘法形式如下,其中
x
,
y
x,y
x,y是变换前的坐标,
x
′
,
y
′
{x}',{y}'
x′,y′是变换后的坐标。其中
m
11
,
m
12
,
m
21
,
m
22
m_{11},m_{12},m_{21},m_{22}
m11,m12,m21,m22为线性变换参数,
m
13
,
m
23
m_{13},m_{23}
m13,m23为平移参数。如果仿射矩阵是对角矩阵,相当于不做任何操作。看到公式不要怕,后面会针对具体示例进行解释:
[
x
′
y
′
1
]
=
[
m
11
m
12
m
13
m
21
m
22
m
23
0
0
1
]
[
x
y
1
]
\\begin{bmatrix} {x}' \\\\ {y}'\\\\ 1 \\end{bmatrix} = \\begin{bmatrix} m_{11}\\ \\ m_{12}\\ \\ m_{13} \\\\ m_{21}\\ \\ m_{22}\\ \\ m_{23} \\\\ 0\\ \\ \\ \\ \\ \\ 0\\ \\ \\ \\ \\ \\ 1 \\end{bmatrix} \\begin{bmatrix} x\\\\ y\\\\ 1 \\end{bmatrix}
⎣⎡x′y′1⎦⎤=⎣⎡m11 m12 m13m21 m22 m230 0 1⎦⎤⎣⎡xy1⎦⎤
旋转、平移与缩放
首先再次强调下图像处理中的坐标系,水平向右为x轴正方向,竖直向下为y轴正方向。
对于图像的旋转,缩放,平移都可以直接通过使用opencv提供的getRotationMatrix2D
方法来求得仿射矩阵,需要传入旋转中心center
,旋转角度angle
(逆时针为正),以及缩放因子scale
,假设以图片中心为旋转中心,顺时针旋转30度(opencv里是以逆时针为正,所以angle=-30
),并缩放0.5倍:
import cv2
img = cv2.imread("1.png")
h, w = img.shape[0], img.shape[1]
m = cv2.getRotationMatrix2D(center=(w // 2, h // 2), angle=-30, scale=0.5)
print(m)
得到的旋转矩阵参数如下:
[[0.433 -0.25 198.14]
[0.25 0.433 16.25]]
接着使用opencv中的cv2.warpAffine
的方法利用求得的仿射矩阵做仿射变换,其中src
为原图像,M
为仿射矩阵,dsize
为输出图像的大小,borderValue
为边界填充颜色(注意是BGR顺序,
(
0
,
0
,
0
)
(0,0,0)
(0,0,0)代表黑色):
import cv2
img = cv2.imread("1.png")
h, w = img.shape[0], img.shape[1]
m = cv2.getRotationMatrix2D(center=(w // 2, h // 2), angle=-30, scale=0.5)
r_img = cv2.warpAffine(src=img, M=m, dsize=(w, h), borderValue=(0, 0, 0))
cv2.imshow("origin", img)
cv2.imshow("rotation_scale_trans", r_img)
cv2.waitKey(0)
如图,左边是原图,右边是旋转、缩放、平移后的图片(注意,旋转后如果有超出指定范围dsize
的像素都会被截去)。
接着结合上面的仿射变换公式来讲(不想看理论的可以跳过)。其中
m
11
,
m
12
,
m
21
,
m
22
m_{11},m_{12},m_{21},m_{22}
m11,m12,m21,m22为线性变换参数(沿坐标原点旋转就是一个简单的线性变换),
m
13
,
m
23
m_{13},m_{23}
m13,m23为平移参数(分别对应x轴方向平移和y轴方向平移)。
[
m
11
m
12
m
13
m
21
m
22
m
23
0
0
1
]
\\begin{bmatrix} m_{11}\\ \\ m_{12}\\ \\ m_{13} \\\\ m_{21}\\ \\ m_{22}\\ \\ m_{23} \\\\ 0\\ \\ \\ \\ \\ \\ 0\\ \\ \\ \\ \\ \\ 1 \\end{bmatrix}
⎣⎡m11 m12 m13m21 m22 m230 0 1⎦⎤
上面的操作其实可以分解成三步,第一步沿坐标原点旋转,第二步缩放图片,第三步平移图片。
对于第一步的原点旋转对应的仿射矩阵为(通过cv2.getRotationMatrix2D(center=(0, 0), angle=-30, scale=1.0)
求得):
[
0.866
−
0.5
0
0.5
0.866
0
0
0
1
]
\\begin{bmatrix} 0.866\\ \\ -0.5\\ \\ 0 \\\\ 0.5\\ \\ \\ \\ \\ \\ 0.866\\ \\ \\ 0 \\\\ 0\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ 0\\ \\ \\ \\ \\ \\ \\ \\ \\ 1 \\end{bmatrix}
⎣⎡0.866 −0.5 00.5 0.866 00 0 1⎦⎤
当然这里也可以直接使用旋转矩阵模板来计算,但需要注意的是模板里的旋转矩阵默认y轴是竖直向上的,但图像处理中y轴是竖直向下的,且都是以逆时针旋转为正,所以这里的
θ
=
30
°
\\theta=30\\degree
θ=30°:
[
c
o
s
(
θ
)
−
s
i
n
(
θ
)
0
s
i
n
(
θ
)
c
o
s
(
θ
)
0
0
0
1
]
\\begin{bmatrix} cos(\\theta)\\ \\ -sin(\\theta)\\ \\ 0 \\\\ sin(\\theta)\\ \\ \\ \\ \\ \\ cos(\\theta)\\ \\ \\ 0 \\\\ 0\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ 0\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ 1 \\end{bmatrix}
⎣⎡cos(θ) −sin(θ) 0sin(θ) cos(θ) 00 0 1⎦⎤
对于第二步图片的缩放,直接使用如下缩放矩阵:
[
S
x
0
0
0
S
y
0
0
0
1
]
\\begin{bmatrix} S_x\\ \\ \\ \\ 0 \\ \\ \\ \\ 0 \\\\ 0\\ \\ \\ \\ S_y\\ \\ \\ \\ 0 \\\\ 0\\ \\ \\ \\ 0\\ \\ \\ \\ 1 \\end{bmatrix}
⎣⎡Sx 0 00 Sy 00 0 1以上是关于数据增广:旋转,缩放,平移以及错切的主要内容,如果未能解决你的问题,请参考以下文章