
第一次在知乎写文章,操作不是很熟练,把写好的markdown文件直接导入后发现会出现排版错乱的问题,索性将markdown的内容直接粘贴过来再调整格式。要是有大佬知道怎么解决这个问题请赐教。废话不多说,直接上正文。
本文是在完成图像处理与图像识别课程第六次作业过程中的一些知识点总结,主要包括以下两部分:
- 课后作业
- 两图看懂Forward Warping和Inverse Warping
- OpenCV的相关实现
下文中编程题用到的代码和代码运行结果已经上传到Github中,仅供参考。
一.课后作业
1.证明题
证明:仿射变换(Affine Transformation
)中平行线变换后仍然是平行线。
设AB∥CD,A′,B′,C′,D′
分别是A,B,C,D
经过某个仿射变换后的像。假设A′B′
与C′D'
不平行,则由于它们在同一个平面上,因此它们有公共点P′
,所以点P′
的原像P
既在直线AB
上,又在直线CD
上。这与AB∥CD
的前提矛盾,因此A′B′∥C′D′
。
2.编程题
通过实验对比正向变换(Forward warping
)与反向变换(inverse warping
)对图像变形/扭曲(Image warps
)结果的不同,且总结正向变换的缺点可能有哪些。
注:pts1 = np.float32([[50,50],[200,50],[50,200]]),pts2 = np.float32([[10,100],[200,50],[100,250]]),以pts1->pts2的变换矩阵为对lena.jpg扭曲所需的变换关系。
下图为正向变换与反射变换的结果。程序使用matplotlib
画出的1,2,3,4四个子图分别为原图,正向变换的结果,原图,反向变换的结果。其中红色的点为pts1,蓝色的点为pts2。可以明显的看出正向变换的结果产生了大量空洞,并且在实现过程中会有像素的重叠,使image warping
的结果不理想,而反向变换的图像则不会产生这种问题。

二.两图看懂Forward Warping和Inverse Warping
1.Forward Warping

- Forward Warping的原理:遍历
source image
中的每个点p_source
,乘以从source image
到destination image
的affine matrix
,将其投影到destination image
中得到p_destination
,如果p_destination
的坐标不是整数,则进行四舍五入取整,这必然会产生问题:destination image
中有的位置没有从source image
中投影过来的点,有的位置有多个从source image
中投影过来的点,所以会产生很多空洞,产生类似波纹的效果。
2.Inverse Warping

- Inverse Warping的原理:遍历
destination image
中的每个点p_destination
,乘以destination image
到source image
的affine matrix
,得这个点在source image
中的对应点p_source
,令p_destination
的像素值等于p_source
的值,如果p_source
的坐标不是整数,则采用插值逼近的方法进行近似,因此不会产生的Forward Warping
的问题。
三.OpenCV的相关实现
1.OpenCV中的warpAffine
函数
- 由下图中列出的公式可知,OpenCV中的warpAffine 的实现是基于Inverse Warping的。

说明:
- 当WARP_INVERSE_MAP被指定时,函数的输入参数
M
表示从destination image
到source image
的2×3的transform matrix
,可以直接遍历destination image
中的每个像素点,代入上图中的公式进行affine transform
- 当WARP_INVERSE_MAP没有被指定时,
M
表示从source image
到destination image
的affine matrix
,在函数内部首先会调用另一个函数invertAffineTransform求出M
的逆,仍然是2×3的affine matrix
,然后再代入上图中的公式进行affine transform
flages
表示插值方式与WARP_INVERSE_MAP的组合,默认为flags=cv2.INTER_LINEAR
,表示线性插值,此外还有:cv2.INTER_NEAREST
(最近邻插值),cv2.INTER_AREA
(区域插值),cv2.INTER_CUBIC
(三次样条插值)和cv2.INTER_LANCZOS4
(Lanczos插值)

borderValue
表示边界填充值,默认值为0,因此可能出现“黑边”现象- 一般情况下
cv2.warpAffine(img,M,(rows,cols))
即可完成基本的affine transform
2.OpenCV中的getAffineTransform函数
- 官方文档——函数接口
getAffineTransform
函数的功能是计算给定的两组点(每组点有3个)之间的Affine Matrix

- 具体实现过程
/* Calculates coefficients of affine transformation
* which maps (xi,yi) to (ui,vi), (i=1,2,3):
*
* ui = c00*xi + c01*yi + c02
*
* vi = c10*xi + c11*yi + c12
*
* Coefficients are calculated by solving linear system:
* / x0 y0 1 0 0 0 /c00 /u0
* | x1 y1 1 0 0 0 | |c01| |u1|
* | x2 y2 1 0 0 0 | |c02| |u2|
* | 0 0 0 x0 y0 1 | |c10| |v0|
* | 0 0 0 x1 y1 1 | |c11| |v1|
* 0 0 0 x2 y2 1 / |c12| |v2|
*
* where:
* cij - matrix coefficients
*/
3.OpenCV的invertAffineTransform函数
上一节提到在OpenCV
的warpAffine函数中如果WARP_INVERSE_MAP没有被指定时,在函数内部先要对Affine Matrix
求逆,下面介绍使用OpenCV
的 invertAffineTransform
函数求Affine Matrix
的逆的内容
- 官方文档——函数接口

- 主要实现过程

参考资料
OpenCV-doc getAffineTransform函数docs.opencv.org
OpenCV-doc warpAffine函数docs.opencv.org
Princeton University CS426 lectures, FALL 2000www.cs.princeton.edu
北京邮电大学2020秋季学期图像处理与图像识别课程lecture07github.com
线代启示录仿射变换ccjou.wordpress.com