数据增广:旋转,缩放,平移以及错切

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} xy1=m11  m12  m13m21  m22  m230      0      1xy1


旋转、平移与缩放

首先再次强调下图像处理中的坐标系,水平向右为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以上是关于数据增广:旋转,缩放,平移以及错切的主要内容,如果未能解决你的问题,请参考以下文章

CS184.1X 计算机图形学导论 第3讲L3V1

Android Matrix图像变换处理

Android Matrix 的理解与应用

OpenCV从仿射矩阵得到旋转量平移量缩放量

OpenCV从仿射矩阵得到旋转量平移量缩放量

日常回答小朋友问题