仿射变换实现组合操作 抠图+缩放+旋转

前言

之前在工作中需要用仿射变换的方式来实现,用给定的bounding box(标注框)从一张

图片中扣出特定的区域,然后做旋转和缩放等特定操作。然后在网上搜索了一下与仿射变换相关

的资料,看了仿射变换的思想和一些例子,然后结合手头上的代码,做了一些实验,最后终于搞

懂了如何实现。实验代码(提供C++、Scala和Python三种语言的实现):

码云地址

Github地址

正文

根据给定的标注框从原图中裁剪出物体并且对裁剪出的图片做各种随机旋转和缩放变换,

如果这几个步骤能合成一个仿射变换来做,则代码看起来会更加的简洁和通用。不过之前只了解

如何生成简单的仿射变换矩阵,而且上网上查阅了不少相关的资料,基本都是介绍一些常用的简

单变换,没看到这种有点复杂的组合变换怎么做。后来觉得还是得先了解清楚仿射变换的原理,

才知道怎么实现。首先贴上原图:

现在需要实现把图中的熊猫宝宝裁剪出来,标注框信息:[175,30,250,270], 这四个数字

从左到右的意思是, 标注框左上角x坐标, 标注框左上角y坐标, 框的宽, 框的高。

其实仿射变换的就是把原图上的一个点映射到目标图上的对应点,映射规则由变换矩阵

确定。然后复杂的仿射变换可以通过将简单的仿射变换对应的变换矩阵做矩阵乘法就得到

对应的复杂变换的矩阵。那么把图中的熊猫宝宝裁剪出来的,加上缩放和旋转等的组合变换,

其实可以分解为以下四个变换(这个是我实验的结果,可能还有其他更好的方式):

第一个变换矩阵(crop_mat)

是根据标注框以及裁剪出的大小生成裁剪与缩放组合矩阵,假设标注框信息是

[x, y, bboxW, bboxW],裁剪出的框大小 [outW, outH],这个大小表达的意思是相当于根据

标注框裁剪出物体后,再把该物体缩放的大小。首先我们先计算出物体在原图的中心点以及

物体在变换后的中心点,物体在原图的中心点就是 [x + bboxW / 2, y + bboxH / 2],变换后

的中心点就是 [outW / 2, outH / 2],则变换矩阵定义如下:

这个变换矩阵代表的意思简单来说就是把物体在原图上的中心点映射为裁剪缩放后图的中心点,

做个简单的验证即可,我们知道原图中心点是 [x + bboxW / 2, y + bboxH / 2],做个矩阵向

量乘法就到了[outW / 2, outH / 2]。

第二个变换矩阵(shift_mat1)

是平移矩阵,是做旋转之前的准备工作,把经过第一个变换后的中心点

(就是[outW / 2, outH / 2])平移到原点,矩阵定义:

第三个变换矩阵(rotate_map)

是旋转矩阵,给定旋转的角度 a,变换矩阵定义如下:

需要注意的是,用于计算公式中的cos和sin是弧度,所以要先把角度转为弧度,就是

先除以180再乘以pi。

第四个变换矩阵(shift_mat2)

是平移矩阵,把经过中心点平移回原来的位置,矩阵定义:

然后四个矩阵连续做矩阵乘法(注意不是矩阵点乘)就得到组合矩阵,哪个变换先做,

则优先排在右边,所以最后的矩阵是 shift_mat2 * rotate_mat * shift_mat1 * crop_mat:

有兴趣的读者可以自己推导下。

实验结果

标注框信息:[175,30,250,270]。

实验一、裁剪后图片大小设为[250,270],旋转0度

实验二、裁剪后图片大小设为[250,270],旋转20度

实验三、裁剪后图片大小设为[500,540],旋转-20度

实验四、裁剪后图片大小设为[125,135],旋转0度

相关资料

[1] 仿射变换

[2] 图像几何变换之仿射变换

[3] 何为仿射变换(Affine Transformation)

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏学海无涯

Android开发之奇怪的Fragment

说起Android中的Fragment,在使用的时候稍加注意,就会发现存在以下两种: v4包中的兼容Fragment,android.support.v4.ap...

3155
来自专栏拭心的安卓进阶之路

Java 集合深入理解(12):古老的 Vector

今天刮台风,躲屋里看看 Vector ! 都说 Vector 是线程安全的 ArrayList,今天来根据源码看看是不是这么相...

2437
来自专栏Phoenix的Android之旅

Java 集合 Vector

List有三种实现,ArrayList, LinkedList, Vector, 它们的区别在于, ArrayList是非线程安全的, Vector则是线程安全...

662
来自专栏MelonTeam专栏

ArrayList源码完全分析

导语: 这里分析的ArrayList是使用的JDK1.8里面的类,AndroidSDK里面的ArrayList基本和这个一样。 分析的方式是逐个API进行解析 ...

4489
来自专栏刘君君

JDK8的HashMap源码学习笔记

3008
来自专栏开发与安全

算法:AOV网(Activity on Vextex Network)与拓扑排序

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称之为AOV网(Activity on Vextex ...

2517
来自专栏计算机视觉与深度学习基础

Leetcode 114 Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place. For example, Given...

1938
来自专栏拭心的安卓进阶之路

Java 集合深入理解(6):AbstractList

今天心情比天蓝,来学学 AbstractList 吧! ? 什么是 AbstractList ? AbstractList 继承自 AbstractCollec...

19110
来自专栏Hongten

ArrayList VS Vector(ArrayList和Vector的区别)_面试的时候经常出现

1682
来自专栏聊聊技术

原 初学图论-Kahn拓扑排序算法(Kah

2878

扫码关注云+社区