dst = cv2.resize(src, dsize[, fx[, fy[, interpolation]]])
目标图像 dst 的大小既可以通过参数 dsize 决定,也可以通过 fx 和 fy 决定。
当 cv2.resize() 参数列表中指定了 dsize 参数,那么无论是否指定了 fx 和 fy 参数,图像的输出大小都由 dsize 决定。
当 cv2.resize() 参数中 dsize = None 时,图像的输出大小由 fx 和 fy 参数决定。此时输出图像的大小为:
d s i z e = S i z e ( r o u n d ( f x ∗ s r c . w i d t h ) , r o u n d ( f x ∗ s r c . h e i g h t ) ) dsize = Size(round(fx*src.width), round(fx*src.height)) dsize=Size(round(fx∗src.width),round(fx∗src.height))
类型 | 说明 |
---|---|
cv2.INTER_LINEAR | 双线性插值(默认) |
cv2.INTER_NEAREST | 最临近插值 |
cv2.INTER_CUBIC | 三次样条插值 |
cv2.INTER_AREA | 区域插值,类似最临近插值 |
cv2.INTER_LANCZOS4 | 使用 8x8 近邻的 Lancozos 插值方式 |
cv2.INTER_MAX | 插值编码掩码 |
import cv2
dog = cv2.imread('dog.jpg')
height, width = dog.shape[:2]
# dsize 决定
dog1 = cv2.resize(dog, (int(width * 0.5), int(height)))
# fx fy 决定
dog2 = cv2.resize(dog,None,fx=0.5,fy=1)
cv2.imshow('dog', dog)
cv2.imshow('dog1', dog1)
cv2.imshow('dog2', dog2)
cv2.waitKey()
cv2.destroyAllWindows()
采用两种方式,将图像的宽度变小为原来的 0.5 倍如下:
dst = cv2.flip(src, flipCode)
import cv2
dog = cv2.imread('dog.jpg')
x = cv2.flip(dog,0)
y = cv2.flip(dog,1)
xy = cv2.flip(dog,-1)
cv2.imshow('dog', dog)
cv2.imshow('x', x)
cv2.imshow('y', y)
cv2.imshow('xy', xy)
cv2.waitKey()
cv2.destroyAllWindows()
将图像分别绕 x, y, xy 轴旋转,结果如下:
仿射指的是图像通过一些列的几何变换来实现平移、旋转等多种操作。仿射可以保持图像的平直性和平行性。平行性指的是图像在仿射变换后,平行线仍然是平行线;平直性指的是图像在仿射变换后,直线仍然是直线。
dst = cv2.warpAffine(src, M, dsize[, flags[, borderMode[, borderValue]]])
原图与 M 矩阵的变换公式具体为:
d s t ( x , y ) = s r c ( M 11 x + M 12 y + M 13 , M 21 x + M 22 y + M 23 ) dst(x,y)=src(M_{11}x+M_{12}y+M_{13},M_{21}x+M_{22}y+M_{23}) dst(x,y)=src(M11x+M12y+M13,M21x+M22y+M23)
如果把图像向左平移 100 个像素,向上平移 200 个像素,根据公式(2)我们可以得知: d s t ( x , y ) = s r c ( x − 100 , y − 200 ) dst(x,y)=src(x-100,y-200) dst(x,y)=src(x−100,y−200),所以矩阵 M 的值应该为 [[1, 0, -100],[0, 1, -200]] 。
import cv2
import numpy as np
dog = cv2.imread('dog.jpg')
height,width = dog.shape[:2]
M = np.float32([[1,0,-100],[0,1,-200]])
dog2=cv2.warpAffine(dog,M,(width,height))
cv2.imshow('dog', dog)
cv2.imshow('dog2', dog2)
cv2.waitKey()
cv2.destroyAllWindows()
使用 cv2.warpAffine() 函数进行图像旋转时,需要设定图像的旋转中心、旋转角度等其他参数,所以 M 矩阵的设置稍微复杂,但是可以通过 cv2.getRotationMatrix2D() 函数来获取变换矩阵 M 。
retval = getRotationMatrix2D(center, angle, scale)
import cv2
dog = cv2.imread('dog.jpg')
height,width = dog.shape[:2]
M = cv2.getRotationMatrix2D((height//2,width//2),30,0.5)
dog2=cv2.warpAffine(dog,M,(width,height))
cv2.imshow('dog', dog)
cv2.imshow('dog2', dog2)
cv2.waitKey()
cv2.destroyAllWindows()
以图像中心为旋转点,逆时针旋转 30°,缩小一半的图像结果为:
一个矩形图像有左上角,右上角,左下角,右下角四个点,只要改变左上角,右上角,左下角这三个点的位置,图像便可以进行复杂的放射变换,变换为任意的平行四边形。可以通过函数 cv2.getAffineTransform(src, dst) 函数来设置变换矩阵 M,将 src 原图的点映射到 dst 中。
retval = cv2.getAffineTransform(src, dst)
import numpy as np
import cv2
dog = cv2.imread('dog.jpg')
height,width = dog.shape[:2]
src = np.float32([[0,0],[width-1,0],[0,height-1]])
dst = np.float32([[0,height*0.3],[width*0.5,height*0.3],[width*0.1,height*0.8]])
M = cv2.getAffineTransform(src,dst)
dog2=cv2.warpAffine(dog,M,(width,height))
cv2.imshow('dog', dog)
cv2.imshow('dog2', dog2)
cv2.waitKey()
cv2.destroyAllWindows()
以代码结果为:
平行四边形仿射是将图像变换为任意平行四边形,而透视则把图像变换为任意四边形。
dst = warpPerspective(src, M, dsize[, flags[, borderMode[, borderValue]]])
retval = cv2.getPerspectiveTransform(src, dst)
import cv2
import numpy as np
dog = cv2.imread('dog.jpg')
height,width = dog.shape[:2]
src = np.float32([[0,0],[width-1,0],[0,height-1],[width-1,height-1]])
dst = np.float32([[50,50],[width-150,50],[50,height-50],[width-50,height-50]])
M = cv2.getPerspectiveTransform(src,dst)
dog2 = cv2.warpPerspective(dog,M,(width,height))
cv2.imshow('dog', dog)
cv2.imshow('dog2', dog2)
cv2.waitKey()
cv2.destroyAllWindows()
把一幅图像内的像素点放置到另一个图像内的指定位置,这个过程就叫做重映射。在构建新图像时,需要确定新图像中每个像素点在原始图像的位置。所以映射函数的作用就是查找新图像像素在原始图像内的位置,该过程将新图像像素映射到原始图像内,因此称为反向映射。
dst = cv2.remap(src, map1, map2, interpolation[, borderMode[, borderValue]])
(x, y) 表示 dst 图像像素在 src 图像内的位置,OpenCV 中以图像的左上角为原点,左上角到右上角的方向为 x 轴正方向,左上角到左上角的方向为 y 轴正方向;
map1 和 map2 就是用来说明方向映射的参数,当它们都采用单值写法时,map1 表示 (x, y) 中 x 轴的映射位置,map2 表示 (x, y) 中 y 轴的映射位置,所以 map1 有时也写作 mapx, map2 有时也写作 mapy。
为什么需要插值?因为 map1 和 map2 参数的值是浮点数,所以目标图像 dst 可以反向映射回一个非整数的位置,这意味着目标图像可以反向映射到原始图像的两个像素点中间,而两个像素点之间的并没有像素值,这时就需要采用插值方式来填充目标图像。
通过自定义映射函数,可以实现不同的形式的重映射,例如图像的翻转,图像的缩放等,因此重映射函数可以实现本章节前面的缩放、翻转等其他功能。
设有一个 5x5 大小的图像,现需要将目标图像中所有像素点绕 x 轴翻转。即
import cv2
import numpy as np
img = np.random.randint(0,256,size=(5,5),dtype=np.uint8)
height_y,width_x = img.shape
mapx = np.ones(img.shape,dtype=np.float32)
mapy = np.ones(img.shape,dtype=np.float32)
for i in range(height_y):
for j in range(width_x):
mapx.itemset((i,j),j)
mapy.itemset((i,j),height_y - 1 - i)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print('img=\n',img)
print('mapx=\n',mapx)
print('mapy=\n',mapy)
print('dst=\n',dst)
运行结果如下:
设有一个 5x5 大小的图像,现需要将目标图像中所有像素点绕 y 轴翻转。即
import cv2
import numpy as np
img = np.random.randint(0,256,size=(5,5),dtype=np.uint8)
height_y,width_x = img.shape
mapx = np.ones(img.shape,dtype=np.float32)
mapy = np.ones(img.shape,dtype=np.float32)
for i in range(height_y):
for j in range(width_x):
mapx.itemset((i,j),width_x - 1 - j)
mapy.itemset((i,j),i)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print('img=\n',img)
print('mapx=\n',mapx)
print('mapy=\n',mapy)
print('dst=\n',dst)
运行结果如下:
设有一个 5x5 大小的图像,现需要将目标图像中所有像素点绕 x 和 y 轴翻转。即
import cv2
import numpy as np
img = np.random.randint(0,256,size=(5,5),dtype=np.uint8)
height_y,width_x = img.shape
mapx = np.ones(img.shape,dtype=np.float32)
mapy = np.ones(img.shape,dtype=np.float32)
for i in range(height_y):
for j in range(width_x):
mapx.itemset((i,j),width_x - 1 - j)
mapy.itemset((i,j),height_y - 1 - i)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print('img=\n',img)
print('mapx=\n',mapx)
print('mapy=\n',mapy)
print('dst=\n',dst)
运行结果如下:
设有一个 5x5 大小的图像,现需要将目标图像中 x 和 y 轴互换。即
import cv2
import numpy as np
img = np.random.randint(0,256,size=(5,5),dtype=np.uint8)
height_y,width_x = img.shape
mapx = np.ones(img.shape,dtype=np.float32)
mapy = np.ones(img.shape,dtype=np.float32)
for i in range(height_y):
for j in range(width_x):
mapx.itemset((i,j),i)
mapy.itemset((i,j),j)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print('img=\n',img)
print('mapx=\n',mapx)
print('mapy=\n',mapy)
print('dst=\n',dst)
运行结果如下:
设有一个 5x5 大小的图像,现需要将目标图像中所有像素点都映射为原始图像第1行2列的像素值。即
import cv2
import numpy as np
img = np.random.randint(0,256,size=(5,5),dtype=np.uint8)
mapx = np.ones(img.shape,dtype=np.float32)*2
mapy = np.ones(img.shape,dtype=np.float32)*1
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print('img=\n',img)
print('mapx=\n',mapx)
print('mapy=\n',mapy)
print('dst=\n',dst)
运行结果如下:
设有一个 5x5 大小的图像,现需要将目标图像中所有像素点都映射为原始图像对应位置的像素值。即
import cv2
import numpy as np
img = np.random.randint(0,256,size=(5,5),dtype=np.uint8)
height_y,width_x = img.shape
mapx = np.ones(img.shape,dtype=np.float32)
mapy = np.ones(img.shape,dtype=np.float32)
for i in range(height_y):
for j in range(width_x):
mapx.itemset((i,j),j) # mapx 表示的是 x 轴,即图像的 width_x 域,所以设置为 j
mapy.itemset((i,j),i) # mapy 表示的是 y 轴,即图像的 height_y 域,所以设置为 i
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print('img=\n',img)
print('mapx=\n',mapx)
print('mapy=\n',mapy)
print('dst=\n',dst)
运行结果如下: