OpenCV-Python图像处理:透视变换概念、矩阵及实现案例详解

☞ ░ 老猿Python博文目录:https://blog.csdn.net/LaoYuanPython

要理解投影变换的原理最好能理解仿射变换的原理,关于仿射变换可参考老猿的仿射变换相关系列博文。

仿射变换博文传送门(带星号的为付费专栏文章):
  1. *图像仿射变换原理1:齐次坐标来龙去脉详解
  2. *图像仿射变换原理2:矩阵变换、线性变换和图像线性变换矩阵
  3. *图像仿射变换原理3:仿射变换类型及变换矩阵详解
  4. *图像仿射变换原理4:组合变换及对应变换矩阵
  5. *图像仿射变换原理5:组合变换矩阵的OpenCV-Python实现
  6. OpenCV-Python图像处理:仿射变换详解及案例
  7. OpenCV-Python仿射变换开发中遇到的坑
  8. openCV仿射变换:getAffineTransform的案例
  9. 为什么称图像旋转、错切、缩放变换是线性变换?
  10. 图像仿射变换:绕点旋转和指定直线依赖轴shear错切变换矩阵
  11. 图像仿射变换shear怎么翻译?剪切、错切、推移哪个译词好?
  12. 仿射变换原理和其OpenCV-Python实现知识汇总
OpenCV-Python图像处理:透视变换概念、矩阵及实现案例详解

一、概述

图像几何变换又称为图像空间变换,是各种图像处理算法的基础。它是在不改变图像内容的情况下,对图像像素进行空间几何变换的处理方式。它将一幅图像中的坐标位置映射到另一幅图像中的新坐标位置,其实质是改变像素的空间位置,估算新空间位置上的像素值。因此几何变换在变换过程中会建立一种原图像像素与变换后图像像素之间的映射关系,通过这种关系,能够从一方的像素计算出另一方的像素的坐标位置。通常将图像坐标映射到输出的过程称作向前映射,反之,将输出图像映射到输入的过程称作向后映射。向后映射在实践中使用较多,原因是能够避免使用向前映射中出现映射不完全和映射重叠的问题

适当的几何变换可最大程度地消除由于成像角度、透视关系乃至镜头自身原因所造成的几何失真所产生的负面影响。几何变换常常作为图像处理应用的预处理步骤,是图像归一化的核心工作之一。

一个几何变换需要两部分运算:首先是空间变换所需的运算,如平移、缩放、旋转和投影等, 需要用它来表示输出图像与输入图像之间的像素映射关系;此外,还需要使用灰度插值算法, 因为按照这种变换关系进行计算, 输出图像的像素可能被映射到输入图像的非整数坐标上。

图像的几何变换包括透视变换和仿射变换,透视变换又称为投影变换、投射变换、投影映射,透视变换是将图片投影到一个新的视平面,它是二维(x,y)到三维(X,Y,Z)、再到另一个二维(x’,y’)空间的映射。

:这部分文字写得很干脆和透彻,主要摘抄自CSDN知名博主Eastmount的博文《[Python图像处理] 三十六.OpenCV图像几何变换万字详解(平移缩放旋转、镜像仿射透视)》。

二、透视变换矩阵

图像透视变换(Perspective Transformation)的本质是将图像从一个几何平面投影到另一个几何平面,透视变换保证同一条直线的点还是在同一条直线上,但不再保证平行了。因为这是一个二维图像经过一个三维变换,然后映射到另外一个二维空间,二维图像的二维空间与映射后的二维空间不一样,如果一样就是仿射变换。

与前面《https://blog.csdn.net/LaoYuanPython/article/details/113788380 图像仿射变换原理3:仿射变换类型及变换矩阵详解》介绍仿射变换的仿射矩阵类似,透视变换也是建立在矩阵运算基础上的,通过矩阵运算可以很快的找到新旧图像的像素对应关系。

透视变换使用如下齐次坐标公式来进行描述:
在这里插入图片描述
上面公式中源图像和目标图像的坐标使用齐次坐标方式表示,变换矩阵为3阶方阵,该方阵为一单应性矩阵,就是比仿射矩阵多了一行。
在这里插入图片描述

可以看到,透视变换矩阵前2行2列为线性变换矩阵的元素构成(蓝色框标记范围),黄色框标记范围两个元素为平移对应元素,红色椭圆前2行整体为仿射矩阵,灰色矩形标记范围的第三行用于透视变换的空间变换,实际上第三行也只有前两列的m31、m32用于透视变换的空间变换,因为m33可以变换为常量1(关于这点具体请见付费专栏文章《getPerspectiveTransform通过4对点确认透视变换矩阵的原理分析》的分析)。

