【图像处理】OpenCV+Python图像处理入门教程(四)几何变换
这篇随笔介绍使用OpenCV进行图像处理的第四章 几何变换。
4 几何变换
图像的几何变换是指将一幅图像映射到另一幅图像内。有缩放、翻转、仿射变换、透视、重映射等操作。
4.1 缩放
使用cv2.resize()函数实现对图像的缩放,但要注意cv2.resize()函数内的dsize参数与原图像的行列属性是相反的,也就是:目标图像的行数是原始图像的列数,目标图像的列数是原始图像的行数。
下面举例说明cv2.resize()函数的用法:
1 import cv2
2 img=cv2.imread('E:/python_opencv/tupian.jpg')
3 rows,cols=img.shape[0:2] #行数和列数等于img的长度和宽度
4 size=(int(cols*0.9),int(rows*0.5)) #比例:列变为原来0.9倍,行变为0.5倍
5 rst=cv2.resize(img,size) #将img按size比例缩放
6 print('img.shape=',img.shape)
7 print('rst.shape=',rst.shape)
运行程序的结果如下:
img.shape=(600,60,3)
rst.shape=(300,54,3)
可以看出,行数变为原来的0.5倍,列数变为原来的0.9倍。代码中size的行列位置发生了交换。
4.2 翻转
使用cv2.flip()函数对图像翻转,能够实现水平方向翻转、垂直方向翻转、两个方向同时翻转。
下面举例说明cv2.flip()函数的用法:
1 import cv2
2 img=cv2.imread('E:/python_opencv/tupian.jpg')
3 x=cv2.flip(img,0) #图x对原图像绕x轴翻转
4 y=cv2.flip(img,1) #图y对原图像绕y轴翻转
5 xy=cv2.flip(img,-1) #图xy对原图像绕x轴y轴同时翻转
6 cv2.imshow('img',img)
7 cv2.imshow('x',x)
8 cv2.imshow('y',y)
9 cv2.imshow('xy',xy)
10 cv2.waitKey()
11 cv2.destroyAllWindows()
程序运行结果如下四幅图,第一幅是原图,第二幅是绕x轴翻转,第三幅是绕y轴翻转,第四幅是绕x轴y轴同时翻转。
4.3 仿射
仿射变换是指图像实现平移、旋转等操作。
先设置一个变换矩阵M,然后使用cv2.warpAffine()函数对原图像和变换矩阵M进行仿射操作。
(一)平移
要实现图像的平移,我们先自定义一个转换矩阵,再进行仿射平移变换。例程如下:
1 import cv2
2 import numpy as np
3 img=cv2.imread('E:\python_opencv/tupian.jpg')
4 height,width=img.shape[:2] #读取原图像的长和宽
5 x=100 #自定义转换矩阵M的x轴移动值
6 y=200 #自定义转换矩阵M的y轴移动值
7 M=np.float32([[1,0,x],[0,1,y]]) #构造转换矩阵M
8 move=cv2.warpAffine(img,M,(width,height)) #平移映射
9 cv2.imshow('orginal',img)
10 cv2.imshow('move',move)
11 cv2.waitKey()
12 cv2.destroyAllWindows()
程序运行结果如下图所示,左为原图,右为平移后的图。
(二)旋转
使用函数cv2.getRotationMatrix2D()获得转移矩阵M,然后使用函数cv2.warpAffine()进行仿射旋转变换。例程如下:
1 import cv2
2 img=cv2.imread('E:\python_opencv/tupian.jpg')
3 height,width=img.shape[:2] #读取原图像的长和宽
4 M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6) #以中心为原点,逆时针旋转45°,且缩小为原图的0.6倍,获得转移矩阵M
5 rotate=cv2.warpAffine(img,M,(width,height)) #旋转映射
6 cv2.imshow('original',img)
7 cv2.imshow('rotation',rotate)
8 cv2.waitKey()
9 cv2.destroyAllWindows()
程序运行结果如下图所示,左为原图,右为旋转后的图。
4.4 透视
透视变换是指将矩阵图形投影到另一个视平面,可以映射为任意四边形,所以透视变换也被称为投影映射(Projection Mapping),并不是字面意义上的“透视”。透视与上节的仿射不同,仿射可以将矩阵映射为任意平行四边形。
使用cv2.warpPerspective()函数实现透视变换。例程如下:
1 #完成图像透视
2 import cv2
3 import numpy as np
4 img=cv2.imread('E:/python_opencv/tupian.jpg')
5 rows,cols=img.shape[:2] #读取原图像的长和宽
6 print(rows,cols)
7 #生成旋转矩阵M
8 pts1=np.float32([[150,50],[400,50],[60,450],[310,450]])
9 pts2=np.float32([[50,50],[rows-50,50],[50,cols-50],[rows-50,cols-50]])
10 M=cv2.getPerspectiveTransform(pts1,pts2)
11 #使用函数cv2.warpPerspective()进行透视变换
12 dst=cv2.warpPerspective(img,M,(cols,rows))
13 cv2.imshow('img',img)
14 cv2.imshow('dst',dst)
15 cv2.waitKey()
16 cv2.destroyAllWindows()
程序运行结果如下图所示,左为原图,右为透视变换的图。
我们可以看到,原图片经过透视映射后,变成另一个视角下的任意四边形了。
4.5 重映射
重映射是修改了像素点的位置,从而生成一幅新的图像,包括:复制、绕x轴y轴翻转,x轴y轴互换,图像缩放等。
均使用cv2.remap()重映射函数进行操作。
需要注意cv2.remap()中的两个参数mapx、mapy。mapx表示对应位置上x轴坐标值,mapy表示对应位置上y轴坐标值。
(一)复制
使用cv2.remap()函数完成图像复制,需先定义mapx,mapy的值,然后循环映射每个像素点到对应的位置上。
代码如下:
1 import cv2
2 import numpy as np
3 img=cv2.imread('E:/python_opencv/tupian.jpg')
4 rows,cols=img.shape[:2] #读取行列数
5 mapx=np.zeros(img.shape[:2],np.float32) #mapx参数设定为对应位置上的x轴坐标值
6 mapy=np.zeros(img.shape[:2],np.float32) #mapy参数设定为对应位置上的y轴坐标值
7 for i in range(rows): #对每个元素复制映射
8 for j in range(cols):
9 mapx.itemset((i,j),j)
10 mapy.itemset((i,j),i)
11 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
12 cv2.imshow('original',img)
13 cv2.imshow('result',rst)
14 cv2.waitKey()
15 cv2.destroyAllWindows()
执行后结果如下所示,可以看到,实现了图像的复制重映射。
(二)绕x轴翻转
重映射法对图像绕x轴翻转,表明mapx的值保持不变,mapy的值调整为总行数-1-当前行号,其余部分代码不变,所以循环体内代码变为:
1 for i in range(rows):
2 for j in range(cols):
3 mapx.itemset((i,j),j) #mapx的值保持不变
4 mapy.itemset((i,j),rows-1-i) #mapy的值调整为总行数-1-当前行号
(三)绕y轴翻转
重映射法对图像绕y轴翻转,表明mapx的值调整为总行数-1-当前列号,mapy的值保持不变,所以循环体内代码变为:
1 for i in range(rows):
2 for j in range(cols):
3 mapx.itemset((i,j),cols-1-j) #mapx的值调整为总列数-1-当前列号
4 mapy.itemset((i,j),i) #mapy的值保持不变
(四)绕x轴y轴翻转
重映射也能实现图像绕x轴和y轴的同时翻转,只需将前两个部分合并,使mapx的值调整为总行数-1-当前列号,mapy的值调整为总行数-1-当前行号。例程如下:
1 import cv2
2 import numpy as np
3 img=cv2.imread('E:\python_opencv/tupian.jpg')
4 rows,cols=img.shape[:2]
5 mapx=np.zeros(img.shape[:2],np.float32)
6 mapy=np.zeros(img.shape[:2],np.float32)
7 for i in range(rows):
8 for j in range(cols):
9 mapx.itemset((i,j),cols-1-j) #mapx的值调整为总列数-1-当前列号
10 mapy.itemset((i,j),rows-1-i) #mapy的值调整为总行数-1-当前行号
11 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
12 cv2.imshow('original',img)
13 cv2.imshow('result',rst)
14 cv2.waitKey()
15 cv2.destroyAllWindows()
执行后结果如下所示,可以看到,实现了图像的绕x轴和y轴翻转重映射过程。
(五)x轴、y轴互换
重映射中,x轴、y轴互换表明,mapx的值变为所在行的行号,mapy的值变为所在列的列号。
但当行数和列数不一致时,行或列无法完成映射的部分就被处理为0。示例代码如下:
1 #使用函数cv2.remap()实现图像绕x轴和y轴的互换
2 import cv2
3 import numpy as np
4 img=cv2.imread('E:\python_opencv/tupian.jpg')
5 rows,cols=img.shape[:2]
6 mapx=np.zeros(img.shape[:2],np.float32)
7 mapy=np.zeros(img.shape[:2],np.float32)
8 for i in range(rows):
9 for j in range(cols):
10 mapx.itemset((i,j),i) #mapx的值变为所在行的行号
11 mapy.itemset((i,j),j) #mapy的值变为所在列的列号
12 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
13 cv2.imshow('original',img)
14 cv2.imshow('result',rst)
15 cv2.waitKey()
16 cv2.destroyAllWindows()
结果如图:
可以看到,列数多于行数的部分被置为0(黑色)。
(六)图像的缩放
重映射提供了cv2.remap()函数能够实现图像的放大或缩小。处理图像后,可以将图像固定在围绕其中心的某个区域。
下面例程中,x轴和y轴均缩小为原来的0.25-0.75倍之间。
1 import cv2
2 import numpy as np
3 img=cv2.imread('E:\python_opencv/tupian.jpg')
4 rows,cols=img.shape[:2]
5 mapx=np.zeros(img.shape[:2],np.float32)
6 mapy=np.zeros(img.shape[:2],np.float32)
7 for i in range(rows):
8 for j in range(cols):
9 if 0.25*cols < i < 0.75*cols and 0.25*rows < i < 0.75*rows:
10 #在目标图像的x轴(0.25-0.75)倍之内生成缩小图像
11 mapx.itemset((i,j),2*(j-0.25*cols)+0.5)
12 #在目标图像的y轴(0.25-0.75)倍之内生成缩小图像
13 mapy.itemset((i,j),2*(i-rows*0.25)+0.5)
14 else:
15 #不在上述区域的点都取(0,0)坐标点的值
16 mapx.itemset((i,j),0)
17 mapy.itemset((i,j),0)
18 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) #图像缩放重映射
19 cv2.imshow('original',img)
20 cv2.imshow('result',rst)
21 cv2.waitKey()
22 cv2.destroyAllWindows()
图像缩放重映射结果如下:
这次内容就分享到这里了,下次继续更新第5章 图像阈值处理,希望与各位老师和小伙伴们交流学习~
【图像处理】OpenCV+Python图像处理入门教程(四)几何变换的更多相关文章
- PySide——Python图形化界面入门教程(四)
PySide——Python图形化界面入门教程(四) ——创建自己的信号槽 ——Creating Your Own Signals and Slots 翻译自:http://pythoncentral ...
- 无废话ExtJs 入门教程四[表单:FormPanel]
无废话ExtJs 入门教程四[表单:FormPanel] extjs技术交流,欢迎加群(201926085) 继上一节内容,我们在窗体里加了个表单.如下所示代码区的第28行位置,items:form. ...
- Python基础入门教程
Python基础入门教程 Python基础教程 Python 简介 Python环境搭建 Python 基础语法 Python 变量类型 Python 运算符 Python 条件语句 Python 循 ...
- Python爬虫入门教程 48-100 使用mitmdump抓取手机惠农APP-手机APP爬虫部分
1. 爬取前的分析 mitmdump是mitmproxy的命令行接口,比Fiddler.Charles等工具方便的地方是它可以对接Python脚本. 有了它我们可以不用手动截获和分析HTTP请求和响应 ...
- Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
1. Python爬虫入门教程 爬取背景 2019年1月10日深夜,打开了百思不得姐APP,想了一下是否可以爬呢?不自觉的安装到了夜神模拟器里面.这个APP还是比较有名和有意思的. 下面是百思不得姐的 ...
- 2019-03-22 Python Scrapy 入门教程 笔记
Python Scrapy 入门教程 入门教程笔记: # 创建mySpider scrapy startproject mySpider # 创建itcast.py cd C:\Users\theDa ...
- Elasticsearch入门教程(四):Elasticsearch文档CURD
原文:Elasticsearch入门教程(四):Elasticsearch文档CURD 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: ...
- RabbitMQ入门教程(四):工作队列(Work Queues)
原文:RabbitMQ入门教程(四):工作队列(Work Queues) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https:/ ...
- JasperReports入门教程(四):多数据源
JasperReports入门教程(四):多数据源 背景 在报表使用中,一个页面需要打印多个表格,每个表格分别使用不同的数据源是很常见的一个需求.假如我们现在有一个需求如下:需要在一个报表同时打印所有 ...
随机推荐
- 【Alpaca】.Net版开源配置中心 - 技术选型 Vue 3.0
是否可以用 Vue 3.0 现有的Vue 2.* 不推荐,坐等Vue 3.0出迁移工具吧,手动改的话工作量还是不小的 新项目 考虑下团队内对Vue + TS + VS Code的熟练程度.过程中你会遇 ...
- /usr/lib/nvidia-384/libEGL.so.1 is not a symbolic link
记得要将384改为自己系统对应的a. sudo mv /usr/lib/nvidia-384/libEGL.so.1 /usr/lib/nvidia-384/libEGL.so.1.org sudo ...
- React 组件之间通信 All in One
React 组件之间通信 All in One 组件间通信 1. 父子组件之间通信 props 2. 兄弟组件之间通信 3. 跨多层级的组件之间通信 Context API https://react ...
- 微信小程序-云开发实战教程
微信小程序-云开发实战教程 云函数,云存储,云数据库,云调用 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/gettin ...
- 微信小程序 TypeScript bug
微信小程序 TypeScript bug 执行自定义预览前预处理命令失败! internal/modules/cjs/loader.js:584 throw err; ^ Error: Cannot ...
- js currying function All In One
js currying function All In One js 实现 (5).add(3).minus(2) 功能 例: 5 + 3 - 2,结果为 6 https://stackoverflo ...
- k8s部署mysql数据持久化
在这里我部署mysql的目的是为了后面将上一篇博客docker打包的el-admin镜像部署到k8s上,所以本文主要是部署mysql并实现持久化. 1.将我们的应用都部署到 el-admin 这个命名 ...
- 近期最值得关注的潜力币种——VAST
近期币圈的热度又再次被掀起,很多新的币种也争相上线,还有一些币种虽然还未上线,但是在币圈的火热程度也非同一般.小编留意了一下,最近在币圈讨论的最火的便是VAST代币.许多生态建设者乃至机构都表示很看好 ...
- 实用Macbook软件系列
Macbook Software 实用Macbook软件系列 我的Mac都装了哪些软件 鉴于很多小伙伴刚刚由win系统转换到mac,一开始会有很多不适应的地方,所以本期文章准备给大家介绍下mac上一些 ...
- 自己写的一个抢票加速的Python小程序源码分享-----纯属娱乐
最近这段时间频频看到微信群里发什么 抢票加速,智行.携程.飞猪.美团,对于我这能坐客车就不坐火车的人来说,无所谓靠谱不靠谱 突发奇想的整理了下整个抢票加速的逻辑,写了这个小程序,代码很low,拒绝批评 ...