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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

理解静态库、动态库加载

个人主页:Lei宝啊 愿所有美好如期而遇 系统角度理解 我们先来谈谈进程地址空间,当我们将一个可执行程序跑起来的时候,操作系统首先会在内存中创建出task_struct,也就是进程控制块,然后将可执行程序的代码和数据加载…

整数和浮点数在内存中存储

整数在内存中的存储 整数的2进制表⽰⽅法有三种,即原码、反码和补码。 对于整形来说,数据存放内存中的其实是补码。 在计算机系统中,数值一律用补码来表示和存储。原因是,使用补码,可以使符号位和数值域统一处理&am…

ARMday7

VID_20240322_203313 1.思维导图 2.main.c #include"key_inc.h" //封装延时函数 void delay(int ms) {int i,j;for(i0;i<ms;i){for(j0;j<2000;j){}} } int main() {//按键中断的初始化key1_it_config();key2_it_config();key3_it_config();while(1){printf(&q…

备战蓝桥杯Day34 - 每日一题

题目描述 解题思路 1.输入数据n&#xff0c;并将字符串类型转换成整数类型 2.求出输入n是2的几次幂&#xff08;调用math库中的求对数的方法&#xff09;&#xff0c;在下面的循环中要用到 3.定义sum和&#xff0c;将抽取到的牌的总数加起来存储 4.count 0 # 记录 2 的第几…

台达变频通过Modbus转Profinet网关可以在环网冗余中使用

Modbus转Profinet网关&#xff08;如XD-MDPN100&#xff09;是一种能够实现Modbus协议与Profinet协议之间转换的设备。它支持Modbus RTU协议和Profinet协议还支持MRP环网冗余系统&#xff0c;,可以通过配置软件进行协议转换&#xff0c;使得原本只能使用Modbus协议的设备可以与…

微服务day05(中) -- ES索引库操作

索引库就类似数据库表&#xff0c;mapping映射就类似表的结构。 我们要向es中存储数据&#xff0c;必须先创建“库”和“表”。 2.1.mapping映射属性 mapping是对索引库中文档的约束&#xff0c;常见的mapping属性包括&#xff1a; type&#xff1a;字段数据类型&#xff0c;…

中兴通讯服务器荣获滴滴“最佳需求响应「和衷共济」奖”

在数字经济加速发展的背景下&#xff0c;算力成为数字产业的核心支撑力量&#xff0c;而服务器和存储产品更是为互联网创新体验提供了底层基础设施保障。在此背景下&#xff0c;中兴通讯服务器产品有效支撑滴滴出行智慧交通解决方案&#xff0c;凭借卓越表现&#xff0c;获得滴…

QGraphicsView的使用,view坐标,scene坐标,item坐标

Graphics View绘图构架 QGraphicsScene&#xff08;场景&#xff09;&#xff1a;可以管理多个图形项QGraphicsItem&#xff08;图形项&#xff09;&#xff1a;也就是图元&#xff0c;支持鼠标事件响应。QGraphicsView&#xff08;视图&#xff09;&#xff1a;关联场景可以让…

基于python+vue学生作业管理系统flask-django-nodejs-php

快速发展的社会中&#xff0c;人们的生活水平都在提高&#xff0c;生活节奏也在逐渐加快。为了节省时间和提高工作效率&#xff0c;越来越多的人选择利用互联网进行线上打理各种事务&#xff0c;然后线上管理系统也就相继涌现。与此同时&#xff0c;人们开始接受方便的生活方式…

IDEA/Android Studio格式化代码快捷键失效的解决

问题描述 用AS写一个项目的时候&#xff0c;发现CtrlAltL的格式化快捷键并不生效&#xff0c;按下之后没有任何反应。而格式化文件快捷键CtrlAltShiftL依旧生效&#xff0c;难道是设置出了问题&#xff1f; 打开设置页面发现快捷键设置很正确&#xff0c;并没问题&#xff0c…

掌握C语言结构体,开启编程新世界

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 前言 前面我们也涉及到了结构体的讲解&#xff0c;但是只是粗略的讲了一下。 接下…

力扣hot100题解(python版91-95题)

91、不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&…

java分割等和子集(力扣Leetcode416)

分割等和子集 力扣原题链接 给你一个只包含正整数的非空数组nums。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5, 5] …

【深度学习基础知识】IOU、GIOU、DIOU、CIOU

这里简单记录下IOU及其衍生公式。   为了拉通IOU及其衍生版的公式对比&#xff0c;以及方便记忆&#xff0c;这里用一个统一的图示来表示出所有的参数 【&#xff21;】目标框的区域【&#xff22;】预测框的区域【&#xff23;】&#xff21;与&#xff22;的交集【&#xff…

关于TEMU 亚马逊美国哺乳枕(Nursing Pillow)法规16 CFR 1242介绍

美国首个哺乳枕法规16 CFR 1242发布 美国消费品安全委员会CPSC于2023年9月26日在联邦公报上发布了哺乳枕新法规16 CFR 1242的草案&#xff0c;旨在降低哺乳枕使用带来的伤害和死亡风险。该法规草案提到了在使用哺乳枕时由于婴儿睡着或无人看护而导致的窒息、陷落和跌落风险。在…

2024:RAG年

如果 2023 年都是关于 ChatGPT 和 Llama-2 等基础LLM&#xff0c;那么我的预测是 2024 年将是关于检索增强一代&#xff08;RAG&#xff09;的。 在这篇博文中&#xff0c;我阐述了为什么 RAG 将在 2024 年飞速发展&#xff0c;不仅是企业采用率&#xff0c;而且消费者采用率也…

BigDecimal类的使用,用于精确计算任意精度的数字

BigDecimal类 BigDecimal 是 Java 中用于精确表示任意精度的十进制数的类。在很多情况下,使用基本数据类型(如 double 或 float)进行浮点数计算可能会导致精度丢失或舍入错误。BigDecimal 提供了一种更精确的解决方案,可以处理需要高精度计算的场景,比如财务应用或科学计算…

记录解决问题--activiti8.2 流程图图片由png改为svg前端不显示图片问题

1.说明 如果是vue svg显示&#xff0c;请查阅其他标准资料&#xff0c;类似使用svg标签。我这里讲的另外一种情况&#xff0c;链接返回的是svg文件&#xff0c;需要用v-html显示图片。 2.activiti6流程图图片格式 ①png格式。可以查看链接返回&#xff0c;以png开头。 ②前端…

蓝桥杯练习——神秘咒语——axios

目标 完善 index.js 中的 TODO 部分&#xff0c;通过新增或者修改代码&#xff0c;完成以下目标&#xff1a; 点击钥匙 1 和钥匙 2 按钮时会通过 axios 发送请求&#xff0c;在发送请求时需要在请求头中添加 Authorization 字段携带 token&#xff0c;token 的值为 2b58f9a8-…

适合新生儿的奶瓶有哪些?五款高分新生儿奶瓶分享!

每一个有新生儿的家庭都一定会挑选奶瓶&#xff0c;但是因为市面有太多品牌和款式&#xff0c;让大家难以挑选&#xff0c;更为重要的是还有可能会不小心选到劣质的产品&#xff0c;不仅奶嘴的仿真度差、易胀气&#xff0c;还可能高温消毒后散发有害物质&#xff01;那么新生儿…