三、透视变换的作用

透视变换主要有三个作用:

  • 图像校正:透视变换可以将原图中涉及平面展现不合理的图像进行校正。为了说明问题,在此借用CSDN博主xiaowei_cqu的《【图像处理】透视变换 Perspective Transformation》中的图例来示意:
    在这里插入图片描述

  • 图像视角变换:就是将看图的视角进行调整一下,请看如下图:
    在这里插入图片描述

  • 图像拼接:相机拍照时,最终成像的照片角度大部分情况下不同,如果能将其转成相同的角度,则可以将多张照片进行拼接。进一步的了解大家可以参考单应性矩阵的理解及求解3的介绍。

    老猿就这个情况进行了仔细考虑,感觉可以通过如下思路来实现拼接:对于不同的两张涉及景物相邻的照片,找出相邻处都有的景物的相同位置的四个点,对两个图像进行仿射变换,将四个点都映射成相同大小的标准长方形,然后将两张结果图像进行拼接,拼接时将两个长方形完全重合,拼接后再将该结果照片进行仿射变换,确保长方形部分变换成两张原图中任意一张的四个点位置,则二者视角就统一了。找到合适的图像老猿就试一下,试了之后再详细介绍案例。

四、OpenCV-Python相关透视变换函数

4.1、getPerspectiveTransform 函数

getPerspectiveTransform函数根据源图像和目标图像上的四对点坐标来计算从原图像透视变换到目标头像的透视变换矩阵。

4.1.1、调用语法

getPerspectiveTransform(src, dst, solveMethod=None)

4.1.2、语法说明
  • src:源图像上四个点的坐标构成的矩阵,要求其中任意三点不共线
  • dst:目标图像上四个点的坐标构成的矩阵,要求其中任意三个点不共线,且每个点与src的对应点对应
  • solveMethod:矩阵分解方法,传递给cv2.solve(DecompTypes) 求解线性方程组或解决最小二乘问题,默认值为None,表示使用DECOMP_LU。
    solveMethod对应取值及含义如下
    在这里插入图片描述
    注:矩阵分解 ,英文称为matrix decomposition或matrix factorization是将矩阵拆解为数个矩阵的乘积,可分为三角分解、满秩分解、Jordan分解和SVD(奇异值)分解等,常见的有三种:1)三角分解法 (Triangular Factorization),2)QR 分解法 (QR Factorization),3)奇异值分解法 (Singular Value Decompostion)。 在图像处理方面,矩阵分解被广泛用于降维(压缩)、去噪、特征提取、数字水印等,是十分重要的数学工具,其中特征分解(谱分解)和奇异值分解是两种常用方法。


    老猿对矩阵分解目前也只知道概念,参阅资料《浅谈矩阵分解以及应用》,相关具体知识并不熟悉,对此有兴趣的可以进一步查阅相关资料。
  • 返回值:为一3*3的透视变换矩阵

4.2、warpPerspective 函数

warpPerspective函数用于对输入图像进行透视变换,透视变换使用如下公式来计算结果图像和输入图像的对应关系:
在这里插入图片描述
其中Mij代表透视变换矩阵的9个元素。

4.2.1、调用语法

warpPerspective(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)

4.2.2、语法说明
  • src:输入图像矩阵
  • M:3*3的透视变换矩阵,可以通过getPerspectiveTransform等函数获取
  • dsize:结果图像大小,为宽和高的二元组
  • dst:输出结果图像,可以省略,结果图像会作为函数处理结果输出
  • flags:可选参数,插值方法的组合(int 类型),默认值 INTER_LINEAR,本函数官方材料说明取值为INTER_LINEAR 或 INTER_NEAREST与 WARP_INVERSE_MAP的组合,但老猿测试其他标志也是支持的,具体取值及含义请参考《https://blog.csdn.net/LaoYuanPython/article/details/111771138 OpenCV-Python图像处理:插值方法及使用resize函数进行图像缩放》的介绍
  • borderMode:可选参数,边界像素模式(int 类型),默认值 BORDER_CONSTANT,本函数官方材料说明取值为BORDER_CONSTANT 或 BORDER_REPLICATE,实际上所有取值类型都支持,包括形态变换中不支持的BORDER_WRAP、BORDER_TRANSPARENT都能支持,并且不同取值有不同效果,具体取值及含义请参考《https://blog.csdn.net/LaoYuanPython/article/details/109441709 OpenCV-Python图像处理:腐蚀和膨胀原理及erode、dilate函数介绍》的介绍
  • borderValue:可选参数,边界填充值,当borderMode为cv2.BORDER_CONSTANT时使用,默认值为None;
  • 返回值:为透视变换后的结果图像矩阵,最后的结果矩阵每个像素与原图像像素的对应关系为:
    在这里插入图片描述

