Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >常用数据增广方法,解决数据单一问题

常用数据增广方法,解决数据单一问题

作者头像
Datawhale
发布于 2020-05-29 08:42:18
发布于 2020-05-29 08:42:18
2.4K00
代码可运行
举报
文章被收录于专栏:Datawhale专栏Datawhale专栏
运行总次数:0
代码可运行

Datawhale干货

寄语:本文将对传统图像算法的数据增广方式进行学习,以最常用的平移和旋转为例,帮助大家梳理几何变换的概念和应用,并对其在OpenCV的框架下进行了实现。

数据增广是深度学习中常用的技巧之一,主要用于增加训练数据集,让数据集尽可能的多样化,使得训练的模型具有更强的泛化能力。目前数据增广主要包括:水平/垂直翻转,旋转,缩放,裁剪,剪切,平移,对比度,色彩抖动,噪声等。传统图像算法中,常用几何变换来进行数据增广,其中常用方法有:缩放,平移,旋转,仿射等。

学习目标

  • 了解几何变换的概念与应用
  • 理解平移、旋转的原理
  • 掌握在OpenCV框架下实现平移、旋转操作

向前映射与向后映射

1. 前向映射

图像的几何变换就是建立一种源图像像素与变换后的图像像素之间的映射关系。也正是通过这种映射关系可以知道原图像任意像素点变换后的坐标,或者是变换后的图像在原图像的坐标位置等。

用简单的数学公式可以表示为:

其中,x,y代表输出图像像素的坐标,u,v表示输入图像的像素坐标,而U,V表示的是两种映射关系,f是将点(u,v)映射到(x,y)的映射关系,需要说明的是,映射关系可以是线性关系,也可以是多项式关系。

从上面的映射关系可以看到,只要给出了图像上任意的像素坐标,都能够通过对应的映射关系获得几何变换后的像素坐标。

这种将输入映射到输出的过程我们称之为 “向前映射”。但是在实际应用中,向前映射会出现如下几个问题:

  1. 浮点数坐标,如(1,1)映射为(0.5,0.5),显然这是一个无效的坐标,这时我们需要使用插值算法进行进一步处理。
  2. 可能会有多个像素坐标映射到输出图像的同一位置,也可能输出图像的某些位置完全没有相应的输入图像像素与它匹配,也就是没有被映射到,造成有规律的空洞(黑色的蜂窝状)。

什么是有规律的空洞呢?下面举个例子大家就明白了

可以从上图知道:原图经过前向映射旋转了30度后,输出图像中有规律的空洞(黑色的蜂窝状),那这些空洞是这么来的呢?

可以看到,旋转三十度后,输出图像两个红色的点被映射到同一个坐标,而没有点被映射到绿色问号处,这就造成了间隙和重叠,导致出现蜂窝状空洞。

2. 向后映射

为了克服前向映射的这些不足,因此引进了“后向映射”,它的数学表达式为:

可以看出,后向映射与前向映射刚好相反,它是由输出图像的像素坐标反过来推算该像素为在源图像中的坐标位置。这样,输出图像的每个像素值都能够通过这个映射关系找到对应的为止。而不会造成上面所提到的映射不完全和映射重叠的现象。

在实际处理中基本上都运用向后映射来进行图像的几何变换。但是反向映射也有一个和前向映射一样的问题, 就是映射后会有小数,需通过插值方法决定输出图像该位置的值,OpenCV默认为双线性插值。

在使用过程中,如果在一些不改变图像大小的几何变换中,向前映射还是十分有效的,向后映射主要运用在图像的旋转的缩放中,因为这些几何变换都会改变图像的大小。

几何变换

先看第一个问题,变换的形式。在本篇文章里图像的几何变换全部都采用统一的矩阵表示法,形式如下:

这就是向前映射的矩阵表示法,其中,表示输出图像像素的坐标,,表示输入图像像素的坐标,同理,向后映射的矩阵表示为:

可以证明,向后映射的矩阵的表示正好是向前映射的逆变换。

下面举几个例子。原图如下:

1. 向上平移一个单位向右平移一个单位

2. 放大为原来的两倍

3. 顺时针旋转45度

4. 水平偏移2个单位

