用OpenCV进行几何变换

256 阅读7分钟

随着你对OpenCV的图像处理的深入,你将会遇到一些只能用几何变换来解决的问题。 图像太大,形状不符合你的需要,或者你想旋转你的图像以获得某种数据的增强。

所有这些以及更多的问题都是图像处理中最基本的问题。OpenCV强大的工具包有许多可以旋转、调整大小和重塑图像的功能。因此,让我们来看看其中的一些。

在这篇文章中,我们涉及

  • 仿生变换
  • 非阿法尔变换

1.仿生变换

仿生变换是任何 保留了 碰撞性 和距离比的变换 ;它保留了直线点、直线和平面。这实质上意味着所有的形状都将保持不变,一个正方形仍然是一个正方形,一个长方形仍然是一个长方形等等。

仿生变换通常用于纠正非理想相机角度下的扭曲或变形。当我们说仿生变换时,通常是指以下技术。缩放、平移和旋转。

Data Science Visual

1.1 图像大小的调整

图像是由其大小和分辨率来描述的。分辨率由线性英寸中的像素或点的数量决定。分辨率越高,你的图像质量就越好。然而,图像的大小是由分辨率与图像的高度和宽度相乘而决定的。

正如我们之前提到的,有时我们想把一张图片放到网页上,或者也许我们正在为卷积神经网络处理图片。有些图片太大,有些图片太小,我们想调整它们的大小。幸运的是,在调整大小的时候,OpenCV使我们的工作变得简单了一些。

1.2 OpenCV调整大小

OpenCV的函数,cv2.resize()是一种非常优雅的调整图像大小的方法。该函数需要两个必要的参数,即我们要调整大小的源图像,以及所需输出图像的大小。你还可以定义沿水平和垂直轴的比例因子以及插值的类型。

插值发生在将图像从一个尺寸转移到另一个尺寸的过程中,而选择插值类型只是用来获得新的像素值的数学方法。现在我们知道了调整图片大小所需要的一切。让我们看一下代码,看看缩小尺寸是如何完成的。

import cv2
import numpy as np

image = cv2.imread('/content/drive/MyDrive/baboon.png', 0)
image_shape, image_width, image_height = image.shape, image.shape[1], image.shape[0]

print('Original image dimension is {}'.format(image_shape))
# => Original image dimension is (512, 512)

scale_coeficient = 25/100 #percent of how much we are downscaling
new_width = int(image_width*scale_coeficient) #int is used for rounding
new_height = int(image_height*scale_coeficient)
new_shape = (new_width, new_height)
new_image = cv2.resize(image, new_shape, interpolation = cv2.INTER_AREA)

print('Resized image dimension is {}'.format(new_shape))
# => Resized image dimension is (128, 128)

cv2.imshow(image)
cv2.imshow(new_image)

Resized image

1.3 OpenCV重塑

调整大小和重塑的区别在于,通过调整大小,你可以减少或增加图像的大小。通过重塑图像,你改变了形状但保留了尺寸。例如,你可以将一个图像的大小从100×100调整到20×20或1000×1000,通过重塑,你可以将它从100×100改为10×1000或20×500。

scale_coeficient_width = 0.6# => Reduced by 40% 
scale_coeficient_height = 1.4 # => Increased by 40% 
new_width = int(image_width*scale_coeficient_width)
new_height = int(image_height*scale_coeficient_height)
new_shape = (new_width, new_height)
new_image = cv2.resize(image, new_shape)

print(Reshaped image dimension is {}'.format(new_shape))
# => Reshaped image dimension is (716,307)

Resized image

1.4 图像旋转

图像旋转是除了调整大小之外,图像处理中最基本的几何变换。它有许多应用。它被用于图像校正、图像对齐、数据增强等等。所以让我们在OpenCV中实现它。

OpenCV库中的旋转可以通过多种方式完成。比较简单的是通过使用cv2.rotate()函数。这个函数需要两个参数,一个是你要旋转的图像的源,另一个是代表旋转方向的标志。

image = cv2.imread('/content/drive/MyDrive/lena_color.png', 0)
image_rotated = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
cv2_imshow(image)
cv2_imshow(image_rotated)

Lena Rotation

我们可以看到,图片被顺时针旋转了90度。你可以传递给该函数的其他参数有:cv2.ROTATE_90_COUNTERCLOCKWISE、cv2.ROTATE_180等。

图像旋转也可以通过使用一个旋转矩阵来完成,该矩阵定义了你想如何旋转图片。这个矩阵通常是这样的。[[cos(theta) -sin(theta)] [sin(theta) cos(theta)]],其中 theta 是旋转的角度。不要让数学吓倒你,总是有一个OpenCV函数来帮助我们。旋转矩阵是用getRotationMatrix2D()函数定义的。

该函数需要三个参数:旋转中心、旋转角度和刻度。刻度是 一个各向同性的比例因子,根据所提供的值将图像向上或向下缩放。源图像和旋转矩阵被传递给warpAffine()函数,该函数对原始图像进行旋转。

import cv2

image = cv2.imread('/content/drive/MyDrive/lena_color.png', 0)

# Dividing height and width by 2 to get the center of the image
height, width = image.shape
center = (width/2, height/2)

#Defining a rotation matrix
rotate_matrix = cv2.getRotationMatrix2D(center=center, angle=65, scale=1)
#warpAffine takes three arguments image we want to rotate, rotation matrix, and size of an image
rotated_image = cv2.warpAffine(src=image, M=rotate_matrix, dsize=(width, height))
cv2.imshow(rotated_image)

Lena Rotate 2

1.4 图像平移

图像平移是一个将图像移动到其他方向或坐标的过程,这样,图像中的每一个点都以相同的方向、相同的距离移动,形成一个图像。换句话说,平移是一种技术,它允许我们在水平、垂直或对角线上移动图像。

为了进行平移,我们需要确定所谓的平移矩阵。

它是一个2×3的矩阵,看起来像这样。[[1, 0, 'Tx'], [0, 1, 'Ty']]。Tx代表我们希望图片在水平方向上移动的距离,自然,Ty被描述为我们的图片将在垂直方向上移动的距离。闲话少说,让我们跳进代码。

import cv2

image = cv2.imread('/content/drive/MyDrive/lena_color.png', 0)

# Dividing height and width by 2 to get the center of the image
height, width = image.shape
center = (width/2, height/2)

#Defining a rotation matrix
rotate_matrix = cv2.getRotationMatrix2D(center=center, angle=65, scale=1)
#warpAffine takes three arguments image we want to rotate, rotation matrix, and size of an image
rotated_image = cv2.warpAffine(src=image, M=rotate_matrix, dsize=(width, height))
cv2.imshow(rotated_image)

Translation

正如我们所看到的,我们已经将原始图片的长度和高度移动了四分之一。

2.非阿芬变换

现在让我们来看看非正弦变换。非正弦变换是一种平行线组不需要保持平行的方法。这意味着图像的形状、视点和视角会发生变化。它们向我们展示了随着观察者视角的改变,被感知的物体是如何变化的。

2.1 使用OpenCV改变视角

假设我们有一张从60度角度拍摄的图片,但我们想把它变成从鸟的视角拍摄的图片。

Non-Affine Transformations

我们将通过对图像进行非线性变换来获得所需的图片,所以让我们深入了解一下我们是如何做到这一点的。

img = cv2.imread('/content/bird.png')
print(img.shape) #(239,231)
cv2_imshow(img)

Road Image

这是我们想要改变成鸟的视角的图片。正如我们所看到的,那些笔直和平行的线条实际上看起来并不是这样的。首先,我们需要做的是找到以下各点的坐标(使用cv2.imshow()函数,并将鼠标悬停在你想知道坐标的点上)。

Road Image 2

coords = np.float32([[83,67],[179,68],[31,228]])

现在,我们希望我们选定的点是我们新图像的角。基本上,我们要把左上角的点作为新形成的图像的(0,0)坐标,右上角为(我们图像的宽度,0),左下角为(0,高度),右下角为(宽度,高度)。我们可以自由选择我们新图像的宽度和高度。

img = cv2.imread('/content/bird.png')
print(img.shape[:2]) #(239,231)
cv2_imshow(img)

original_coords = np.float32([[83,67],[179,67],[31,228],[289,228]]) # coordinates of our points

height,width = 200,200 #width and height of our new image
new_image_coords = np.float32([[0,0],[width,0],[0,height],[width,height]]) #setting our points as corners of our new image
P = cv2.getPerspectiveTransform(original_coords,new_image_coords) # This Function calculates the Transformation matrix,it accepts 2 parameters(original coordinates and new coordinates)
perspective_image = cv2.warpPerspective(img,P,(width,height)) # Function that warps our image,First parameter is the original image, second one is transformation matrix, third one is a tuple with width and height of our new image
cv2_imshow(perspective_image)

Transformed Image

正如我们所看到的,我们已经成功地将图像变成了鸟的视角。它在汽车行业、拍摄和安全方面有很大的应用。

总结

几何变换在图像处理中确实很有用,但更高级的程序需要有强大的数学基础。在这篇文章中,我们介绍了它的一些基本原理,并鼓励我们对这个问题进行更多的研究。如前所述,几何变换在图像处理和计算机视觉中有许多应用。此外,我们还邀请你继续我们的图像处理系列文章。