图像几何变换(仿射变换和透视变换...)及python-opencv实现

本文主要是介绍图像几何变换(仿射变换和透视变换...)及python-opencv实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 图像变换类型
    • 仿射变换
    • 透视变换
    • python-opencv实现
    • 参考文献

图像变换类型

图像几何变换主要包括以下几种类型:

  1. 平移(Translation):将图像在水平或垂直方向上移动,不改变图像的尺寸和形状。
  2. 缩放(Scaling):改变图像的大小,可以是均匀缩放,即保持图像的长宽比,或者是非均匀缩放,即在水平和垂直方向上使用不同的缩放因子。
  3. 旋转(Rotation):将图像绕某一点(通常是图像中心)旋转一定角度,旋转后的图像位置会发生变化。
  4. 镜像(Mirroring):也称为翻转,可以是水平镜像或垂直镜像,即将图像沿水平轴或垂直轴翻转。
  5. 仿射变换(AffineTransformation):包括平移、缩放、旋转和错切等线性变换,保持直线和平行线的性质不变。
  6. 透视变换(PerspectiveTransformation):也称为投影变换,它涉及到三维空间中的点到二维平面的映射,可以模拟三维空间中物体的透视效果。

其中,又可以将其分为两大类:仿射变换透视变换。透视变换的作用域是一个三维坐标系(x,y,z), 而仿射变换则是二维(x,y)平面变换。从另一个角度来说,仿射变换也可以看做是一种特殊的透视变换(z轴方向不变)。
透视变换和仿射变换的一个重要区别是:两条平行的线在经过仿射变换之后依然保持平行,但透视变换并不保证这一点。

仿射变换

为了统一将所有的仿射变换都用一种方式表达出来,引入了齐次坐标,这样就能够将平移变换和线性变换表示在一个矩阵中了。如下所示:
在这里插入图片描述
对于单个仿射变换,其矩阵表示如下:
在这里插入图片描述

透视变换

透视变换(Perspective Transformation)是将二维的图片投影到一个三维视平面上,然后再转换到二维坐标下,所以也称为投影映射(Projective Mapping)。简单来说就是二维→三维→二维的一个过程。
在这里插入图片描述

透视变换的矩阵表示如下,我们可以看到它与仿射变换的区别便是最后一行的参数c1和c2的值,对于仿射变换c1=c2=0。
在这里插入图片描述
在这里插入图片描述
通过透视变换的变换矩阵计算新的坐标,其中a33=1,x’和y’为最终计算的结果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
至此,已经知道了仿射变换和透视变换的变换矩阵,那在实际应用时该如何求呢?一个方法是直接根据几何参数计算变换矩阵,另外一个方法是通过原始图像坐标和目标图像坐标求解变换矩阵。通常情况下,更多选择是后者的计算方法。

对于仿射变换,只有6个参数,因此只需要3个点对就可以求解了;而透视变换,则需要8个参数,需要4个点对才能够求解。如下所示为透视变换矩阵的8个方程组。
在这里插入图片描述

python-opencv实现

图像几何变换在计算机视觉和图像处理中有着广泛的应用,如图像配准、目标识别、图像校正等。在实际应用中,这些变换通常通过变换矩阵来实现,可以通过OpenCV等图像处理库来进行操作。
在这里插入图片描述
这是用chatgpt写的代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图像
image = cv2.imread('../images/girl1.jpg')# 平移变换
rows, cols = image.shape[:2]
M_translation = np.float32([[1, 0, 50], [0, 1, 100]])  # 水平移动50像素,垂直移动100像素
translated_image = cv2.warpAffine(image, M_translation, (cols, rows))# 缩放变换
scale_factor = 0.5  # 缩小为原来的一半
resized_image = cv2.resize(image, None, fx=scale_factor, fy=scale_factor)# 旋转变换
center = (cols // 2, rows // 2)
angle = 45  # 旋转角度为45度
M_rotation = cv2.getRotationMatrix2D(center, angle, 1)
rotated_image = cv2.warpAffine(image, M_rotation, (cols, rows))# 镜像变换(水平镜像)
flipped_image = cv2.flip(image, 1)  # 参数1表示水平镜像,参数0表示垂直镜像# 仿射变换
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])
M_affine = cv2.getAffineTransform(pts1, pts2)
affined_image = cv2.warpAffine(image, M_affine, (cols, rows))# 透视变换
pts3 = np.float32([[0, 65], [368, 52], [28, 387], [389, 390]])
pts4 = np.float32([[0, 0], [200, 0], [60, 300], [500, 300]])
M_perspective = cv2.getPerspectiveTransform(pts3, pts4)
perspective_image = cv2.warpPerspective(image, M_perspective, (cols, rows))# 错切变换
M_shearing = np.float32([[1, 0.2, 0], [0.2, 1, 0]])
sheared_image = cv2.warpAffine(image, M_shearing, (cols, rows))# 转置变换
transposed_image = cv2.transpose(image)# 显示结果图像
plt.figure()
plt.subplot(331)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Original Image')plt.subplot(332)
plt.imshow(cv2.cvtColor(translated_image, cv2.COLOR_BGR2RGB))
plt.title('Translated Image')plt.subplot(333)
plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
plt.title('Resized Image')plt.subplot(334)
plt.imshow(cv2.cvtColor(rotated_image, cv2.COLOR_BGR2RGB))
plt.title('Rotated Image')plt.subplot(335)
plt.imshow(cv2.cvtColor(flipped_image, cv2.COLOR_BGR2RGB))
plt.title('Flipped Image')plt.subplot(336)
plt.imshow(cv2.cvtColor(affined_image, cv2.COLOR_BGR2RGB))
plt.title('Affine Image')plt.subplot(337)
plt.imshow(cv2.cvtColor(perspective_image, cv2.COLOR_BGR2RGB))
plt.title('Perspective Image')plt.subplot(338)
plt.imshow(cv2.cvtColor(sheared_image, cv2.COLOR_BGR2RGB))
plt.title('Sheared Image')plt.subplot(339)
plt.imshow(cv2.cvtColor(transposed_image, cv2.COLOR_BGR2RGB))
plt.title('Transposed Image')plt.show()

参考文献

[1] 仿射变换(Affine Transformation)在2D和3D坐标下的变换矩阵
[2] (十四)透视变换
[3] 算法笔记 : 透视变换(透射变换)
[4] 仿射变换和透视变换矩阵的参数含义与区别

这篇关于图像几何变换(仿射变换和透视变换...)及python-opencv实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/836681

相关文章

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Python安装时常见报错以及解决方案

《Python安装时常见报错以及解决方案》:本文主要介绍在安装Python、配置环境变量、使用pip以及运行Python脚本时常见的错误及其解决方案,文中介绍的非常详细,需要的朋友可以参考下... 目录一、安装 python 时常见报错及解决方案(一)安装包下载失败(二)权限不足二、配置环境变量时常见报错及

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J

SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤

《SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤》本文主要介绍了SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤,文中通过示例代码介绍的非常详... 目录 目标 步骤 1:确保 ProxySQL 和 mysql 主从同步已正确配置ProxySQL 的

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点: