当前位置: 首页 > news >正文

python图像处理实战(三)—图像几何变换

🚀写在前面🚀

🖊个人主页:https://blog.csdn.net/m0_52051577?type=blog 

🎁欢迎各位大佬支持点赞收藏,三连必回!!

🔈本人新开系列专栏—python图像处理

❀愿每一个骤雨初晴之时,所有的蜻蜓振翅和雨后惊雷,都归你。

前言

      图像几何变换就是在不改变图像像素值的前提下,对图像进行像素变换的处理。通常几何变换可以用来解决由成像的角度、透视位置不合预期等问题。比如拍摄的斜着的路牌,如果我们在只能对现有的照片进行处理的情况下又想要从侧面看到路牌上的字体,那么此时就要用到几何变换。

      几何变换作为图像归一化的核心工作之一,对图像的预处理起到了重要作用。 

目录

一、所需函数及基础变换的插值方法

1.所需函数

2.常见插值方法

3.最近邻插值

4.最近邻和双线性插值比较

二、图像操作

1.裁剪图像 (放大缩小)

         2.平移变换 

         3.错切变换 

         4.镜像变换

4.1方式一

4.2方式二

          5.旋转变换 

5.1方式一

5.2方式二

5.3设置不同缩放因子时的旋转效果

 6.放大缩小

 7.透视变换


 注:本文涉及到的图片资源可在博客积分资源中获取,相关链接:https://download.csdn.net/download/m0_52051577/87844285?spm=1001.2014.3001.5503 

一、所需函数及基础变换的插值方法

1.所需函数

cv.resize(src, dsize,dst=None,fx=None, fy=None, interpolation=None)

功能:用来放大及缩小图像的函数。

参数:[输入图像,修改尺寸,输出图像,x方向缩放系数,Y 方向缩放系数,插值方式]


M = np.array([[...]], dtype=np.float32)
cv.warpAffine(img, M, dsize)

功能:对图像进行平移变换。

参数:M表示构造的变换矩阵,warpAffine()函数中img表示变换的图像,M表示变换矩阵,dsize设置修改尺寸。


cv.flip(img,bool)

功能:对图像进行镜像变换。

参数:其中img表示变换的图像,flip()函数中bool为布尔值,可选0或1,0表示垂直镜像;1表示水平镜像;-1表示水平垂直同时进行。


M = cv.getRotationMatrix2D(center, angle, scale)

功能:对图像进行旋转变换(角度可定义)

参数:

getRotationMatrix2D()函数中center 表示旋转图像所要围绕的中心点。

angle 表示旋转的角度. 在OpenCV中正角度是逆时针的。

scale 表示缩放因子,可选的。


img_rotate = cv.rotate(img, cv.ROTATE_90_CLOCKWISE)

功能:对图像进行旋转变换(90°)

参数:rotate()旋转函数,将图像旋转90°。


M = cv.getPerspectiveTransform(src, dst)

功能:求得图像透视变换的变换矩阵。

参数:cv2.getPerspectiveTransform()函数根据图像中不共线的 4 个点在变换前后的对应位置求得 (3x3) 变换矩阵。


img = cv.warpPerspective(img, M, dsize)

功能:对图像进行透视变换。

参数:cv2.warpPerspective 使用该 (3x3) 变换矩阵即可求出变换后的图像。标量进行加法运算。 


2.常见插值方法

在做图像处理时,经常会碰到小数像素坐标的取值问题,这就需要一种插值算法来对坐标进行插值。常见的四种插值方法如下:

最近邻插值: interpolation = cv.INTER_NEAREST

放大图片:interpolation = cv.INTER_CUBIC(速度慢)

                  interpolation = cv.INTER_LINEAR  线性插值(速度快)

缩小图片:interpolation = cv.INTER_AREA


3.最近邻插值

将原本10X10的图像放大成15X15,放大1.5倍。

比如要计算新图像在(10,11)处的灰度值,则对应原图像(10/1.5,11/1.5)= (6.7,7.3)处的灰度值,四舍五入取整,选取原图像(7,7)处的灰度值即可。如下图:


4.最近邻和双线性插值比较

##### 最近邻和双线性插值比较
import cv2 as cv
import numpy as np
import matplotlib.pyplot as pltdef show(img):plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB), cmap='gray', vmin=0, vmax=255)plt.show()img = cv.imread('pic/rabbit50x33.jpg')
img_resize1 = cv.resize(img, (330, 500), interpolation=cv.INTER_NEAREST)
img_resize2 = cv.resize(img, (330, 500), interpolation=cv.INTER_LINEAR)show(img)
show(np.hstack([img_resize1, img_resize2]))

 

最左图为模糊处理后的图像,中间图为最近邻处理的效果图,最右图为双插值处理的效果图,可见同样图片尺寸下,双插值处理效果更清晰。


二、图像操作

首先,定义导入图片的函数。

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def show(img):if img.ndim == 2:plt.imshow(img, cmap='gray', vmin=0, vmax=255)else:img = cv.cvtColor(img, cv.COLOR_BGR2RGB)plt.imshow(img)plt.show()

1.裁剪图像 (放大缩小)

img = cv.imread('pic/rabbit500x333.jpg')
show(img)
img.shape  #查看图像维度

 如图,原图的维度为(500,333,3),下面将图像裁剪。

# 裁剪
rabbit = img[150:450, 50:300, :]
show(rabbit)

 

如图,裁剪后的维度中,150:450表示纵轴上裁剪的长度,50:300表示横轴上裁剪的长度。 


 2.平移变换 

平移变换的原理为,在原有像素点的基础上指定x方向与y方向的偏移量▲x与▲y,将原有的像素坐标(x0,y0)进行处理,平移后的坐标为(x,y);并将方程写成原向量与偏移向量相加的形式。同时原向量还可写成[[1,0],[0,1]]向量组与[x0,y0]相乘的形式,随后再偏移向量填补,写成3阶矩阵3维向量相乘的形式,从而实现平移变换

# 平移
transM = np.array([[1, 0, 20],[0, 1, 100]
], dtype=np.float32)img_trans = cv.warpAffine(img, transM, dsize=(333, 500))
show(img_trans)

 

如图,首先构造平移矩阵transM, 分别指定x与y方向上的平移量,用图像中每个像素点对应的矩阵点乘平移矩阵transM,从而实现图像的平移变换。其中dsize是设置平移图像的尺寸。


3.错切变换 

错切变换实现原理:令x=x0+y0tanθ,y=y0。按上图公式进行变换,y0tanθ为x在水平方向上的错切量,纵轴位置不变,从而实现水平方向的错切变换。

# 错切
shearM = np.array([[1, 0.3, 0],[0, 1,   0]
], dtype=np.float32)img_shear = cv.warpAffine(img, shearM, dsize=(400, 500))show(img_shear)

 

如图,错切变换后的图像是由矩阵错切变换公式得来的,公式中tanα表示横坐标错切比例,横坐标错切量dx=原像素点纵坐标y0×错切所占比例tanα。同理,tanβ表示纵坐标错切比例,纵坐标错切量dy=原像素点纵坐标x0×错切所占比例tanβ。以这样的方式得到的图像即为错切变换图像。 


4.镜像变换

 镜像变换原理:本质是将水平或竖直方向的坐标对称过去。

4.1方式一

# 镜像1
mirrorM = np.array([[-1, 0, 333],[0,  1, 0]
], dtype=np.float32)img_mirr = cv.warpAffine(img, mirrorM, dsize=img.shape[:2][::-1])
show(img_mirr)

 

如图,mirrorM中,x方向向量的首位元素为-1,表示将原图横向翻转,纵轴不变。 

 4.2方式二

# 镜像2
img_mirh = cv.flip(img, 1)
img_mirv = cv.flip(img, 0)
img_mirb = cv.flip(img, -1)
show(np.hstack([img, img_mirh, img_mirv, img_mirb]))

 

如图,采用flip()函数进行镜像翻转,其中1表示水平翻转,0表示竖直翻转,-1表示水平竖直同时进行。


5.旋转变换 

 旋转变换原理:首先定义旋转矩阵,再将原图像对应向量×矩阵中每个行向量分量。

 

旋转矩阵推导过程如上图,定义旋转半径r,旋转角α和β,其中(x0,y0)根据三角公式可以用r和α表示出来。

那么同理,要想将(x0,y0)变换到新坐标(x,y),同样用r和旋转角来表示,此时的旋转角为α-β,表示出新坐标(x,y)后,再用rcosαrsinα替换掉x0,y0。并将方程组写成矩阵相乘的形式,即为旋转矩阵。

5.1方式一

# 旋转1
img_rotate = cv.rotate(img, cv.ROTATE_90_CLOCKWISE)
show(img_rotate)

采用rotate()函数将图像顺时针旋转90°。

5.2方式二

# 旋转2
rotateM = cv.getRotationMatrix2D((80, 100), 45, 1)
img_rotate = cv.warpAffine(img, rotateM, dsize=(500, 500))
show(img_rotate)

 

采用getRotationMatrix2D()函数,定义旋转图像所要围绕的中心点(80,100),定义旋转的角度为45°,定义缩放因子为1。进行旋转变换,并调整尺寸为(500,500)。

5.3设置不同缩放因子时的旋转效果

# 旋转scale
rotateM1 = cv.getRotationMatrix2D((80, 100), 45, 0.8)
rotateM2 = cv.getRotationMatrix2D((80, 100), 45, 1)
rotateM3 = cv.getRotationMatrix2D((80, 100), 45, 1.2)img_rotate1 = cv.warpAffine(img, rotateM1, dsize=(700, 300))
img_rotate2 = cv.warpAffine(img, rotateM2, dsize=(700, 300))
img_rotate3 = cv.warpAffine(img, rotateM3, dsize=(700, 300))show(np.hstack([img_rotate1, img_rotate2, img_rotate3]))

 

如图,缩放因子越大,图像显示越大。 


 6.放大缩小

# 放大、缩小
img_resize = cv.resize(img, (300, 200))
show(img_resize)

 

采用 resize()函数对尺寸进行重新定义,设置尺寸为(300,200)。


 7.透视变换

透视变换原理:选取图像中四点的坐标(一般四点呈现平行四边形,根据图像位置来判定选取),再另外选择四点坐标(一般为矩形,根据自己想要呈现的效果来选取),分为两种矩阵srcdst,其中src为变换前选取的坐标矩阵,dst为想要变换的坐标矩阵。并采用getPerspectiveTransform()函数构造计算后的变换矩阵。并用warpPerspective()函数进行透视变换。如今,透视变换主要用于车道检测和图片矫正。

import cv2 as cv
img = cv.imread('pic/parthenon500x750.jpg')
show(img)
src = np.array([[210, 50],[610, 270],[650, 480],[150, 450]
], dtype=np.float32)dst = np.array([[150, 50],[650, 50],[650, 480],[150, 480]
], dtype=np.float32)M = cv.getPerspectiveTransform(src, dst)img2 = cv.warpPerspective(img, M, dsize=(750, 500))
show(img2)

 构造的变换矩阵M为:

array([[ 2.71437487e-01,  1.50299394e-01,  5.07376979e+01],[-6.40928318e-01,  1.08051969e+00,  1.18987142e+02],[-1.23293942e-03,  5.45617563e-04,  1.00000000e+00]])

 

 如图,左边为原图,右边为透视变换后的效果。

🚗 创作不易,期待大佬们的三连支持!🚗

相关文章:

python图像处理实战(三)—图像几何变换

🚀写在前面🚀 🖊个人主页:https://blog.csdn.net/m0_52051577?typeblog 🎁欢迎各位大佬支持点赞收藏,三连必回!! 🔈本人新开系列专栏—python图像处理 ❀愿每一个骤雨初…...

学习vue2笔记

