opencv实现三重点_关于Image Warping的理解与实现

88137c11a07ed802d8f9f6a43a6da254.png

第一次在知乎写文章,操作不是很熟练,把写好的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的结果不理想,而反向变换的图像则不会产生这种问题。

c5583abac7c19cc81399896676049ec9.png

二.两图看懂Forward Warping和Inverse Warping

1.Forward Warping

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

2.Inverse Warping

cf114306924b298a6388177b3264f142.png
  • Inverse Warping的原理:遍历destination image中的每个点p_destination,乘以destination imagesource imageaffine matrix,得这个点在source image中的对应点p_source,令p_destination的像素值等于p_source的值,如果p_source的坐标不是整数,则采用插值逼近的方法进行近似,因此不会产生的Forward Warping的问题。

三.OpenCV的相关实现

1.OpenCV中的warpAffine函数

  • 由下图中列出的公式可知,OpenCV中的warpAffine 的实现是基于Inverse Warping的。
455d69ec490e392d4eac4ebaecfa88b3.png

说明:

  • WARP_INVERSE_MAP被指定时,函数的输入参数M表示从destination imagesource image2×3transform matrix,可以直接遍历destination image中的每个像素点,代入上图中的公式进行affine transform
  • WARP_INVERSE_MAP没有被指定时,M表示从source imagedestination imageaffine matrix,在函数内部首先会调用另一个函数invertAffineTransform求出M的逆,仍然是2×3affine matrix,然后再代入上图中的公式进行affine transform
  • flages表示插值方式WARP_INVERSE_MAP的组合,默认为 flags=cv2.INTER_LINEAR,表示线性插值,此外还有:cv2.INTER_NEAREST(最近邻插值),cv2.INTER_AREA(区域插值),cv2.INTER_CUBIC(三次样条插值)和cv2.INTER_LANCZOS4(Lanczos插值)
04db7f1fe60ecc88f486fd42351261ba.png
  • borderValue表示边界填充值,默认值为0,因此可能出现“黑边”现象
  • 一般情况下cv2.warpAffine(img,M,(rows,cols))即可完成基本的affine transform

2.OpenCV中的getAffineTransform函数

  • 官方文档——函数接口getAffineTransform函数的功能是计算给定的两组点(每组点有3个)之间的Affine Matrix
5186fde9c60942017522708d44c1555b.png
  • 具体实现过程
/* 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函数

上一节提到在OpenCVwarpAffine函数中如果WARP_INVERSE_MAP没有被指定时,在函数内部先要对Affine Matrix求逆,下面介绍使用OpenCVinvertAffineTransform函数求Affine Matrix的逆的内容

  • 官方文档——函数接口
b272beab252276ad728bfdd7175d1187.png
  • 主要实现过程
62ac2cd4df0ddf5890d00ba4e5371618.png

参考资料

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


版权声明:本文为weixin_36198673原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。