本文首发于:https://my.oschina.net/Ldpe2G/blog/1803375。
在翻以前oschina上写的博客的时候,看到这篇觉得还挺有趣的,就重新修改并添加一些新的内容发到再公号上。
一般对图像做 augmentation 都会用仿射变换去实现,如果是用OpenCV来实现就是生成一个放射变换矩阵再调用OpenCV的warpAffine
函数,传入变换矩阵和图片得到变换后的输出,这里的难点在于如何生成这个仿射变换矩阵。
本文通过结合一个实际的例子(根据 bounding box 从图片中裁剪出特定的区域,然后做旋转、斜切和缩放等操作)来讲解如何通过一个简单的方法生成组合操作的仿射变换矩阵。
本文实验代码(包含了C++、Scala 和 Python 的实现):
https://github.com/Ldpe2G/CodingForFun/tree/master/AffineTransformationEx
下面来看下一个实际的例子,比如下图,根据给定的标注框从原图中裁剪出熊猫宝宝,并且对其做旋转、斜切和缩放等操作。
标注框
, 这四个数字从左到右的意思分别是, 标注框左上角
坐标, 标注框左上角
坐标, 框的宽和高。
其实仿射变换原理就是把原图上的一个点映射到目标图上的对应点,映射规则由变换矩阵确定。然后复杂的仿射变换可以通过将简单的仿射变换矩阵做矩阵乘法就得到。
像上面的例子,把图中的熊猫宝宝裁剪出来的,加上缩放、斜切和旋转等的组合变换,其实可以分解为6个变换(这个6个矩阵的顺序是我实验的结果,可能还有其他更好的方式):
裁剪、缩放、平移、旋转、斜切、平移
第一个变换矩阵,是根据标注框生成裁剪的矩阵,假设标注框信息是
,则裁剪出的框大小为。
首先计算出物体在原图的中心点以及物体在变换后的中心点,物体在原图的中心点坐标是
,而变换后的中心点坐标是
,则裁剪变换矩阵定义如下:
这个变换矩阵代表的意思简单来说就是把物体在原图上的中心点映射为裁剪后图的中心点,
做个简单的验证即可,物体在原图中心点坐标是
,做个矩阵向量乘法就得到了
。
第二个矩阵是根据输出大小作缩放,假设裁剪出来之后需要把图片大小缩放为 [outW,outH],则缩放矩阵为:
第三个矩阵是为了第四个旋转做准备的,首先把图中心点平移到左上角的原点,经过前两个变换之后,图片中心点变为[outW/2,outH/2]
,相当于把该点平移到左上角的原点,则平移矩阵为:
然后以原点为中心旋转
度,则旋转矩阵如下:
需要注意的是计算公式中的
表示的是弧度,所以要把角度转为弧度,就是要先把角度除以 180 再乘以
。
接着假设斜切变换因子是
,
和
方向可以单独设置,这里是统一设为一个值了,则斜切矩阵如下:
最后做完变换之后,再把原点平移回原来的中心点,平移矩阵如下:
最后把这6个矩阵做矩阵乘法(注意不是矩阵点乘)就得到最终的组合矩阵,注意哪个变换先做则优先排在右边,所以最后的矩阵是:
标注框信息:
。
,旋转0度
,逆时针旋转20度
,顺时针旋转20度
,斜切系数-0.2
,顺时针旋转20度,斜切系数0.2
本文分享自 GiantPandaCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!