《数字图像处理-OpenCV/Python》连载(44)图像的投影变换

《数字图像处理-OpenCV/Python》连载(44)图像的投影变换


本书京东优惠购书链接:https://item.jd.com/14098452.html
本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html

在这里插入图片描述


第 6 章 图像的几何变换


几何变换分为等距变换、相似变换、仿射变换和投影变换,是指对图像的位置、大小、形状和投影进行变换,将图像从原始平面投影到新的视平面。OpenCV图像的几何变换,本质上是将一个多维数组通过映射关系转换为另一个多维数组。


本章内容概要

  • 介绍仿射变换,学习使用仿射变换矩阵实现图像的仿射变换。
  • 学习使用函数实现图像的平移、缩放、旋转、翻转和斜切。
  • 介绍投影变换,学习使用投影变换矩阵实现图像的投影变换。
  • 介绍图像的重映射,学习使用映射函数实现图像的自定义变换和动态变换。

6.6 图像的投影变换

透视变换(Perspective Transformation)是OpenCV中常用的投影变换,是指将图像投影到一个新的视平面。投影变换的特点是原始图像中的平行关系和比例关系都可以改变,但图像中的直线在投影变换后仍然能保持直线。
投影变换可以通过对三维空间中的物体旋转进行校正,主要用于图像拼接和校正透视投影导致的图像失真。
投影变换的方法是在原始图像上确定不共线的4个点,给定这4个点在变换图像中的位置,就确定了一个投影变换,其变换关系可以由如下的3×3矩阵来描述。

[ x ~ y ~ z ~ ] = M P [ x y z ] , M P = [ M 11 M 12 M 13 M 21 M 22 M 23 M 31 M 32 M 33 ] \begin{bmatrix} \tilde{x}\\ \tilde{y}\\ \tilde{z} \end{bmatrix} = M_P \begin{bmatrix} x\\ y\\ z \end{bmatrix} ,\hspace{1em} M_P= \begin{bmatrix} M_{11} &M_{12} &M_{13}\\ M_{21} &M_{22} &M_{23}\\ M_{31} &M_{32} &M_{33} \end{bmatrix} x~y~z~ =MP xyz ,MP= M11M21M31M12M22M32M13M23M33

仿射变换是在二维平面进行变换的,而投影变换是在三维坐标系进行变换的。仿射变换是3点变换,投影变换是4点变换。比较仿射变换与投影变换的描述公式,仿射变换可以被视为z轴不变的透视变换。

在OpenCV中,先由函数cv.getPerspectiveTransform计算投影变换矩阵 M P M_P MP,再由函数cv.warpPerspective根据投影变换矩阵 M P M_P MP 计算得到投影变换图像。

函数cv.getPerspectiveTransform能根据图像中不共线的4个点在变换前后的对应位置坐标,求解得到投影变换矩阵 M P M_P MP


函数原型

cv.getPerspectiveTransform(src, dst[,solveMethod]) → MP

参数说明

  • src:原始图像中不共线4个点的坐标,是形状为(4,2)的Numpy数组。
  • dst:投影变换图像中对应的不共线4个点的坐标,是形状为(4,2)的Numpy数组。
  • solveMethod:矩阵分解方法。
    • DECOMP_LU:选择最佳轴的高斯消元法,默认方法。
    • DECOMP_SVD:奇异值分解(SVD)方法。
    • DECOMP_EIG:特征值分解方法,必须与src对称。
    • DECOMP_CHOLESKY:Cholesky LLT分解方法。
    • DECOMP_QR:正交三角(QR)分解方法。
    • DECOMP_NORMAL:使用正则方程,与前述方法联合使用。
  • MP:投影变换矩阵,是形状为(3,3)、类型为np.float32的Numpy数组。

注意问题

  • (1)虽然参数src、dst通常表示输入、输出图像,但在函数cv.getPerspectiveTransform中是指原始图像与变换图像中不共线的4个点,也被称为四边形的顶点。
  • (2) 参数src、dst是形状为(4,2)的Numpy数组,数值是图像中4个顶点的坐标(x,y)。

函数cv.warpPerspective可通过投影变换矩阵计算投影变换图像。

函数原型

cv.warpPerspective (src, M, dsize[, dst, flags, borderMode, borderValue]) → dst

由投影变换矩阵M计算投影变换图像的公式为

参数说明

  • src:原始图像,是Numpy数组。
  • dst:投影变换输出图像,类型与src相同,图像尺寸由参数dsize确定。
  • M:投影变换矩阵,是形状为(3,3)、类型为np.float32的Numpy数组。
  • dsize:输出图像大小,格式为元组(w,h)。
  • flags:插值方法与逆变换标志,可选项。
    • INTER_LINEAR:双线性插值,默认方法。
    • INTER_NEAREST:最近邻插值。
    • WARP_INVERSE_MAP:逆变换标志。
  • borderMode:边界扩充方法,可选项,默认为cv.BORDER_CONSTANT。
  • borderValue:边界填充值,可选项,默认值为0,表示黑色填充。

注意问题

  • (1) 输出图像大小dsize的格式为(w,h),与OpenCV中图像形状(h,w)的顺序相反。
  • (2) 通过函数cv.warpPerspective计算投影变换,投影变换矩阵M的形状为(3,3),数据类型必须是np.float32。
  • (3) 当flags设为WARP_INVERSE_MAP时,先由投影变换矩阵计算逆投影变换矩阵,再计算输入图像的逆投影变换图像。

【例程0606】基于投影变换实现图像校正

手机或相机拍摄的照片,通常都存在投影变形。本例程通过投影变换实现图像校正。

先用鼠标在图像中依次选取矩形的4个顶点,获取4个顶点的坐标,再根据长宽比计算4个顶点在投影变换后的坐标,进行投影变换,就可以实现图像校正。


# 【0606】基于投影变换实现图像校正
import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltdef onMouseAction(event, x, y, flags, param):  # 鼠标交互 (单击选点,右击完成)setpoint = (x, y)if event == cv.EVENT_LBUTTONDOWN:  # 单击pts.append(setpoint)  # 选中一个多边形顶点print("选择顶点 {}:{}".format(len(pts), setpoint))if __name__ == '__main__':img = cv.imread("../images/Fig0602.png")  # 读取彩色图像(BGR)imgCopy = img.copy()height, width = img.shape[:2]# 鼠标交互从输入图像选择 4 个顶点print("单击左键选择 4 个顶点 (左上-左下-右下-右上):")pts = []  # 初始化 ROI 顶点坐标集合status = True  # 进入绘图状态cv.namedWindow('origin')  # 创建图像显示窗口cv.setMouseCallback('origin', onMouseAction, status)  # 绑定回调函数while True:if len(pts) > 0:cv.circle(imgCopy, pts[-1], 5, (0,0,255), -1)  # 绘制最近的一个顶点if len(pts) > 1:cv.line(imgCopy, pts[-1], pts[-2], (255, 0, 0), 2)  # 绘制最近的一段线段if len(pts) == 4:  # 已有 4个顶点,结束绘制cv.line(imgCopy, pts[0], pts[-1], (255,0,0), 2)  # 绘制最后的一段线段cv.imshow('origin', imgCopy)cv.waitKey(1000)breakcv.imshow('origin', imgCopy)cv.waitKey(100)cv.destroyAllWindows()  # 释放图像窗口ptsSrc = np.array(pts)  # 列表转换为 (4,2),Numpy 数组print(ptsSrc)# 计算投影变换矩阵 MPptsSrc = np.float32(pts)  # 列表转换为Numpy数组,图像4个顶点坐标为 (x,y)x1, y1, x2, y2 = int(0.1*width), int(0.1*height), int(0.9*width), int(0.9*height)ptsDst = np.float32([[x1,y1], [x1,y2], [x2,y2], [x2,y1]])  # 投影变换后的 4 个顶点坐标MP = cv.getPerspectiveTransform(ptsSrc, ptsDst)# 投影变换dsize = (450, 400)  # 输出图像尺寸为 (w, h)perspect = cv.warpPerspective(img, MP, dsize, borderValue=(255,255,255))  # 投影变换print(img.shape, ptsSrc.shape, ptsDst.shape)plt.figure(figsize=(9, 3.4))plt.subplot(131), plt.axis('off'), plt.title("1.Original")plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))plt.subplot(132), plt.axis('off'), plt.title("2.Selected vertex")plt.imshow(cv.cvtColor(imgCopy, cv.COLOR_BGR2RGB))plt.subplot(133), plt.axis('off'), plt.title("3.Perspective correction")plt.imshow(cv.cvtColor(perspect, cv.COLOR_BGR2RGB))plt.tight_layout()plt.show()