坐标系变换

再看第二个问题,变换中心,对于缩放、平移可以以图像坐标原点(图像左上角为原点)为中心变换,这不用坐标系变换,直接按照一般形式计算即可。而对于旋转和偏移,一般是以图像中心为原点,那么这就涉及坐标系转换了。

我们都知道,图像坐标的原点在图像左上角,水平向右为 X 轴,垂直向下为 Y 轴。数学课本中常见的坐标系是以图像中心为原点,水平向右为 X 轴,垂直向上为 Y 轴,称为笛卡尔坐标系。看下图:

因此,对于旋转和偏移,就需要3步(3次变换):

  • 将输入原图图像坐标转换为笛卡尔坐标系;
  • 进行旋转计算。旋转矩阵前面已经给出了;
  • 将旋转后的图像的笛卡尔坐标转回图像坐标。

那么,图像坐标系与笛卡尔坐标系转换关系是什么呢?先看下图:

在图像中我们的坐标系通常是AB和AC方向的,原点为A,而笛卡尔直角坐标系是DE和DF方向的,原点为D。

令图像表示为M×N的矩阵,对于点A而言,两坐标系中的坐标分别是(0,0)和(-N/2,M/2),则图像某像素点(x',y')转换为笛卡尔坐标(x,y)转换关系为,x为列,y为行:

逆变换为:

于是,根据前面说的3个步骤(3次变换),旋转(顺时针旋转)的变换形式就为,3次变换就有3个矩阵:

即:

基于OpenCV的实现

  • 工具:OpenCV4.1.0+VS2019
  • 平台:WIN10

函数原型(c++)

OpenCV仿射变换相关的函数一般涉及到warpAffine和getRotationMatrix2D这两个:

  • 使用OpenCV函数warpAffine 来实现一些简单的重映射.
  • OpenCV函数getRotationMatrix2D 来获得旋转矩阵。

1. warpAffined函数详解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void boxFilter( InputArray src, OutputArray dst,                int ddepth,                Size ksize,                Point anchor = Point(-1,-1),                bool normalize = true,                int borderType = BORDER_DEFAULT );
  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
  • 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的M,2×3的变换矩阵。
  • 第四个参数,Size类型的dsize,表示输出图像的尺寸。
  • 第五个参数,int类型的flags,插值方法的标识符。此参数有默认值INTER_LINEAR(线性插值)。
  • 第六个参数,int类型的borderMode,边界像素模式,默认值为BORDER_CONSTANT。
  • 第七个参数,const Scalar&类型的borderValue,在恒定的边界情况下取的值,默认值为Scalar(),即0。

2. getRotationMatrix2D函数详解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
C++: Mat getRotationMatrix2D(Point2f center, double angle, double scale)

参数:

  • 第一个参数,Point2f类型的center,表示源图像的旋转中心。
  • 第二个参数,double类型的angle,旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)。
  • 第三个参数,double类型的scale,缩放系数。

实现示例(c++)

1、旋转

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Mat src = imread("../image/source3.jpg");//读取原图像  cv::Mat dst;    //旋转角度  double angle = 45;  cv::Size src_sz = src.size();  cv::Size dst_sz(src_sz.height, src_sz.width);  int len = std::max(src.cols, src.rows);   //指定旋转中心(图像中点)  cv::Point2f center(len / 2., len / 2.);
  //获取旋转矩阵(2x3矩阵)  cv::Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
  //根据旋转矩阵进行仿射变换  cv::warpAffine(src, dst, rot_mat, dst_sz);
  //显示旋转效果  cv::imshow("image", src);  cv::imshow("result", dst);  cv::waitKey(0);  return 0;

但是这么写有一个问题,就是旋转后图像会被截断,如下图所示:(左边为原图,右边为顺时针旋转45度后的图)

可以看到,图像的一部分被截断了,其原因是:

1. 旋转过后的图像大小应该发生变化才能装下旋转后的图片;

2. OpenCv将坐标转成笛卡尔坐标系后没转回图像坐标系。

其中比较难理解的是图像大小的变换,下面举一个例子大家就能明白了:

如图:ABCD是变换前矩形,EFGH是变换后的矩形,变换的矩阵表示为:

