【翻译:OpenCV-Python教程】图像的几何变换

⚠️这个系列是自己瞎翻的,文法很丑,主要靠意会,跳着跳着捡重要的部分翻,翻错了不负责,就这样哈。

⚠️基于3.4.3,Geometric Transformations of Images,原文

目标

  • 学会对图像应用不同的几何变换,比如平移、旋转、仿射变换等等。
  • 你会遇到这些方法: cv.getPerspectiveTransform

变换

OpenCV提供了两个转换方法,cv.warpAffinecv.warpPerspective,用他们你可以完成所有类型的转换。cv.warpAffine 用了 2x3 转换矩阵作为参数,而 cv.warpPerspective 采用了 3x3 转换矩阵作为参数。

放缩

缩放只是调整图像大小。OpenCV自带了一个方法 cv.resize() 来做这件事。可以手动指定图像的大小,也可以指定缩放系数。使用不同的重写方法,推荐的重写方法是用来缩小的 cv.INTER_AREA ,以及用于缩放的 cv.INTER_CUBIC (慢)和 cv.INTER_LINEAR 。默认的情况下,所有调整大小使用的都是 cv.INTER_LINEAR 。你可以使用以下方法之一调整输入图像的大小:

import numpy as np
import cv2 as cv

img = cv.imread('messi5.jpg')
res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC)

#OR

height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)

平移映射

平移映射就是在改变物体的位置,比如你知道 (x,y) ,要把它偏移到 (tx,ty) 的位置,你就要创造一个映射矩阵 M 如下:

M = \begin{bmatrix} 1&0&tx \\ 0&1&ty \\ \end{bmatrix}

你可以把它装成一个 np.float32 型的Numpy数组,并且传入 cv.warpAffine() 方法中,看以下的代码(把(0,0))转换到(100,50):

import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()

警告

cv.warpAffine() 方法的第三个参数是以**(宽, 高)**格式表示的输出图像的大小,记住宽等于列数,高等于行数。

看以下结果

translation.jpg

旋转

要旋转一个图像 θ 角度,要通过这种格式的一个映射矩阵:

M = \begin{bmatrix} cos\theta &-sin\theta \\ sin\theta&cos\theta \end{bmatrix}

但 OpenCV 提供了扩展过的旋转,通过可调整的旋转中心,你可以在你想要的任意地点开始旋转。修改过的映射矩阵给出如下:

\begin{bmatrix} \alpha &\beta & (1-\alpha) \times center.x - \beta \times center.y\\-\beta&\alpha&(1-\alpha) \times center.y + \beta \times center.x \end{bmatrix}

其中

α=scale⋅cosθ,β=scale⋅sinθ

要找出这个映射矩阵,OpenCV 提供了一个方法,cv.getRotationMatrix2D 。查看以下例子,以图像中心旋转图像90度,并且不做任何拉伸。

img = cv.imread('messi5.jpg',0)
rows,cols = img.shape
# cols-1 and rows-1 are the coordinate limits.
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))

看下面的结果:

rotation.jpg

仿射变换

在仿射变换中,所有原图中的平行线会在输出图像中依然保持平行。要找到这个映射矩阵,我们需要从输入图像中三个点的位置,以及在输出图像中对应的位置。然后用 cv.getAffineTransform 会创建一个 2x3 矩阵,用来当做参数传入 cv.warpAffine 

查看下面的例子,并且也看一下我选择的点(用绿色标记出来了):

img = cv.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 = cv.getAffineTransform(pts1,pts2)
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

看结果:

affine.jpg

透视变换

要完成透视变换,你需要一个 3x3 的映射矩阵,直线会在映射之后保持笔直。要找到这个映射矩阵,你需要四个原图上的点,以及它们在转换后图像上对应的位置。在这四个点中,其中任意三个不能共线。

然后这个映射矩阵可以通过方法 cv.getPerspectiveTransform 来拿到,然后再把这个 3x3 映射矩阵应用于 cv.warpPerspective 方法上。

看以下代码:

img = cv.imread('sudoku.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 = cv.getPerspectiveTransform(pts1,pts2)
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

结果:

perspective.jpg

额外资源

  • "Computer Vision: Algorithms and Applications", Richard Szeliski (计算机视觉:算法和应用)

Exercises


上篇:【翻译:OpenCV-Python教程】改变色彩空间

下篇:【翻译:OpenCV-Python教程】图像阈值

翻译OpenCV-Python教程 图像阈值
Translate OpenCV-Python tutorial image threshold

猜你喜欢

转载自blog.csdn.net/ssybc/article/details/84308574