OpenCV-python学习笔记(五)——几何变换

五、几何变换

几何变换指将一幅图像映射到另外一幅图像内的操作,分别有缩放,翻转,放射变换,透视,重映射等

一、缩放cv.2resize()

dst=cv2.resize (src,dsize[,fx[,fy[,interpolation]]])

**(1)dst:**代表输出的目标图像,该图像的类型与src相同,其大小为dsize (当该值非零时),或者可以通过src.size () 、 fx、fy计算得到。

**(2)src:**代表需要缩放的原始图像。

**(3)dsize:**代表输出图像大小。

**(4)fx:**代表水平方向的缩放比例。

**(5)fy:**代表垂直方向的缩放比例。

**(6)interpolation:**代表插值方式
在这里插入图片描述
(1)通过参数dsize指定目标图像大小

​ 如果指定参数dsize的值,则无论是否指定了参数fx和fy的值,都由参数dsize来决定目标图像的大小。

​ 此时需要注意的是,dsize内第1个参数对应缩放后图像的苋度(WIan,以列效wbls,-参数fx相关),第2个参数对应缩放后图像的高度(height,即行数rows,与参数fy相关)。
​ 指定参数dsize的值时,x方向的缩放大小(参数fx)为︰
(double) dsize.width/src.cols
​ 同时,y方向的缩放大小(参数fy)为︰
(double) dsize.height/src.rows

(2):通过fx和fy指定

dsize=Size (round ( fx·src.cols) ,round (fy*src.rows) )

	插值是指在对图像进行几何处理时,给无法直接通过映射得到值的像素点赋值。例如,将图像放大为原来的2倍,必然会多出一些**无法被直接映射值的像素点**,对于这些像素点,插值方式决定了如何确定它们的值。

​ 除此以外,还会存在一些非整数的映射值,例如,反向映射可能会把目标图像中的像素点值映射到原始图像中的非整数值对应的位置上,当然原始图像内是不可能存在这样的非整数位置的,即目标图像上的该像素点不能对应到原始图像的某个具体位置上,此时也要对这些像素点进行插值处理,以完成映射。

当缩小图像时,使用区域插值方式(INTER_AREA)能够得到最好的效果

当放大图像时,使用三次样条插值(INTER_CUBIC)方式和双线性插值(INTER_LINEAR)方式都能够取得较好的效果。三次样条插值方式速度较慢,双线性插值方式速度相对较快且效果并不逊色。

​ 在shape属性中,第1个值对应的是行数,第2个值对应的是列数
​ 在dsize参数中,第1个值对应的是列数,第2个值对应的是行数

二、翻转cv2.flip ()

水平,垂直方向翻转

dst=cv2.flip (src,flipCode)

**(1)dst:**代表和原始图像具有同样大小、类型的目标图像。
**(2)src:**代表要处理的原始图像。
(3)flipCode: 代表旋转类型。该参数的意义如表所示。

参数值 说明 意义
0 只能是0 绕x轴翻转
正数 1.2.3等任意正数 绕y轴翻转
负数 -1.-2.-3等任意负数 围绕x,y轴同时翻转

示例:

import cv2
img=cv2.imread ("lena.png")
x=cv2.flip (img,0)
y=cv2.flip (img,1)
xy=cv2.flip (img,-1)
cv2.imshow ("img",img)
cv2.imshow ("x",x)
cv2.imshow ("y",y)
cv2.imshow ("xy",xy)
cv2.waitKey ()
cv2.destroyAllWindows ()

三、仿射cv2.warpAffine ()

仿射变换是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。

通过变换矩阵(映射矩阵)M实现变换

dst (x,y) =src (M11x+M12y+M13,M21x+M22y+M23)

仿射矩阵R=变换矩阵M×原始图像O