即表达式为:

所以,要算旋转后图片的大小,只需计算原图像四个顶点变换后的图像所确定的外接矩形长宽。

因为经过坐标变换后的图像是关于原点对称的,所以计算D点变换后的横坐标的绝对值乘2,就是变换后矩形的长,计算A点变换后的纵坐标的绝对值乘2,就是变换后矩形的宽。

设原图像长为2a,宽为2b,变换后的图像长宽为c,d,则A点的坐标为:(-a, b), D点坐标:(a, b)

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  Mat src = imread("../image/source3.jpg");//读取原图像  Mat dst;  // 旋转角度  double angle = 45.0;
  // 计算旋转后输出图形的尺寸  int rotated_width = ceil(src.rows * fabs(sin(angle * CV_PI / 180)) + src.cols * fabs(cos(angle * CV_PI / 180)));  int rotated_height = ceil(src.cols * fabs(sin(angle * CV_PI / 180)) + src.rows * fabs(cos(angle * CV_PI / 180)));
  // 计算仿射变换矩阵  Point2f center(src.cols / 2, src.rows / 2);  Mat rotate_matrix = getRotationMatrix2D(center, angle, 1.0);
  // 防止切边,对平移矩阵B进行修改  rotate_matrix.at<double>(0, 2) += (rotated_width - src.cols) / 2;  rotate_matrix.at<double>(1, 2) += (rotated_height - src.rows) / 2;
  // 应用仿射变换  warpAffine(src, dst, rotate_matrix, Size(rotated_width, rotated_height), INTER_LINEAR, 0, Scalar(255, 255, 255));  imshow("result", dst);  cv::imwrite("right.jpg", dst);  waitKey();  return 0;

结果:

2、平移

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Mat src = imread("../image/source2.jpg");//读取原图像  cv::Mat dst;
  cv::Size dst_sz = src.size();
  //定义平移矩阵  cv::Mat t_mat =cv::Mat::zeros(2, 3, CV_32FC1);
  t_mat.at<float>(0, 0) = 1;  t_mat.at<float>(0, 2) = 300; //水平平移量  t_mat.at<float>(1, 1) = 1;  t_mat.at<float>(1, 2) = 300; //竖直平移量
  //根据平移矩阵进行仿射变换  cv::warpAffine(src, dst, t_mat, dst_sz);
  //显示平移效果  cv::imshow("image", src);  cv::imshow("result", dst);
  cv::waitKey(0);
  return 0;

3. 仿射变化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <opencv2/opencv.hpp>#include <iostream>using namespace cv;using namespace std;
int main(int argc, char** argv){    Mat src = imread("../image/source2.jpg");//读取原图像
    //分别在原图像和目标图像上定义三个点    Point2f srcTri[3];    Point2f dstTri[3];
    srcTri[0] = Point2f(0, 0);    srcTri[1] = Point2f(src.cols - 1, 0);    srcTri[2] = Point2f(0, src.rows - 1);
    dstTri[0] = Point2f(src.cols * 0.0, src.rows * 0.33);    dstTri[1] = Point2f(src.cols * 0.85, src.rows * 0.25);    dstTri[2] = Point2f(src.cols * 0.15, src.rows * 0.7);
    Mat dst;//目标图像    //设置目标图像的大小和类型与原图像一致,初始像素值都为0    dst = Mat::zeros(src.rows, src.cols, src.type());    //计算仿射变换矩阵     Mat trans_mat = getAffineTransform(srcTri, dstTri);    //对原图像应用上面求得的仿射变换    warpAffine(src, dst, trans_mat, src.size());
    //显示结果    imshow("origin_image", src);    imshow("dst_image", dst);
    //储存图像    imwrite("dst1.jpg", dst);    waitKey(0);    return 0;}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Datawhale 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
10、图像的几何变换——平移、镜像、缩放、旋转、仿射变换 OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(1)OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(2)数字图像
  图像几何变换又称为图像空间变换,它将一副图像中的坐标位置映射到另一幅图像中的新坐标位置。我们学习几何变换就是确定这种空间映射关系,以及映射过程中的变化参数。图像的几何变换改变了像素的空间位置,建立一种原图像像素与变换后图像像素之间的映射关系,通过这种映射关系能够实现下面两种计算:
vv彭
2020/10/27
4.2K0
10、图像的几何变换——平移、镜像、缩放、旋转、仿射变换
    


OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(1)OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(2)数字图像
OpenCV与仿射变换
拉伸、收缩、扭曲、旋转是图像的几何变换,在三维视觉技术中大量应用到这些变换,又分为仿射变换和透视变换。
种花家的奋斗兔
2020/11/12
1.2K0
【走进OpenCV】重映射与仿射变换
其中的 f 就是映射方式,也就说,像素点在另一个图像中的位置是由 f 来计算的。
小白学视觉
2019/10/24
1.3K0
【从零学习OpenCV 4】图像仿射变换
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。
小白学视觉
2019/11/30
9680
经验 | OpenCV图像旋转的原理与技巧
初学图像处理,很多人遇到的第一关就是图像旋转,图像旋转是图像几何变换中最具代表性的操作,包含了插值、背景处理、三角函数等相关知识,一个变换矩阵跟计算图像旋转之后的大小公式就让很多开发者最后直接调用函数了事,但是其实这个东西并没有这么难懂,可以说主要是之前别人写的公式太吓人,小编很久以前第一次接触的也是被吓晕了!所以决定从程序员可以接受的角度从新介绍一下图像旋转基本原理与OpenCV中图像旋转函数操作的基本技巧。
OpenCV学堂
2020/12/18
3K0
图像处理的仿射变换与透视变换
  这一周主要在研究图像的放射变换与透视变换,目前出现的主要问题是需要正确识别如下图中的编码标志点圆心。 1.当倾斜角较小时:
3D视觉工坊
2020/12/11
1.5K0
图像处理的仿射变换与透视变换
【opencv实践】仿射变换和透视变换
上面这副图就是我们今天要处理的了,我们想把它从拍照视角变成鸟瞰图,这是机器人导航中的常用手段,以便在该平面上进行规划和导航。
周旋
2020/06/04
5.8K1
Task02 几何变换
该部分将对基本的几何变换进行学习,几何变换的原理大多都是相似,只是变换矩阵不同,因此,我们以最常用的平移和旋转为例进行学习。在深度学习领域,我们常用平移、旋转、镜像等操作进行数据增广;在传统CV领域,由于某些拍摄角度的问题,我们需要对图像进行矫正处理,而几何变换正是这个处理过程的基础,因此了解和学习几何变换也是有必要的。
致Great
2020/04/30
7720
计算机视觉:6.2~6.5 图像的基本变换与仿射变换
图像的基本变换与仿射变换 6.2 图像的翻转和旋转 图像的翻转 flip(src, flipCode) flipCode=0:上下翻转; flipCode>0:左右翻转; flipCode<0:上下 + 左右翻转; # 图像的翻转 import cv2 import numpy as np # 读取图片 doge = cv2.imread('./doge.jpg') new_doge1 = cv2.flip(doge, flipCode=0) new_doge2 = cv2.flip(doge, fl
DioxideCN
2022/08/05
8090
计算机视觉:6.2~6.5 图像的基本变换与仿射变换
OpenCV图像几何变换专题(缩放、翻转、仿射变换及透视)【python-Open_CV系列(五)】
OpenCV图像几何变换专题(缩放、翻转、仿射变换及透视)(python为工具) 【Open_CV系列(五)】
全栈程序员站长
2022/11/16
1.2K0
OpenCV图像几何变换专题(缩放、翻转、仿射变换及透视)【python-Open_CV系列(五)】
视觉进阶 | Numpy和OpenCV中的图像几何变换
上面的图像使它不言而喻什么是几何变换。它是一种应用广泛的图像处理技术。例如,在计算机图形学中有一个简单的用例,用于在较小或较大的屏幕上显示图形内容时简单地重新缩放图形内容。
小白学视觉
2020/02/27
2.4K0
图像仿射
算法:图像仿射是图像通过一系列几何变换实现平移、旋转等多种操作。仿射变换保持图像平直性和平行性。平直性是图像经过仿射变换后,直线仍然是直线。平行性是图像经过仿射变换后,平行线仍然是平行线。
裴来凡
2022/05/28
5330
图像仿射
OpenCV 几何变换-图像旋转
OpenCV提供了warpAffine函数实现图片仿射变换功能,我们可以利用这个函数实现图像旋转,函数原型为:
chaibubble
2022/05/07
2900
OpenCV 几何变换-图像旋转
OpenCV极坐标变换函数warpPolar的使用
前阵子在做方案时,得了几张骨钉的图片,骨科耗材批号效期管理一直是比较麻烦的,贴RFID标签成本太高,所以一般考虑还是OCR的识别比较好,因为本身骨钉的字符是按圆印上去的,直接截取图片进行OCR没法识别,需要经过图像处理后再识别,所以这篇就是学习一下OpenCV的极坐标变换函数。
Vaccae
2023/12/14
5600
OpenCV极坐标变换函数warpPolar的使用
空间变换是什么_信号与系统状态转移矩阵
文章提出的STN的作用类似于传统的矫正的作用。比如人脸识别中,需要先对检测的图片进行关键点检测,然后使用关键点来进行对齐操作。但是这样的一个过程是需要额外进行处理的。但是有了STN后,检测完的人脸,直接就可以做对齐操作。关键的一点就是这个矫正过程是可以进行梯度传导的。想象一下,人脸检测完了,直接使用ROI pooling取出人脸的feature map,输入STN就可以进行矫正,输出矫正后的人脸。后面还可以再接点卷积操作,直接就可以进行分类,人脸识别的训练。整个流程从理论上来说,都有梯度传导,理论上可以将检测+对齐+识别使用一个网络实现。当然实际操作中可能会有各种trick。
全栈程序员站长
2022/11/02
1K0
空间变换是什么_信号与系统状态转移矩阵
OpenCV 3.1.0中的图像放缩与旋转
OpenCV在3.1.0版本中的图像放缩与旋转操作比起之前版本中更加的简洁方便,同时还提供多种插值方法可供选择。首先来看图像放缩,通过OpenCV核心模块API函数resize即可实现图像的放大与缩小。 一:图像放缩(zoom in/out) 函数resize相关API参数介绍 -src表示输入图像,类型一般是Mat类型 -dst表示输出图像,类型一般是Mat类型 -dsize表示输出图像大小,如果是零的话表示从fx与fy两个参数计算得到 dsize= Size(round(src.cols*fx), r
OpenCV学堂
2018/04/04
2.5K0
OpenCV 3.1.0中的图像放缩与旋转
opencv常用函数
本文主要介绍:Opencv常用函数,如均值、最大最小、归一化、滤波、旋转、求连通域等函数。
vv彭
2020/12/16
1.1K0
图像变换基础:齐次坐标系
在前面讨论线性变换的时候,我们没有提到平移。什么是平移?以二维的平面为例,如图2-2-10所示,向量 就是向量 平移的结果,即连接两个图形的对应点的直线平行,则两个图形是平移变换。很显然,这种平移不是线性变换——向量 所在直线并不是平面空间的子空间。尽管如此,我们可以用矩阵加法表示图2-2-10所示的平移变换:
老齐
2022/01/04
2.6K0
图像变换基础:齐次坐标系
实战 | OpenCV实现多角度模板匹配(详细步骤 + 代码)
本文将介绍使用OpenCV实现多角度模板匹配的详细步骤 + 代码。(来源公众号:OpenCV与AI深度学习)
Color Space
2022/05/26
13.8K0
实战 | OpenCV实现多角度模板匹配(详细步骤 + 代码)
【5】OpenCV2.4.9实现图像拼接与融合方法【SURF、SIFT、ORB、FAST、Harris角点 、stitch 】
本文出现的数据结果和码源见:https://download.csdn.net/download/sinat_39620217/18269470
汀丶人工智能
2022/12/21
3.2K0
【5】OpenCV2.4.9实现图像拼接与融合方法【SURF、SIFT、ORB、FAST、Harris角点 、stitch 】
推荐阅读
相关推荐
10、图像的几何变换——平移、镜像、缩放、旋转、仿射变换 OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(1)OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(2)数字图像
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验