目标
• 学习对图像进行各种变换,例如缩放、平移、旋转、仿射变换、透射变换。
• 将要学到的函数有: cv2.getPerspectiveTransform()
变换
OpenCV 提供了两个变换函数, cv2.warpAffine() 和 cv2.warpPerspective(),使用这两个函数你可以实现所有类型的变换。cv2.warpAffine() 接收的参数是2 × 3 的变换矩阵,而 cv2.warpPerspective() 接收的参数是 3 × 3 的变换矩阵。
扩展缩放只是改变图像的尺寸大小。 OpenCV 提供的函数 cv2.resize( )可以实现这个功能。图像的尺寸可以自己手动设置,你也可以指定缩放因子。(以下代码分别展示了用这两种方法改变图像的尺寸)
interpolation参数表示我们可以选择使用不同的插值方法。在缩放时我们推荐使用 cv2.INTER_AREA(像素区域重采样);在扩展时我们推荐使用cv2.INTER_CUBIC(三次插值,较慢) 和 cv2.INTER_LINEAR(线性插值,较快)。默认情况下所有改变图像尺寸大小的操作使用的插值方法都是 cv2.INTER_LINEA。
cv2.resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
参数说明:src:输入图像; dsize:输出图像的尺寸; det:输出图像; fx, fy是水平和垂直方向的缩放因子;interpolation:插值方法。用法如下:
img=cv2.imread('messi5.jpg')
# 第一种:直接设置输出图像的尺寸,所以不用设置缩放因子
height,width=img.shape[0:2]
img1=cv2.resize(img,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
#OR
# 第二种:设置缩放因子。因为后边设置了缩放因子,所以下面本应该是输出图像尺寸的参数为None
img2=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
平移就是将对象换一个位置。如果你要沿(x, y)方向移动,移动的距离是(tx, ty),你可以以下面的方式构建移动矩阵:
你可以使用 Numpy 数组构建这个矩阵(数据类型是 np.float32),然后把它传给 cv2.warpAffine( )函数。看看下面这个例子吧,它被移动了(100,50)个像素。
import numpy as np
import cv2
img = cv2.imread('chepai.jpg')
rows, cols = img.shape[0: 2]
M = np.float32([[1, 0, 100], [0, 1, 50]]) #通过numpy构建变换矩阵
dst = cv2.warpAffine(img, M, (cols, rows)) #实施变换,注意看第三个参数
cv2.imshow('img', img)
cv2.imshow('img_dst', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
警告:函数 cv2.warpAffine( ) 的第三个参数的是输出图像的大小,它的格式应该是图像的(宽,高)。应该记住的是图像的宽对应的是列数,高对应的是行数。
但是 OpenCV 允许你在任意地方进行旋转,但是旋转矩阵的形式应该修改为:
为了构建这个旋转矩阵,OpenCV 提供了cv2.getRotationMatrix2D()函数,下面的例子是在不缩放的情况下将图像旋转 90 度
import cv2
import numpy as np
img = cv2.imread('messi5.jpg', 0)
rows,cols = img.shape
# cols-1 and rows-1 are the coordinate limits.
# 这里的第一个参数为旋转中心,第二个为旋转角度,第三个为旋转后的缩放因子
# 可以通过设置旋转中心,缩放因子,以及窗口大小来防止旋转后超出边界的问题
M = cv2.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0), 90, 1)
# 第三个参数是输出图像的尺寸中心
dst = cv2.warpAffine(img, M, (cols,rows))
cv2.imshow('img', img)
cv2.imshow('img_dst', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
在仿射变换中,原图中所有的平行线在结果图像中同样平行。为了创建这个矩阵我们需要从原图像中找到三个点以及他们在输出图像中的位置。然后cv2.getAffineTransform()会创建一个 2x3 的矩阵,最后这个矩阵会被传给函数 cv2.warpAffine()。
来看看下面的例子,以及我选择的点(被标记为绿色的点)
import cv2
import numpy as np
from matplotlib import pyplot as plt
img=cv2.imread('drawing.png')
rows,cols,ch=img.shape
pts1=np.float32([[50,50],[200,50],[50,200]])
pts2=np.float32([[10,100],[200,50],[100,250]])
M=cv2.getAffineTransform(pts1,pts2)
dst=cv2.warpAffine(img,M,(cols,rows))
plt.subplot(121,plt.imshow(img),plt.title('Input'))
plt.subplot(121,plt.imshow(img),plt.title('Output'))
plt.show()
结果如下图:
对于透视变换,我们需要一个 3x3 变换矩阵。在变换前后直线还是直线。要构建这个变换矩阵,你需要在输入图像上找 4 个点,以及他们在输出图像上对应的位置。这四个点中的任意三个都不能共线。这个变换矩阵可以由cv2.getPerspectiveTransform( ) 函数构建。然后把这个矩阵传给函数cv2.warpPerspective()。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img=cv2.imread('sudokusmall.png')
rows,cols,ch=img.shape
# 输入、输出图像上相应的四个点
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M=cv2.getPerspectiveTransform(pts1,pts2)
dst=cv2.warpPerspective(img,M,(300,300))
plt.subplot(121,plt.imshow(img),plt.title('Input'))
plt.subplot(121,plt.imshow(img),plt.title('Output'))
plt.show()
结果如下:
参考文献:
1.《OpenCV-Python中文教程》(段力辉 译)
2. OpenCV-Python官方文档