计算机视觉教程2-4:图像仿射变换原理

举报
Mr.Winter 发表于 2022/03/21 21:21:21 2022/03/21
【摘要】 1 理论基础考虑如图1所示的一个变换,即将点P经过一个运算映射f映射成点Q。下面解释如果现在已知了P和Q的坐标,应该如何求出这个变换f图1直观地,写出代数方程:{x′= a1x+a2y+txy′= b1x+b2y+ty \left\{\begin{aligned}x' & = \ a_1 x+a_2 y+t_x\\y '& = \ b_1 x+b_2 y+t_y\\\end{aligne...

3a42366089df410590ace510e81229fd.png


1 理论基础

考虑如图1所示的一个变换,即将点P经过一个运算映射f映射成点Q。下面解释如果现在已知了P和Q的坐标,应该如何求出这个变换f
在这里插入图片描述

图1
直观地,写出代数方程:

{ x =   a 1 x + a 2 y + t x y =   b 1 x + b 2 y + t y \left\{ \begin{aligned} x' & = \ a_1 x+a_2 y+t_x\\ y '& = \ b_1 x+b_2 y+t_y\\ \end{aligned} \right.

写成矩阵形式

[ x y 1 ] = [ a 1 a 2 t x b 1 b 2 t y 0 0 1 ] [ x y 1 ] \begin{bmatrix} x'\\y'\\1\end{bmatrix}=\begin{bmatrix} a_1 & a_2 &t_x\\ b_1 & b_2 &t_y\\0&0&1 \end{bmatrix}\begin{bmatrix} x\\y\\1\end{bmatrix}

二维坐标的变化用三维矩阵的原因是要增加一个偏移量t的维度,否则t无法表现在映射关系f中。为了更深刻地理解第三维度,将其和线性变换作对比。线性变换的特点是:

①变换前后,直线仍然是直线

②变换前后,原点位置不变。

给出线性变换的变换矩阵:

[ x y ] = [ a 1 a 2 b 1 b 2 ] [ x y ] \begin{bmatrix} x'\\y'\\ \end{bmatrix}=\begin{bmatrix} a_1 & a_2 \\ b_1 & b_2 \\\end{bmatrix}\begin{bmatrix} x\\y\\\end{bmatrix}

将(0,0)代入显然原点位置不变。将 i \vec i =(1,0)以及 j \vec j =(0,1)代入可以得到一组新的由变换矩阵完全决定的基底,因此线性变换就是保持原点位置不变,将两条坐标轴(基底)进行变换,得到一个变换后新的坐标轴,原坐标系所有点被这个变换矩阵映射到新坐标系的对应点,而加入了第三维度偏移量之后的变换过程就可能使坐标原点发生平移,因此可能涵盖更多的变换,图3总结了三维度变换的可能情况。
在这里插入图片描述

图2 该图来源网络

2 算法实现

在OpenCV中,可使用cv2.warpAffine()进行操作。其中的参数Matrix就是变换矩阵,不过这里用户提供给cv2.warpAffine()的变换矩阵只要是
一个2×3的矩阵即可,也就是包含以下参数的矩阵: [ a 1 a 2 t x b 1 b 2 t y ] \begin{bmatrix} a_1 & a_2 &t_x\\ b_1 & b_2 &t_y\end{bmatrix} 因为所有变换矩阵的第三行都是确定的,该方法可以自动添加。

下面进行测试检验:

import cv2
import numpy as np

img = cv2.imread(r'C:\Users\91398\Desktop\test.jpg',1)
imgHeight = img.shape[0]
imgWidth = img.shape[1]
mat = np.float32([[1,0,0],[0,1,0]])
dstImg = cv2.warpAffine(img,mat,(imgWidth,imgHeight))
cv2.imshow('src.jpg',dstImg)
cv2.waitKey(0)
cv2.destroyAllWindows()

这个代码段给出的就是原图像如图3(i),这点可以从2×3的变换矩阵系数看到。现在对其逆时针翻转90°,修改mat参数即可,得到图3(ii)可以发现其完全变黑,观察算法理论知,这是因为整个图片被旋转到了画布之外。对旋转90°的变换矩阵增加一点y分量,也即旋转后再将y轴平移一个距离,可看到图像出现,这也证明了之前的黑色是因为图像出现在画布外。

图3

从上面的操作可以看出,虽然给cv2.warpAffine()传递一个变换矩阵,确实可以做到图像的各种变换,但每次操作都可能要进行横轴或纵轴的平移,这是很不方便的,因此在此基础上引入了一些新的方法:

cv2.getRotationMatrix2D((x_center,y_center),theta,scaling=1)

这个方法可以得到一个自定义旋转中心的变换矩阵,免去了旋转+平移的操作

cv2.getAffineTransform(pos1,pos2)

这个方法可以得到一个未知关系的变换矩阵,因为很大一部分变换并不能明确地使用图3的某种变换来实现,但我们已经知道变换前后的某三组点,那么可以根据这个方法求出这个变换矩阵,并将其应用于整个图像,使整个图像实现已知三组点的所谓变换。这里强调三组点的原因是二维平面变换矩阵 [ a 1 a 2 t x b 1 b 2 t y ] \begin{bmatrix} a_1 & a_2 &t_x\\ b_1 & b_2 &t_y\end{bmatrix} 有6个未知参数,一组点可以产生两个方程,因此需要三组点。可以推广,在三维平面的变换就需要四组点来实现矩阵求解。

3 小结

进行图像仿射变换的关键在于变换矩阵的求解。在简单的平移、旋转等变换时,可以自己手动传入一个变换矩阵,注意这个矩阵得用np.float32格式;也可以用OpenCV自定义中心的方法来实现。对于比较复杂,关系未知的变换,可以找到其中的三组点,用cv2.getAffineTransform()来求解变换矩阵,再传入cv2.warpAffine()


🚀 计算机视觉基础教程说明

章号                                    内容
  0               色彩空间与数字成像
  1               计算机几何基础
  2               图像增强、滤波、金字塔
  3               图像特征提取
  4               图像特征描述
  5               图像特征匹配
  6               立体视觉
  7               项目实战

🔥 更多精彩专栏

👇配套代码 · 优质体验 · 系统知识 请关注👇
AI技术社
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。