dst=cv2.warpAffine (src,M,dsize[,flags[,borderMode[,borderValue]

**(1)src:**代表要仿射的原始图像。
**(2)M:**代表一个2×3的变换矩阵。使用不同的变换矩阵,就可以实现不同的仿射变换。
**(3)dsize:**代表输出图像的尺寸大小。
**(4)flags:**代表插值方法,默认为INTER_LINEAR。当该值为WARP_INVERSE_MAP时,意味着M是逆变换类型,实现从目标图像dst到原始图像src的逆变换。
(5)borderMode: 代表边类型,默认为BORDER_CONSTANT。当该值为BORDER_TRANSPARENT时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值。
**(6)borderValue:**代表边界值,默认是0。
通过以上分析可知,在OpenCV中使用函数cv2.warpAffine ()实现仿射变换,忽略其可选参数后的语法格式为:

dst=cv2.warpAffine (src ,M ,dsize)

5.3.1 平移

**示例:**将原始图像srcj向右移动100个像素、向下移动200个像素,其对应关系为:

dst (x,y)=src (x+100,y+200)

将表达式补充全:dst (x,y)=src (1·x+y·0+100,0·x+1·y+200)

根据表达式,则得出矩阵为:
M = [ 1 0 100 0 1 200 ] M=\left[\begin{matrix} 1&0&100\\ 0&1&200 \end{matrix}\right] M=[1001100200]
利用自定义转换矩阵完成图像平移:

import cv2
import numpy as np
img=cv2.imread ("lena.png")
height,width=img.shape[:2]
x=100
y=200
M=np.float32 ([[1,0,x],[0,1,y]])
move=cv2.warpAffine (img,M,(width,height) )
cv2.imshow ( "original" ,img)
cv2.imshow ("move",move)
cv2.waitKey ()
cv2.destroyAllWindows ()

结果:
在这里插入图片描述

5.3.2 旋转

通过cv2.getRotationMatrix2D()函数获取转换矩阵

retval=cv2.getRotationMatrix2D ( center,angle,scale)

**(1)center:**旋转中心点

**(2)angle:**旋转角度,正数表示逆时针旋转,负数表示顺时针旋转

**(3)scale:**变换尺度(缩放大小)

示例:图像中心为原点,逆时针旋转45°,图片缩小为原来的0.6倍

import cv2
img=cv2.imread ( "lena.png")
height,width=img.shape[:2]
M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6)
rotate=cv2.warpAffine (img,M,(width,height))
cv2.imshow("original",img)
cv2.imshow("rotation",rotate)
cv2.waitKey()
cv2.destroyAllWindows()

结果:
在这里插入图片描述

5.3.3 更复杂的仿射变换

retval=cv2.getAffineTransform ( src,dst)

**(1)src:**输入图像的三个点坐标

**(2)dst:**输出图像的三个点坐标

src和dst是包含三个二维数组的数组

示例:

import cv2
import numpy as np
img=cv2.imread ('lena.png')
rows,cols,ch=img.shape
p1=np.float32 ([[0,0],[cols-1,0],[0,rows-1]])
p2=np.float32([[0,rows*0.33],[cols*0.85,rows*0.25],[cols*0.15,rows*0.7]])
M=cv2.getAffineTransform (p1,p2)
dst=cv2.warpAffine (img,M,( cols,rows))
cv2.imshow ( "origianl",img)
cv2.imshow ( "result",dst)
cv2.waitKey ()
cv2.destroyAllWindows ()

结果:
在这里插入图片描述

四、透视cv2.warpPerspective ()

dst=cv2.warpPerspective (src,M,dsize[,flags[,borderMode[,borderValue]])

(1)src: 代表要透视的图像。
**(2)M:**代表一个3×3的变换矩阵。
**(3)dsize:**代表输出图像的尺寸大小。

用cv2.getPerspectiveTransform ()来生成其需要的变换矩阵

retval=cv2.getPerspectiveTransform (src,dst)

**(1)src:**输入图像的四个点坐标

**(2)dst:**输出图像的四个点坐标

五、重映射cv2.remap()

把一幅图像内的像素点放置到另一幅图像内的指定位置

dst=cv2.remap ( src,map1,map2,interpolation[,borderMode[ ,borderValue]])

**(1)src:**原始图像

**(2)map1:**表示(x,y)点的一个映射或者 表示CV_16SC2 ,CV_32FC1,CV_32FC2类型(x,y)点的x值。

**(3)map2:**当map1表示(x,y)时,该值为空。当map1表示(x,y)点的x值时,该值是CV_16UC1,CV_32FC1类型(x,y)点的y值。

**(4) lnterpolation:**代表插值方式,这里不支持lNTER_AREA方法。

说明:map1针对坐标x,map2针对坐标y,其值都是浮点数,map1指代像素点的列号,map2表示像素点的行号

5.5.1 复制

示例1:

import cv2
import numpy as np
img=cv2.imread ( "lena.png")
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),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 ()

结果:
在这里插入图片描述

说明:np.zeros()函数

numpy.zeros(shape, dtype=float)

**shape:**创建的新数组的形状(维度)。
**dtype:**创建新数组的数据类型。
**返回值:**给定维度的全零数组。

shape:

**img.shape[:2]:**取彩色图片的长,宽

**img.shape[:3]:**取彩色图片的长,宽,通道

**img.shape[0]:**图像的垂直尺寸(高度或长度)

**img.shape[1]:**图像的水平尺寸(高度)

**img.shape[2]:**图像的通道数

示例2:

import cv2
import numpy as np
img=np.random.randint (0,256,size=[4,5], dtype=np.uint8)
rows,cols=img.shape
mapx = np.zeros (img.shape, np.float32)
mapy = np.zeros (img.shape , np.float32)
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)
print ( "img=\n" , img)
print ( "mapx=\n" , mapx)
print ( "mapy=\n" , mapy)
print ("rst=\n" , rst)

itemset()函数

用于设置数组中特定位置的数值

itemset(j, z)         //“j“代表的是从左往右数,数组的第几个元素,”z“表示这个元素的值
itemset((x, y), z)    //(x,y)代表的就是矩阵中元素位置,‘z’为该元素的值

示例:

import numpy as np

a = np.random.randint(9, size=(3, 3))
print("a =", a)
a.itemset(4, 0)  # 将第4个数设置为0
print("a =", a)
a.itemset((2, 2), 9)  # 将位置为(2, 2)的数设置为9
print("a =", a)

结果:

a = [[1 3 6]
 [3 6 7]
 [4 1 1]]
 
a = [[1 3 6]
 [3 0 7]
 [4 1 1]]
 
a = [[1 3 6]
 [3 0 7]
 [4 1 9]]

5.5.2 绕x轴翻转

dst=cv2.remap ( src,map1,map2,interpolation[,borderMode[ ,borderValue]])

map1的值保持不变。

map2的值调整为“总行数-1-当前行号”

import cv2
import numpy as np
img=cv2 .imread ("lena.bmp")
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),j)
		mapy.itemset((i,j),rows-1-i)
rst=cv2.remap (img , mapx , mapy , cv2.INTER_LINEAR)
cv2 .imshow ("original" , img)
cv2.imshow ("result" , rst)
cv2.waitKey ()
cv2.destroyAllwindows ()

5.5.3 绕y轴翻转

如果想让图像绕着y轴翻转,意味着在映射过程中:

y坐标轴的值保持不变。
x坐标轴的值以y轴为对称轴进行交换。

反映在map1和map2上:

map2的值保持不变

map1的值调整为**“总列数-1-当前列号”。**

示例:

import cv2
import numpy as np
img=cv2.imread ( "lena.png")
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)
        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()

结果:
在这里插入图片描述

5.5.4 绕x轴,y轴翻转

map1的值调整为**"总列数-1-当前列号”**。

map2的值调整为**“总行数-1-当前行号”**。

示例:

import cv2
import numpy as np
img=cv2.imread("lena.png")
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)
        mapy.itemset ((i,j),rows-1-i)
rst=cv2.remap (img, mapx ,mapy, cv2.INTER_LINEAR)
cv2.imshow ( "original" , img)
cv2 .imshow ( "result" ,rst)
cv2.waitKey ()
cv2.destroyAllWindows ()

结果:
在这里插入图片描述

5.5.5 x轴、y轴互换

mapx的值调整为所在的行号。

mapy的值调整为所在的列号。

示例:

import cv2
import numpy as np
img=cv2 .imread ("lena.png" )
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)
        mapy.itemset ((i,j),j)
rst=cv2.remap (img,mapx , mapy, cv2.INTER_LINEAR)
cv2.imshow ( "original" ,img)
cv2.imshow ( "result" , rst)
cv2.waitKey ()
cv2.destroyAllWindows ()

结果:
在这里插入图片描述

5.5.6 图像的缩放

缩小图像后,可以将图像固定在围绕其中心的某个区域。

例如,将其x轴,y轴设置为:

在目标图像的x轴(0.25·x轴长度,0.75·x轴长度)区间内生成缩小图像; x轴其余区域的点取样自x轴上任意一点的值。

在目标图像的y轴(0.25·y轴长度,0.75· y轴长度)区间内生成缩小图像; y轴其余区域的点取样自y轴上任意一点的值。

示例:

import cv2
import numpy as np
img=cv2.imread ("lena.png")
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< j <0.75*rows:
            mapx.itemset ((i,j),2*(j - cols*0.25 ) + 0.5)
            mapy.itemset ((i,j),2* ( i - rows*0.25 ) + 0.5)
        else :
            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 ()

结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_56321457/article/details/125929180