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 plt

def 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]])

 

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

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

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

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

相关文章

c语言修炼之猜数字游戏

前言 小伙伴们&#xff0c;今天来学习猜数字游戏叭&#xff01;废话不多说&#xff0c;让我们一起开始学习叭! 思路&#xff1a; 一打开游戏就出现一个菜单然后可以让我们选择是进入游戏还是退出游戏&#xff01; #include<stdio.h> void menu() {printf("*****…

【MySQL】基本查询之表的增删改查

【MySQL】表的增删改查 一、插入操作----insert1.1 简单插入1.2 插入时是否更新----ON DUPLICATE KEY UPDATE1.3 插入时替换----REPLACE 二、查询----select2.1 简单查询与去重2.2 基本查询----where条件2.2.3 案列演示 2.4 排序----order by 三、修改操作----update四、删除--…

Lua学习笔记:浅谈table的实现

前言 本篇在讲什么 Lua中的table的实现 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Sublime Text编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手 提供全流程的源码内容 ★提高阅读体验★ &…

大数据Doris(五十三):MySQL Dump 导出

文章目录 MySQL dump 导出 一、Dump导出案例 二、注意事项 MySQL Dump 导出 mysqldump是一个常用的 MySQL 数据库备份工具&#xff0c;它可以将 MySQL 数据库中的数据导出为 SQL 格式的文件&#xff0c;从而实现对数据的备份、迁移和恢复等操作。Doris 在0.15 之后的版本已…

青岛大学_王卓老师【数据结构与算法】Week04_03_双向链表_学习笔记

本文是个人学习笔记&#xff0c;素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享&#xff0c;另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权&#xff0c;请留言作删文处理。 课程视频链接&#xff1a; 数据结构与算法基础–…

Spring Boot 集成 Redisson分布式锁

Redisson 是一种基于 Redis 的 Java 驻留集群的分布式对象和服务库&#xff0c;可以为我们提供丰富的分布式锁和线程安全集合的实现。在 Spring Boot 应用程序中使用 Redisson 可以方便地实现分布式应用程序的某些方面&#xff0c;例如分布式锁、分布式集合、分布式事件发布和订…

Oracle数据库软件安装与卸载

Oracle数据库软件安装与卸载 实验目的及要求 学习Oracle12c数据库服务器软件和客户端软件的安 装与卸载,掌握客户端服务名的设置,建立客户端与服务器的网络连接,熟悉windows操作系统中Oracle相关服务的操作。理解数据库管理的基本架构。 &#xff08;1&#xff09;熟悉Oracle…

基于SpringBoot+SpringCloud+vue的智慧养老平台设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

虚拟机上用docker + nginx跑前端并支持https和http

情况是这样&#xff0c;我在虚拟机上&#xff0c;使用docker跑前端&#xff0c;需要这个前端支持https&#xff0c;原http的话自动跳转到https。另外&#xff0c;前端部署使用了负载均衡&#xff0c;即使用了3个docker跑前端&#xff1a;1个入口&#xff0c;另外2个是前端&…

【macOS 系列】mac设置截屏或其他操作的默认保存位置

1、第一步、在用户/图片文件夹下&#xff0c;新建“截图”文件夹 2、第二步、打开终端&#xff0c;输入defaults write com.apple.screencapture location ~/Pictures/截图/后回车 3、第三步、操作完成后&#xff0c;再次输入killall SystemUIServer后回车 如果你在web前端开发…

clickhouse中时间戳转换--网上都没有,自己总结的

第一种&#xff1a; 库里时间戳为13位时&#xff1a; 类似这种13位的时间戳&#xff1a;1476141341051 怎么转换成正常的日期&#xff1a; 如果库里存的string类型&#xff0c;需要toUInt64(date_time) date_time的值为&#xff1a;1476141341051 然后利用toDateTime&…

远古 Windows 98 SE 和 putty 0.63 连接 SSH

远古 Windows 98 SE 和 putty 0.63 连接 SSH 不忘初心一、故障表现二、产生原因三、解决办法四、重启 SSHD 服务生交配置参考 作者&#xff1a;高玉涵 时间&#xff1a;2023.7.1 操作系统&#xff1a; Windows 98 第二版 4.10.2222 A Linux version 5.19.0-32-generic (build…

Redis实战——商户查询(二)

缓存穿透 缓存穿透 &#xff1a;客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这样的请求都会访问到数据库&#xff0c;这样的大量请求同时过来访问这种不存在的数据&#xff0c;这些请求就都会访问到数据库&#xff0c;对数据库造…

基于smardaten无代码开发舆情分析系统

一、前言 在日常生活中&#xff0c;有各种各样的资讯、社交平台。这些平台充斥着大量信息&#xff0c;这些信息中隐含了许多有用数据&#xff0c;但是这些数据无法之间获取&#xff0c;且难以展示&#xff0c;于是就有了舆情分析系统。 舆情分析系统是一个综合的系统&#xf…

基于minsit数据集的图像分类任务|CNN简单应用项目

Github地址 Image-classification-task-based-on-minsit-datasethttps://github.com/Yufccode/CollegeWorks/tree/main/ImageProcessing/Image-classification-task-based-on-minsit-dataset README 摘要 本次实验报告用两种方式完成了基于minst数据集完成了图像的分类任务…

被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了

前言 忙里偷闲学习了点技术写了点demo代码&#xff0c;打算提交到我那 2000Star 的Github仓库上&#xff0c;居然发现有5个Issues&#xff0c;最近的一条日期已经是2022/8/1了&#xff0c;以前我还真没留意过这些&#xff0c;我这人懒得很&#xff0c;本地代码提交成功基本就不…

Python dict keys方法:获取字典中键的序列【将keys转为list】

描述 dict.keys()方法是Python的字典方法&#xff0c;它将字典中的所有键组成一个可迭代序列并返回。 使用示例 >>> list({Chinasoft:China, Microsoft:USA}.keys()) [Chinasoft, Microsoft] >>> test_dict {Chinasoft:China, Microsoft:USA, Sony:Japan,…

【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(7 月 4 日论文合集)

文章目录 一、检测相关(15篇)1.1 Artifacts Mapping: Multi-Modal Semantic Mapping for Object Detection and 3D Localization1.2 Shi-NeSS: Detecting Good and Stable Keypoints with a Neural Stability Score1.3 HODINet: High-Order Discrepant Interaction Network for…

机器学习一:线性回归

1 知识预警 1.1 线性代数 ( A T ) T A (A^\mathrm{T})^\mathrm{T}A (AT)TA$ ( A B ) T A T B T (AB)^\mathrm{T}A^\mathrm{T}B^\mathrm{T} (AB)TATBT ( λ A ) T λ A T (\lambda A)^\mathrm{T}\lambda A^\mathrm{T} (λA)TλAT ( A B ) T B T A T (AB)^\mathrm{T}B^…

【算法与数据结构】28、LeetCode实现strStr函数

文章目录 一、题目二、暴力穷解法三、KMP算法四、Sunday算法五、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、暴力穷解法 思路分析&#xff1a;首先判断字符串是否合法&#xff0c;然后利用for循环&#xff…