程序说明:
(1) 本例程设置了回调函数,通过鼠标交互从输入图像选择了4个顶点。鼠标交互操作的使用方法详见4.9节。
(2) 投影变换后4个顶点的坐标是用户设定的,可以根据需要修改。
(3) 基于投影变换实现图像校正的运行结果如图6-6所示,图6-6(1)所示为原始图像,图6-6(2)所示为用鼠标在原始图像上选定棋盘的4个顶点,图6-6(3)所示为投影变换后的图像。可以看出,原始图像中透视拍照的倾斜棋盘被校正为矩形。


在这里插入图片描述

*图6-6 图像的投影变换


版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/134487182)
Copyright 2023 youcans, XUPT
Crated:2023-11-20

欢迎关注本书CSDN独家连载专栏
《数字图像处理-OpenCV/Python》连载: https://blog.csdn.net/youcans/category_12418787.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/196242.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

V100 GPU服务器安装GPU驱动教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

网络割接用VRRP替换HSRP

如图3-11所示,C6500作为核心层设备上行连接出口路由器NE40E-X3,下行连接接入层设备CE6800。C6500上配置HSRP实现冗余备份网关,同时在二层网络部署MSTP破除环路。 总体思路 HSRP为CISCO私有协议,CE系列交换机(以CE1280…

【汇编】[bx+idata]的寻址方式、SI和DI寄存器

文章目录 前言一、[bxidata]寻址方式1.1 [bxidata]的含义1.2 示例代码 二、SI和DI寄存器2.1 SI和DI寄存器是什么?2.2 [bxsi]和[bxdi]方式寻址2.3 [bxsiidata]和[bxdiidata] 总结 前言 在汇编语言中,寻址方式是指指令如何定位内存中的数据。BX寄存器与偏…

计算机网络——物理层-信道的极限容量(奈奎斯特公式、香农公式)

目录 介绍 奈氏准则 香农公式 介绍 信号在传输过程中,会受到各种因素的影响。 如图所示,这是一个数字信号。 当它通过实际的信道后,波形会产生失真;当失真不严重时,在输出端还可根据已失真的波形还原出发送的码元…

C#,数值计算——插值和外推,Laplace_interp的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Object for interpolating missing data in a matrix by solving Laplaces /// equation.Call constructor once, then solve one or more times /// </summary> …

计算两个向量的叉积numpy.cross()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算两个向量的叉积 numpy.cross() [太阳]选择题 请问代码中最后输出正确的是&#xff1f; import numpy as np a np.array([1, 2, 3]) b np.array([4, 5, 6]) c np.cross(a, b) pri…

iptables详解:常用模块的基本使用

目录 tcp扩展模块 multiport扩展模块 iprange扩展模块 connlimit模块 limit扩展模块 udp扩展模块 icmp扩展模块 state扩展模块 限制每分钟接收10个ICMP数据报文 允许10个数据报文快速通过&#xff0c;然后限制每分钟接收1个个ICMP数据报文 限制网络传输的带宽不可以…

【原创】WeChat Server搭建

功能 微信公众号的后端&#xff0c;为其他系统提供微信登录验证功能 源码地址 https://github.com/songquanpeng/wechat-server 创建MySQL数据库 宝塔\数据库\MySQL 添加数据库 数据库名&#xff1a;wechat_server 用户名&#xff1a;wechat_server 密码&#xff1a;fZNB…

【论文复现】QuestEval:《QuestEval: Summarization Asks for Fact-based Evaluation》

以下是复现论文《QuestEval: Summarization Asks for Fact-based Evaluation》&#xff08;NAACL 2021&#xff09;代码https://github.com/ThomasScialom/QuestEval/的流程记录&#xff1a; 在服务器上conda创建虚拟环境questeval&#xff08;python版本于readme保持一致&…

quinn源码解析:QUIC数据包是如何发送的

quinn源码解析&#xff1a;QUIC数据包是如何发送的 简介QUIC协议中的概念endpoint&#xff08;端点&#xff09;connection&#xff08;连接&#xff09;Stream&#xff08;流&#xff09;Frame (帧) 发包过程解析SendStream::write_allConnectionDriverEndpointDriver 简介 q…

拷贝对象时编译器的一些优化

在传参和传值返回的过程中&#xff0c;编译器会通过一些优化减少拷贝的次数。 class A { public:A():_a(1){cout << "A()" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator(const …

项目自动化构建工具——make/Makefile

目录 一、概念 二、使用实例 三、原理 四、进度条程序 1、缓冲区问题 1、概念 2、\r和\n 2、代码编写 一、概念 一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先…