一文搞懂仿射变换

Posted 修炼之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文搞懂仿射变换相关的知识,希望对你有一定的参考价值。

导读

在图像处理中,我们经常需要对图像进行各种操作如平移、缩放、旋转、翻转等,这些其实都是图像的仿射变换。通过本篇文章,你能够知道它们的实现原理以及如何应用它们。

仿射变换

仿射变换也称仿射投影,是指几何中,对一个向量空间进行线性变换并接上一个平移,变换为另一个向量空间。所以,仿射变换其实也就是再讲如何来进行两个向量空间的变换
假设有一个向量空间 k k k
k = ( x , y ) k=(x,y) k=(x,y)
还有一个向量空间 j j j
j = ( x ′ , y ′ ) j=(x',y') j=(x,y)
如果我们想要将向量空间由 k k k变为 j j j,可以通过下面的公式进行变换
j = k ∗ w + b j = k* w + b j=kw+b
将上式进行拆分可得
x ′ = w 00 ∗ x + w 01 ∗ y + b 0 y ′ = w 10 ∗ x + w 11 ∗ y + b 1 x'=w_00*x+w_01*y+b_0 \\\\ y'=w_10*x+w_11*y+b_1 x=w00x+w01y+b0y=w10x+w11y+b1
我们再将上式转换为矩阵的乘法
[ x ′ y ′ ] = [ w 00 w 01 b 0 w 10 w 11 b 1 ] [ x y 1 ] = M [ x y 1 ] (3) \\left[ \\beginmatrix x' \\\\ y' \\\\ \\endmatrix \\right] \\tag3= \\left[ \\beginmatrix w_00 & w_01 & b_0 \\\\ w_10 & w_11 & b_1\\\\ \\endmatrix \\right] \\left[ \\beginmatrix x \\\\ y \\\\ 1 \\endmatrix \\right]= M \\left[ \\beginmatrix x\\\\ y\\\\ 1 \\endmatrix \\right] [xy]=[w00w10w01w11b0b1]xy1=Mxy1(3)
通过参数矩阵 M M M就可以实现两个向量空间之间的转换,在进行仿射变换的时候我们也只需要一个矩阵 M M M就可以实现平移缩放旋转翻转变换。

接下来,会先介绍原理然后利用OpenCV来实现相应的例子,这里主要利用OpenCV的warpAffine函数来实现仿射变换

warpAffine函数参数:

  • src:输入的图像数组
  • M:仿射变换矩阵
  • dsize:变换后图像的大小
  • flags:使用的插值算法
  • borderValue:边界的填充值
图像平移

在平面坐标系有点 P ( x , y ) P(x,y) P(x,y)和点 P ′ ( x ′ , y ′ ) P'(x',y') P(x,y),如果我们想要将 P P P点移动到 P ′ P' P通过下面的变换就可以实现
x ′ = x + Δ x y ′ = y + Δ y x'=x+\\Delta x \\\\ y' = y + \\Delta y x=x+Δxy=y+Δy
其中 Δ x \\Delta x Δx Δ y \\Delta y Δy就是x方向上和y方向上的偏移量,我们将其转换为矩阵的形式
[ x ′ y ′ ] = [ 1 0 Δ x 0 1 Δ y ] [ x y 1 ] = M [ x y 1 ] \\left[ \\beginmatrix x'\\\\ y'\\\\ \\endmatrix \\right]= \\left[ \\beginmatrix 1 & 0 & \\Delta x\\\\ 0 & 1 & \\Delta y\\\\ \\endmatrix \\right] \\left[ \\beginmatrix x\\\\ y\\\\ 1 \\endmatrix \\right]= M\\left[ \\beginmatrix x\\\\ y\\\\ 1 \\endmatrix \\right] [xy]=[1001ΔxΔy]xy1=Mxy1
上面的矩阵 M M M就是仿射变换的平移参数,接下来我们利用OpenCV中的warpAffine函数来实现

import cv2
import numpy as np
import matplotlib.pyplot as plt

def show_compare_img(original_img,transform_img):
    _,axes = plt.subplots(1,2)
    #显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    #设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("warpAffine transform image")
    plt.show()


def translation_img():
    # 定义一个图像平移矩阵
    # x向左平移(负数向左,正数向右)20个像素
    # y向下平移(负数向上,正数向下)50个像素
    M = np.array([[1, 0, -20], [0, 1, 50]], dtype=np.float)
    # 读取需要平移的图像
    img = cv2.imread("test.jpg")
    # 将图片由BGR转为RGB
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 定义平移后图像的大小,保持和原图大小一致
    dsize = img.shape[:2][::-1]
    # 便于大家观察这里采用白色来填充边界
    translation_img = cv2.warpAffine(img, M, dsize, borderValue=(255, 255, 255))
    # 显示图像
    show_compare_img(img, translation_img)

translation_img()

图像翻转

有时候我们我们需要对图像进行水平翻转垂直翻转镜像翻转(同时进行水平和垂直翻转),想要实现这个功能并不难,我们可以通过opencv内置的flip方法很容易实现,还可以通过numpy的索引来实现,这里我们主要介绍通过仿射变换矩阵来实现这个功能

上图中的 A 、 B 、 C 、 D A、B、C、D ABCD表示图像的四个顶点,如果我们需要对图像进行水平翻转,那么我们就需要将 A A A点和 B B B点进行交换, C

以上是关于一文搞懂仿射变换的主要内容,如果未能解决你的问题,请参考以下文章

opencv 图像各方向旋转

iOS开发之仿射变换示例总结

仿射空间中几种基本映射的矩阵表述

OpenGL基础仿射变换原理解析

【转】仿射变换及其变换矩阵的理解

图像处理之_仿射变换与透视变换