图像几何变换(仿射变换和透视变换...)及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] 仿射变换和透视变换矩阵的参数含义与区别

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

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

相关文章

[Java、Android面试]_10_Java中==与equal()方法的区别?重写equal()方法?

与equal()方法的区别?是一个高频考点,资料整理如下: 文章目录 1. ""的介绍2. .equal的介绍 本人今年参加了很多面试,也有幸拿到了一些大厂的offer,整理了众多面试资料,后续还会分享众多面试资料…

Java并发

目录 线程 什么是线程 进程和线程的区别 线程的生命周期 什么是多线程 并发与并行 多线程的三种实现方式 继承Thread类 1.创建类继承Thread类 2.重写run()方法 3.创建对象启动线程 实现Runnable接口 1.自己定义一个类实现Runnable接口 2.重…

程序猿成长之路之番外篇——矩阵算法

今天在复习线性代数知识的过程中,用java语言简单实现了一下矩阵算法。 数学知识回顾 1.什么是矩阵 在数学领域,矩阵就像一个表格,将数据排放进去,形成一个矩形。我们习惯用一个大括号把矩阵内的数据包括进来。 1.矩阵 在数学领域…

FeignClient是否可以配置多个拦截器?

1、做法 在Spring Cloud中,FeignClient是一个声明式的Web服务客户端,让调用远程服务就像调用本地方法一样简单。拦截器可以用于在发送请求之前或者获得响应之后执行一些操作,比如添加公共的Header、记录日志、做一些统计等。 在Feign中&…

Python Web开发记录 Day14:Django part8 订单管理

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 1、数据库准备2、添加订单3、订单列表4、删除订单5、编辑订单6、补充解答1、数据库准备 1.修改models.py,添加Order订单表 models.py class O…

JavaScript parseInt() 函数

JavaScript parseInt() 函数 从官方理解: parseInt() 函数解析字符串并返回整数。 radix 参数用于指定使用哪种数字系统,例如基数为 16(十六进制)表示字符串中的数字应从十六进制数解析为十进制数。 如果 radix 参数被省略&…

【HTML面试题】src和href的区别

一、请求资源不同 src 在请求资源时,会把这个资源下载下来href 建立链接通道,也就是引用元素和当前文档建立链接 二、作用结果不同 src 会替换当前元素href 只是引用资源和当前元素建立链接,所以不会替换当前内容。 三、浏览器解析方式不…

3.21作业

#include<myhead.h> int do_add(sqlite3 *ppDb) { int xue0; char name[20]""; double coure0; char sql[128]""; printf("请输入学号\n"); scanf("%d",&xue); printf("请输入姓名\n&qu…

Java SE

java概述 1.什么是java java是一门面向对象的编程语言&#xff0c;作为静态面向对象编程语言&#xff0c;极好地实现了面向对象理论&#xff0c;允许程序员以优雅的思维方式进行复杂的编程 。 2.java语言有哪些特点&#xff1f; 2.1面向对象&#xff08;继承封装多多态&…

SOCKS5是什么?

SOCKS5是什么&#xff1f; SOCKS5&#xff0c;作为SOCKS网络协议家族的最新版本&#xff0c;是一种高级的网络协议&#xff0c;用于在客户端和服务器之间通过一个代理服务器交换网络包。它的设计考虑了多种网络环境&#xff0c;包括对IPv6和UDP协议的支持&#xff0c;并引入了…

Uscrapper:一款功能强大的网络资源爬取工具

关于Uscrapper Uscrapper是一款功能强大的网络资源爬取工具&#xff0c;该工具可以帮助广大研究人员从各种网络资源中轻松高效地提取出有价值的数据&#xff0c;并且提供了稳定、友好且易于使用的UI界面&#xff0c;是安全研究人员和网络分析人员的强有力工具。 Uscrapper最大…

漫谈5种注册中心

01 注册中心基本概念 1.1 什么是注册中心&#xff1f; 注册中心主要有三种角色&#xff1a; 服务提供者&#xff08;RPC Server&#xff09;&#xff1a;在启动时&#xff0c;向 Registry 注册自身服务&#xff0c;并向 Registry 定期发送心跳汇报存活状态。 服务消费者&…

哈希、散列表和Rabin-Karp算法

字典 现有一个抽象数据类型(ADT)如下&#xff1a; 包括了一组元素&#xff0c;每个元素都有一个键key。假设没有元素拥有相同的key&#xff0c;如果有相同的key&#xff0c;则覆盖掉原有key的元素。 -insert(item) -delete(item) -search(key):根据给定的key&#xff0c;返…

JetBrains全家桶激活,分享 GoLand 2024 激活的方案

大家好&#xff0c;欢迎来到金榜探云手&#xff01; GoLand 公司简介 JetBrains 是一家专注于开发工具的软件公司&#xff0c;总部位于捷克。他们以提供强大的集成开发环境&#xff08;IDE&#xff09;而闻名&#xff0c;如 IntelliJ IDEA、PyCharm、和 GoLand等。这些工具被…

第4周 Python程序流程控制刷题(循环结构)

单击题目&#xff0c;直接跳转到页面刷题&#xff0c;一周后公布答案。 P5722&#xff1a;数列求和B2054&#xff1a;求平均年龄B2059&#xff1a;奇数求和B2064&#xff1a;斐波那契数列B2077&#xff1a;角谷猜想B2098&#xff1a;整数去重B2128&#xff1a;素数个数 1. P5…

力扣每日练习(3.20)补

322. 零钱兑换 想象你有一堆不同面值的硬币&#xff0c;现在的任务是用这些硬币凑出一个指定的金额&#xff0c;比如说11元&#xff0c;而且要求用的硬币数量尽可能少。 准备工作&#xff1a;首先&#xff0c;我们做了一张表&#xff08;叫dp&#xff09;&#xff0c;这张表记…

前端开发的第三方库

base64.js 地址&#xff1a;https://github.com/dankogai/js-base64 Base64.js 库提供了一个简单的 API&#xff0c;用于将数据转换为 Base64 编码&#xff0c;以及将 Base64 编码的数据解码回原始数据 Base64.js 是一个 JavaScript 库&#xff0c;用于将数据转换为 Base64 编…

LVGL:拓展部件——键盘 lv_keyboard

一、概述 此控件特点&#xff1a; 特殊Button矩阵&#xff1a;lv_keyboard 本质上是一个经过定制的按钮矩阵控件。每个按钮都可以独立触发事件或响应。预定义的键映射&#xff1a;lv_keyboard 自带了一套预设的按键布局和对应的字符映射表&#xff0c;开发者可以根据需要选择…

Vue 性能不给力?这些优化技巧帮你轻松搞定!

结合lighthouse查看各项数据&#xff0c;不断进行性能优化&#xff0c;可以从代码、项目打包、项目部署这三个层面来优化 代码层面 1、v-if和v-show区分使用 v-if&#xff08;惰性的&#xff09;用的条件判断&#xff0c;是惰性的&#xff0c;false的话初始不会渲染&#xf…

oracle迁移至gbase,sql问题总结(完善中)

最近再做国产化适配&#xff0c;需要把oracle里面的数据迁移至gbase 8a库中&#xff0c;这边把迁移过程中遇到的sql问题&#xff0c;记录下&#xff0c;现在仅迁移了一部分&#xff0c;后续会继续完善 1.ORACLE里面的NVL2函数在8a中不支持&#xff0c;可换成DECODE函数 2.表别…