如果flags标记设置了WARP_INVERSE_MAP标记,首先使用invertAffineTransform对变换矩阵进行反转即求其逆矩阵,然后将其放入上面的公式中,而不是将M直接放入

  • 返回值:透视变换后的结果图像

五、案例

5.1、案例说明

5.1.1、输入图像

输入图像文件名为:f:\pic\Dog15.JPG,内容即上面说明 图像视角变换的小狗图像,borderMode用缺省值的图像为上面的小狗变换结果图像,下面我们看看borderMode取不同值BORDER_WRAP时的结果图像。

5.1.2、程序功能说明

本次将一张输入图像,将其原图像的四角对应四个点,通过透视变换映射到新图像,原图像的四个点中,底部左下和右下两个点保持不变,顶部左上和右上两个点的y坐标值映射为图像高度的一半,x坐标映射为宽带的1/3和2/3处。

5.2、示例代码

import cv2
import numpy as np

def changeView(imgFile):
    srcImg = cv2.imread(imgFile)
    r,c = srcImg.shape[:2]
    pointSrc = [[0,0],[c,0],[0,r],[c,r]]
    pointDest = [[int(c/3),int(r/2)],[int(c*2/3),int(r/2)],[0,r],[c,r]]
    srcPoints = np.float32(pointSrc)
    destPoints = np.float32(pointDest)

    m = cv2.getPerspectiveTransform(srcPoints, destPoints)
    resultImg = cv2.warpPerspective(srcImg, m, (c,r),flags=cv2.INTER_AREA ,borderMode=cv2.BORDER_WRAP)
    cv2.imshow("result img", resultImg)
    ch = cv2.waitKey(0)


changeView(r'f:\pic\Dog15.JPG')

5.3、效果

在这里插入图片描述

关于透视变换更多的案例请参考《https://blog.csdn.net/LaoYuanPython/article/details/113958088 狗狗变形记:任选4点的投影变换warpPerspective OpenCV-Python案例》。

六、小结

本节详细介绍了透视变换的概念、变换矩阵、作用以及OpenCV-Python相关的处理函数getPerspectiveTransform 和warpPerspective的语法及参数含义,并分析了输入图像和输出图像四对点确认透视变换矩阵的原理。最后提供了一个案例,来演示透视变换的代码实现及效果。本文的有些内容如四对点确认透视变换矩阵,在其他公开资料也有所提及(如CSDN博主lyhbkz的《单应性矩阵的理解及求解3》),但老猿结合齐次坐标和矩阵运算将其细化了,应该是网上公开资料首次全面介绍。相关内容有助于理解透视变换的概念和OpenCV-Python透视变换的应用方式。

参考资料:

1、[Python图像处理] 三十六.OpenCV图像几何变换万字详解(平移缩放旋转、镜像仿射透视)
2、单应性矩阵的理解及求解3
3、【图像处理】透视变换 Perspective Transformation

更多图像处理的介绍请参考专栏《OpenCV-Python图形图像处理 https://blog.csdn.net/laoyuanpython/category_9979286.html》和《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》相关文章。

更多图像处理的数学基础知识请参考专栏《人工智能数学基础 https://blog.csdn.net/laoyuanpython/category_10382948.html

写博不易,敬请支持:

如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!

如果对文章内容存在疑问,可以在博客评论区留言,或关注:老猿Python 微信公号发消息咨询。

关于老猿的付费专栏

  1. 付费专栏《https://blog.csdn.net/laoyuanpython/category_9607725.html 使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,对应文章目录为《 https://blog.csdn.net/LaoYuanPython/article/details/107580932 使用PyQt开发图形界面Python应用专栏目录》;
  2. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10232926.html moviepy音视频开发专栏 )详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/107574583 moviepy音视频开发专栏文章目录》;
  3. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》为《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的伴生专栏,是笔者对OpenCV-Python图形图像处理学习中遇到的一些问题个人感悟的整合,相关资料基本上都是老猿反复研究的成果,有助于OpenCV-Python初学者比较深入地理解OpenCV,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/109713407 OpenCV-Python初学者疑难问题集专栏目录
  4. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10762553.html Python爬虫入门 》站在一个互联网前端开发小白的角度介绍爬虫开发应知应会内容,包括爬虫入门的基础知识,以及爬取CSDN文章信息、博主信息、给文章点赞、评论等实战内容。

前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。

对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。

如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学Python!

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython

猜你喜欢

转载自blog.csdn.net/LaoYuanPython/article/details/114003964