本文介绍几种常见的图像几何变换方法。

1. 图像缩放

图像缩放就是将源图像中的像素点经过算法映射到目标图像的像素点的过程,即找出目标图像中的像素点Pd(Xd,Yd)对应的源图像的像素点Ps(Xs,Ys),然后将源图像像素点填充到对应目标图像的像素点,最终形成目标图像。常见的图像缩放算法有最邻近点插值法、双线性插值法和BiCubic卷积插值法等。

在OpenCV中提供函数cv2.resize()实现对图像的缩放,该函数原型如下:

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

参数说明:
dst:输出的目标图像,其类型与src相同,大小为dsize(当该值非零时),或者可以通过src.size()、fx、fy计算得到;
src:需要进行缩放的原始图像;
dsize:输出图像的大小;
x:水平方向的缩放比例;
y:垂直方向的缩放比例;
interpolation:插值方式。

插值是指图像在进行几何处理时,给无法直接通过映射得到的值的像素点赋值。比如,将原始图像放大为原来的2倍,必然会多出一些无法被直接映射值的像素点,对于这些像素点,插值方式决定了如何确定它们的值。当缩小图像时,使用区域插值方式(INTER_AREA)能够得到最好的效果;当放大图像时,使用三次样条插值(INTER_CUBIC)方式和双线性插值(INTER_LINEAR)方式都能够取得较好的效果。三次样条插值方式速度较慢,双线性插值方式速度相对较快且效果并不逊色。

测试代码如下:

img = cv2.imread("lenna.jpg")height, width = img.shape[:2]  # 获取图像的高度和宽度cv2.imshow('src', img)# 缩放到原来的二分之一img_test1 = cv2.resize(img, (int(height / 2), int(width / 2)))cv2.imshow('resize1', img_test1)# 最近邻插值法缩放,缩放到原来的四分之一img_test2 = cv2.resize(img, (0, 0), fx=0.25, fy=0.25, interpolation=cv2.INTER_NEAREST)cv2.imshow('resize2', img_test2)cv2.waitKey()cv2.destroyAllWindows()

效果如下:

2 图像旋转

图像旋转是指将图像绕某个中心点旋转一定角度后,得到一幅新的图像。

Python中imutils工具包提供了如下函数实现图像旋转:
imutils.rotate:实现了在旋转完成图分辨率不调整的情况下,对原图像内容旋转,可能局部丢失,缺失部分用黑色填充。
imutils.rotate_bound:保持原图完整,旋转完成图分辨率会改变。

测试代码如下:

 import imutilsimg = cv2.imread("lenna.jpg")cv2.imshow('src', img)# 旋转45度,可能局部丢失,缺失部分用黑色填充rot1 = imutils.rotate(img, angle=45)cv2.imshow("Rotated1", rot1)# 旋转45度,保持原图完整,旋转完成图分辨率会改变rot2 = imutils.rotate_bound(img, angle=45)cv2.imshow("Rotated2", rot2)cv2.waitKey()cv2.destroyAllWindows()

效果如下:

3 图像翻转

翻转也称镜像,是指将图像沿轴线进行轴对称变换。水平镜像是将图像沿垂直中轴线进行左右翻转,垂直镜像是将图像沿水平中轴线进行上下翻转,水平垂直镜像是水平镜像和垂直镜像的叠加。

OpenCV提供了cv2.flip函数,可以将图像沿水平方向、垂直方向、或水平/垂直方向同时进行翻转。其函数原型如下:

cv2.flip(src, flipCode[, dst]) -> dst

参数说明:
scr:变换操作的输入图像;
flipCode:控制参数,整型(int),flipCode>0 水平翻转,flipCode=0 垂直翻转,flipCode<0 水平和垂直翻转;
dst:变换操作的输出图像,可选项。

测试代码如下:

img = cv2.imread("lenna.jpg")  # 读取彩色图像(BGR)imgFlip1 = cv2.flip(img, 0)  # 垂直翻转imgFlip2 = cv2.flip(img, 1)  # 水平翻转imgFlip3 = cv2.flip(img, -1)  # 水平和垂直翻转plt.subplot(221), plt.axis('off'), plt.title("Original")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))  # 原始图像plt.subplot(222), plt.axis('off'), plt.title("Flipped Horizontally")plt.imshow(cv2.cvtColor(imgFlip2, cv2.COLOR_BGR2RGB))  # 水平翻转plt.subplot(223), plt.axis('off'), plt.title("Flipped Vertically")plt.imshow(cv2.cvtColor(imgFlip1, cv2.COLOR_BGR2RGB))  # 垂直翻转plt.subplot(224), plt.axis('off'), plt.title("Flipped Horizontally & Vertically")plt.imshow(cv2.cvtColor(imgFlip3, cv2.COLOR_BGR2RGB))  # 水平垂直翻转plt.show()

效果如下:

4 图像平移

图像的平移就是将图像上的像素点整体移动。图像平移首先定义平移矩阵M,再调用warpAffine()函数实现平移,函数原型如下:

M = np.float32([[1, 0, x], [0, 1, y]])shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

测试代码如下:

img = cv2.imread('lenna.jpg')image = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)# 图像下、上、右、左平移M = np.float32([[1, 0, 0], [0, 1, 100]])img1 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))M = np.float32([[1, 0, 0], [0, 1, -100]])img2 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))M = np.float32([[1, 0, 100], [0, 1, 0]])img3 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))M = np.float32([[1, 0, -100], [0, 1, 0]])img4 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))# 显示图形titles = [ 'Image-down', 'Image-up', 'Image-right', 'Image-left']  images = [img1, img2, img3, img4]  for i in range(4):     plt.subplot(2,2,i+1), plt.imshow(images[i]), plt.title(titles[i])     plt.xticks([]),plt.yticks([])  plt.show()  

效果如下: