OpenCV+Python几何变换的实现示例
作者:雨吹桐 发布时间:2022-02-09 14:44:52
几何变换
图像的几何变换是指将一幅图像映射到另一幅图像内。有缩放、翻转、仿射变换、透视、重映射等操作。
1 缩放
使用cv2.resize()函数实现对图像的缩放,但要注意cv2.resize()函数内的dsize参数与原图像的行列属性是相反的,也就是:目标图像的行数是原始图像的列数,目标图像的列数是原始图像的行数。
下面举例说明cv2.resize()函数的用法:
import cv2
img=cv2.imread('E:/python_opencv/tupian.jpg')
rows,cols=img.shape[0:2] #行数和列数等于img的长度和宽度
size=(int(cols*0.9),int(rows*0.5)) #比例:列变为原来0.9倍,行变为0.5倍
rst=cv2.resize(img,size) #将img按size比例缩放
print('img.shape=',img.shape)
print('rst.shape=',rst.shape)
运行程序的结果如下:
img.shape=(600,60,3)
rst.shape=(300,54,3)
可以看出,行数变为原来的0.5倍,列数变为原来的0.9倍。代码中size的行列位置发生了交换。
2 翻转
使用cv2.flip()函数对图像翻转,能够实现水平方向翻转、垂直方向翻转、两个方向同时翻转。
下面举例说明cv2.flip()函数的用法:
import cv2
img=cv2.imread('E:/python_opencv/tupian.jpg')
x=cv2.flip(img,0) #图x对原图像绕x轴翻转
y=cv2.flip(img,1) #图y对原图像绕y轴翻转
xy=cv2.flip(img,-1) #图xy对原图像绕x轴y轴同时翻转
cv2.imshow('img',img)
cv2.imshow('x',x)
cv2.imshow('y',y)
cv2.imshow('xy',xy)
cv2.waitKey()
cv2.destroyAllWindows()
程序运行结果如下四幅图,第一幅是原图,第二幅是绕x轴翻转,第三幅是绕y轴翻转,第四幅是绕x轴y轴同时翻转。
3 仿射
仿射变换是指图像实现平移、旋转等操作。
先设置一个变换矩阵M,然后使用cv2.warpAffine()函数对原图像和变换矩阵M进行仿射操作。
(一)平移
要实现图像的平移,我们先自定义一个转换矩阵,再进行仿射平移变换。例程如下:
import cv2
import numpy as np
img=cv2.imread('E:\python_opencv/tupian.jpg')
height,width=img.shape[:2] #读取原图像的长和宽
x=100 #自定义转换矩阵M的x轴移动值
y=200 #自定义转换矩阵M的y轴移动值
M=np.float32([[1,0,x],[0,1,y]]) #构造转换矩阵M
move=cv2.warpAffine(img,M,(width,height)) #平移映射
cv2.imshow('orginal',img)
cv2.imshow('move',move)
cv2.waitKey()
cv2.destroyAllWindows()
程序运行结果如下图所示,左为原图,右为平移后的图。
(二)旋转
使用函数cv2.getRotationMatrix2D()获得转移矩阵M,然后使用函数cv2.warpAffine()进行仿射旋转变换。例程如下:
import cv2
img=cv2.imread('E:\python_opencv/tupian.jpg')
height,width=img.shape[:2] #读取原图像的长和宽
M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6) #以中心为原点,逆时针旋转45°,且缩小为原图的0.6倍,获得转移矩阵M
rotate=cv2.warpAffine(img,M,(width,height)) #旋转映射
cv2.imshow('original',img)
cv2.imshow('rotation',rotate)
cv2.waitKey()
cv2.destroyAllWindows()
程序运行结果如下图所示,左为原图,右为旋转后的图。
4 透视
透视变换是指将矩阵图形投影到另一个视平面,可以映射为任意四边形,所以透视变换也被称为投影映射(ProjectionMapping),并不是字面意义上的“透视”。透视与上节的仿射不同,仿射可以将矩阵映射为任意平行四边形。
使用cv2.warpPerspective()函数实现透视变换。例程如下:
#完成图像透视
import cv2
import numpy as np
img=cv2.imread('E:/python_opencv/tupian.jpg')
rows,cols=img.shape[:2] #读取原图像的长和宽
print(rows,cols)
#生成旋转矩阵M
pts1=np.float32([[150,50],[400,50],[60,450],[310,450]])
pts2=np.float32([[50,50],[rows-50,50],[50,cols-50],[rows-50,cols-50]])
M=cv2.getPerspectiveTransform(pts1,pts2)
#使用函数cv2.warpPerspective()进行透视变换
dst=cv2.warpPerspective(img,M,(cols,rows))
cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.waitKey()
cv2.destroyAllWindows()
程序运行结果如下图所示,左为原图,右为透视变换的图。
我们可以看到,原图片经过透视映射后,变成另一个视角下的任意四边形了。
5 重映射
重映射是修改了像素点的位置,从而生成一幅新的图像,包括:复制、绕x轴y轴翻转,x轴y轴互换,图像缩放等。
均使用cv2.remap()重映射函数进行操作。
需要注意cv2.remap()中的两个参数mapx、mapy。mapx表示对应位置上x轴坐标值,mapy表示对应位置上y轴坐标值。
(一)复制
使用cv2.remap()函数完成图像复制,需先定义mapx,mapy的值,然后循环映射每个像素点到对应的位置上。
代码如下:
import cv2
import numpy as np
img=cv2.imread('E:/python_opencv/tupian.jpg')
rows,cols=img.shape[:2] #读取行列数
mapx=np.zeros(img.shape[:2],np.float32) #mapx参数设定为对应位置上的x轴坐标值
mapy=np.zeros(img.shape[:2],np.float32) #mapy参数设定为对应位置上的y轴坐标值
for i in range(rows): #对每个元素复制映射
for j in range(cols):
mapx.itemset((i,j),j)
mapy.itemset((i,j),i)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow('original',img)
cv2.imshow('result',rst)
cv2.waitKey()
cv2.destroyAllWindows()
执行后结果如下所示,可以看到,实现了图像的复制重映射。
(二)绕x轴翻转
重映射法对图像绕x轴翻转,表明mapx的值保持不变,mapy的值调整为总行数-1-当前行号,其余部分代码不变,所以循环体内代码变为:
for i in range(rows):
for j in range(cols):
mapx.itemset((i,j),j) #mapx的值保持不变
mapy.itemset((i,j),rows-1-i) #mapy的值调整为总行数-1-当前行号
(三)绕y轴翻转
重映射法对图像绕y轴翻转,表明mapx的值调整为总行数-1-当前列号,mapy的值保持不变,所以循环体内代码变为:
for i in range(rows):
for j in range(cols):
mapx.itemset((i,j),cols-1-j) #mapx的值调整为总列数-1-当前列号
mapy.itemset((i,j),i) #mapy的值保持不变
(四)绕x轴y轴翻转
重映射也能实现图像绕x轴和y轴的同时翻转,只需将前两个部分合并,使mapx的值调整为总行数-1-当前列号,mapy的值调整为总行数-1-当前行号。例程如下:
import cv2
import numpy as np
img=cv2.imread('E:\python_opencv/tupian.jpg')
rows,cols=img.shape[:2]
mapx=np.zeros(img.shape[:2],np.float32)
mapy=np.zeros(img.shape[:2],np.float32)
for i in range(rows):
for j in range(cols):
mapx.itemset((i,j),cols-1-j) #mapx的值调整为总列数-1-当前列号
mapy.itemset((i,j),rows-1-i) #mapy的值调整为总行数-1-当前行号
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow('original',img)
cv2.imshow('result',rst)
cv2.waitKey()
cv2.destroyAllWindows()
执行后结果如下所示,可以看到,实现了图像的绕x轴和y轴翻转重映射过程。
(五)x轴、y轴互换
重映射中,x轴、y轴互换表明,mapx的值变为所在行的行号,mapy的值变为所在列的列号。
但当行数和列数不一致时,行或列无法完成映射的部分就被处理为0。示例代码如下:
#使用函数cv2.remap()实现图像绕x轴和y轴的互换
import cv2
import numpy as np
img=cv2.imread('E:\python_opencv/tupian.jpg')
rows,cols=img.shape[:2]
mapx=np.zeros(img.shape[:2],np.float32)
mapy=np.zeros(img.shape[:2],np.float32)
for i in range(rows):
for j in range(cols):
mapx.itemset((i,j),i) #mapx的值变为所在行的行号
mapy.itemset((i,j),j) #mapy的值变为所在列的列号
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow('original',img)
cv2.imshow('result',rst)
cv2.waitKey()
cv2.destroyAllWindows()
结果如图:
可以看到,列数多于行数的部分被置为0(黑色)。
(六)图像的缩放
重映射提供了cv2.remap()函数能够实现图像的放大或缩小。处理图像后,可以将图像固定在围绕其中心的某个区域。
下面例程中,x轴和y轴均缩小为原来的0.25-0.75倍之间。
import cv2
import numpy as np
img=cv2.imread('E:\python_opencv/tupian.jpg')
rows,cols=img.shape[:2]
mapx=np.zeros(img.shape[:2],np.float32)
mapy=np.zeros(img.shape[:2],np.float32)
for i in range(rows):
for j in range(cols):
if 0.25*cols < i < 0.75*cols and 0.25*rows < i < 0.75*rows:
#在目标图像的x轴(0.25-0.75)倍之内生成缩小图像
mapx.itemset((i,j),2*(j-0.25*cols)+0.5)
#在目标图像的y轴(0.25-0.75)倍之内生成缩小图像
mapy.itemset((i,j),2*(i-rows*0.25)+0.5)
else:
#不在上述区域的点都取(0,0)坐标点的值
mapx.itemset((i,j),0)
mapy.itemset((i,j),0)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) #图像缩放重映射
cv2.imshow('original',img)
cv2.imshow('result',rst)
cv2.waitKey()
cv2.destroyAllWindows()
来源:https://www.cnblogs.com/wanghaining/p/opencv-python-4.html


猜你喜欢
- 当完整备份数据库的时候,我们有时候可能会遇到一种极端情况,比如服务器上C,D,E三个盘符都只剩下5G空间了但是如果要完整备份业务库需要12G
- 什么是合并多行字符串(连接字符串)呢,例如: SQL> desc test; Name Type Nullable Default C
- 一、背景描述csv格式文件是一种类似于excel的文件格式asc格式文件是一种可以用text打开的文本文件csv转asc本来可以用arcgi
- 本文介绍一款工具 go-callvis,它能够将 Go 代码的调用关系可视化出来,并提供了可交互式的 web 服务。go get -u gi
- 要实现此效果需要 1 个步骤: 第 1 步: 把下面的代码加到<BODY></BODY&g
- 这篇文章主要介绍了Python爬取豆瓣视频信息代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 三个页在同一个窗口,分别为main.htm,left.htm和right.htm。 main.htm <html> <he
- 最近在做cocos2d-x的简明配置,发现有的朋友的文本编辑器,自动将\r\n截断成\n,(在unix上换行使用\n,windows上,换行
- 1.理论只要两个表的公共字段有匹配值,就将这两个表中的记录组合起来。个人理解:以一个共同的字段求两个表中符合要求的交集,并将每个表符合要求的
- 希望对您有所帮助!推荐:[精品]ASP中常用的22个FSO文件操作函数 <%@ Language=VBScript
- go语言做爬虫也是很少尝试,首先我的思路是看一下爬虫的串行实现,然后通过两个并发实现:一个使用锁,另一个使用通道这里不涉及从页面中提取URL
- 整个重装步骤大致分四个步骤进行,第一步,备份原mysql中的所有数据库。第二步,完全卸载mysql第三步,下载安装新版mysql第四步,导入
- 1. 过滤器Python 具有通过列表解析 将列表映射到其它列表的强大能力。这种能力同过滤机制结合使用,使列表中的有些元素被映射的同时跳过另
- 在微软的ASP编程体系中,ADO对象的建立,使得从网页访问数据库成为一件易事,特别是ADO的Recordset对象使得控制数据的输出显示更为
- MySQL中有许多操作符和函数可以返回字符串。本节回答这个问题:返回的字符串使用什么字符集和 校对规则?对于简单的函数,即接收字符串输入然后
- 1、主动删除对象调用del 对象;程序运行结束后,python也会自动进行删除其他的对象。class Animal: &nbs
- 这几天有这样一个需求,要将用户登陆系统的信息统计出来,做成一个报表。当用户登陆成功的时候,服务器会往日志文件里写一条像下面这种格式的记录:”
- 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。看代码:# -*- coding: utf-8 -*-# @File &nb
- 引言:在Python3下运行Matplotlib之时,碰到了”No module named _tkinter“的问题,花费数小时进行研究解
- Pandas库十分强大,但是对于切片操作iloc, loc和ix,很多人对此十分迷惑,因此本篇博客利用例子来说明这3者之一的区别和联系,尤其