学习vue2笔记 文章目录 学习vue2笔记脚手架文件结构关于不同版本的Vuevue.config.js配置文件ref属性props配置项mixin(混入)插件scoped样式总结TodoList案例webStorage组件的自定义事件全局事件总线(GlobalEventBus)消息订阅与发布(pubsub&am…...

【SQL】查找多个表中相同的字段

--查找字段所在 SELECTbb.TABLE_NAME,bb.COLUMN_NAME ,aa.COLUMN_ID,aa.DATA_TYPE,aa.DATA_LENGTH ,bb.COMMENTS FROMuser_tab_cols aa JOIN user_col_comments bb ONaa.TABLE_NAME bb.TABLE_NAMEAND aa.COLUMN_NAME bb.COLUMN_NAME JOIN dba_objects cc ONbb.TABLE_NAME cc…...

“未来之光:揭秘创新科技下的挂灯魅力“

写在前面: 高度信息化当下时代,对电脑及数字设备的需求与日俱增无处不在,随之而来的视觉疲劳和眼睛问题也攀升到了前所未有的高度。传统台灯对于长时间使用电脑的人群来说是完全无法解决这些问题的。一款ScreenBar Halo 屏幕挂灯,…...

Spring boot MongoDB实现自增序列

在某些特定的业务场景下,会需要使用自增的序列来维护数据,目前项目中因为使用MongoDB,顾记录一下如何使用MongoDB实现自增序列。 MongoDB自增序列原理 MongoDB本身不具有自增序列的功能,但是MongoDB的$inc操作是具有原子性的&…...

MyBatis查询数据库【秘籍宝典】

0.MyBatis执行流程1.第一个MyBatis查询1.创建数据库和表1.2.添加MyBatis框架依赖【新项目】1.3.添加MyBatis框架依赖【旧项目】1.4.配置连接数据库1.5.配置MyBatis的XML路径2.MyBatis模式开发2.1 添加MyBatis的xml配置 3.增查改删(CRUD)5.1.增加操作5.2.…...

目标检测舰船数据集整合

PS:大家如果有想要的数据集可以私信我,如果我下载了的话,可以发给你们~ 一、光学数据集 1、 DIOR 数据集(已下载yolo版本)(论文中提到过) DIOR由23463张最优遥感图像和190288个目标实例组成,这些目标实例用…...

第一章 Android 基础--开发环境搭建

文章目录 1.Android 发展历程2.Android 开发机器配置要求3.Android Studio与SDK下载安装4.创建工程与创建模拟器5.观察App运行日志6.环境安装可能会遇到的问题7.练习题 本专栏主要在B站学习视频: B站Android视频链接 本视频范围:P1—P8 1.Android 发展历…...

【LeetCode周赛】2022上半年题目精选集——二分

文章目录 2141. 同时运行 N 台电脑的最长时间解法1——二分答案补充:求一个int数组的和,但数组和会超int 解法2——贪心解法 2251. 花期内花的数目解法1——二分答案代码1——朴素二分写法代码2——精简二分⭐ 解法2——差分⭐⭐⭐ 2258. 逃离火灾解法1—…...

vuejs如何将线上PDF转为base64编码

只需要两个方法-下载与转换: 下载方法: demoDownloadPDF(url) {// if (!(/^https?:/i.test(url))) return;if (window.XMLHttpRequest) var xhr new XMLHttpRequest(); else var xhr new ActiveXObject("MSXML2.XMLHTTP");xhr.open(GET, u…...

Repo工作原理及常用命令总结——2023.07

文章目录 1. 概要2. 工作原理2.1 项目清单库(.repo/manifests)2.2 repo脚本库(.repo/repo)2.3 仓库目录和工作目录2.4 repo 目录结构分析 3. 使用介绍3.1 init3.2 sync3.3 upload3.4 download3.5 forall3.6 prune3.7 start3.8 status 4. 使用实践4.1 对项目清单文件进行定制4.2…...

Python教程(2)——开发python常用的IDE

为什么需要IDE 在理解IDE之前,我们先做以下的实验,新建一个文件,输入以下代码 total_sum 0 for x in range(1,101):total_sum x print(total_sum)非常非常简单的一个程序,主要就是计算1加到100的值,我们将它重命名…...

【lambda函数】lambda()函数

lambda() lambda()语法捕捉列表mutable lambda 底层原理函数对象与lambda表达式 lambda()语法 lambda表达式书写格式: [capture-list] (parameters) mutable -> return-type{ statement }咱…...

ThreeJs CSS3DObject 点击失效问题

想实现一个在选中物体&#xff0c;弹出菜单&#xff0c;结果发现&#xff0c;点击会失效 <ul id"menu" class"list-group list-group-full"><li class"list-group-item" onclick"test()">24小时曲线</li><li cla…...

飞书深诺、恒生面试(部分)(未完全解析)

飞书深诺 说一下你对SaaS项目的理解&#xff1f;数据隔离是怎么处理的&#xff1f;Answer: 我们采用的是SAAS服务多租户数据隔离架构中的1.3共享数据库&#xff0c;通过租户ID来隔离&#xff0c;成本最低&#xff0c;隔离级别最低。Q&#xff1a;有没有开发隔离的中间件&#x…...

Spring Cloud Config: 了解、原理和使用

Spring Cloud Config: 了解、原理和使用 Spring Cloud Config 是 Spring Cloud 生态系统中的一个重要组件&#xff0c;它提供了一种分布式配置管理的解决方案&#xff0c;能够集中管理应用程序的配置&#xff0c;支持多种后端存储&#xff0c;如 Git、SVN、本地文件系统、Vaul…...

基于图的路径规划算法对比

基于图的路径规划算法对比 算法说明与实现效果构造路网1.打开Arcmap2.新建Shapefile文件3.编辑Shapefile属性4.开始编辑5.创建要素并绘制路网6.打断相交线7.保存编辑8.打开图层属性表9.添加字段10.完成字段添加11.计算字段id12.计算点线字段13.选中length字段14.计算length字段…...

SQL Server 索引

1、索引的概念 假设数据库中现在有2万条记录&#xff0c;现在要执行这样一个查询&#xff1a;SELECT * FROM table where num10000。如果没有索引&#xff0c;必须遍历整个表&#xff0c;直到num等于10000的这一行被找到为止&#xff1b;如果在num列上创建索引&#xff0c;SQL …...

java抽奖

目录 一、简要描述 二、代码 一、简要描述 此抽奖方式为&#xff1a;在1~30个数字之间 挑选7个不重复的数字输入&#xff0c;系统会根据中奖的号码与用户输入的号码进行比较&#xff0c;系统会输出是否中奖的提示&#xff01; 二、代码 import java.util.Scanner; import ja…...

【springboot+云计算】B/S医院信息管理系统源码(云HIS)

一、基于云计算技术的B/S架构的医院管理系统(简称云HIS) 采用前后端分离架构&#xff0c;前端由Angular框架、JavaScript语言开发&#xff1b;后端使用Java语言开发。系统遵循服务化、模块化原则开发&#xff0c;具有强大的可扩展性&#xff0c;二次开发方便快捷。为医疗机构提…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...