OpenCV  4.10.0
开源计算机视觉
正在加载...
正在搜索...
没有匹配项
图像的几何变换

目标

  • 学会对图像应用不同的几何变换,如平移、旋转、仿射变换等。
  • 你将会看到这些函数: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')
assert img is not None, "文件无法读取,请使用 os.path.exists() 来检查"
res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC)
#或者
height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
从文件中加载图像。
void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR)
调整图像大小。

翻译

翻译是对象位置的移动。如果您知道了 (x,y) 方向的偏移,并将其设为 \((t_x,t_y)\),您可以按照如下所示创建变换矩阵 \(\textbf{M}\)

\[M = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \end{bmatrix}\]

您可以将其变成一个 np.float32 类型的 Numpy 数组,并将其传递给 cv.warpAffine() 函数。请参见以下示例,了解 (100,50) 的偏移

import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "文件无法读取,请使用 os.path.exists() 来检查"
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
void imshow(const String &winname, InputArray mat)
在指定窗口中显示图像。
int waitKey(int delay=0)
等待按下按键。
void destroyAllWindows()
销毁所有 HighGUI 窗口。
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar &borderValue=Scalar())
对图像应用仿射变换。

警告

cv.warpAffine() 函数的第三个参数是输出图像的大小,其形式应为 **(宽,高)**。记住,宽度 = 列数,且高度 = 行数。

请参见下方的结果

图像

旋转

对图像进行 \(\theta\) 角度的旋转,可通过以下形式的变换矩阵实现

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

但 OpenCV 提供了可调节旋转中心的缩放旋转,以便您可以在任何您喜欢的位置旋转。修改后的变换矩阵由下式给出

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

其中

\[\begin{array}{l} \alpha = 缩放 \cdot \cos \theta , \\ \beta = 缩放 \cdot \sin \theta \end{array}\]

要找到此变换矩阵,OpenCV 提供了一个函数,cv.getRotationMatrix2D。查看以下示例,它将图像相对于中心旋转 90 度,没有任何缩放。

img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "文件无法读取,请使用 os.path.exists() 来检查"
rows,cols = img.shape
# cols-1 和 rows-1 是坐标限制。
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))
Mat getRotationMatrix2D(Point2f center, double angle, double scale)
计算 2D 旋转的仿射矩阵。
Definition imgproc.hpp:2582

查看结果

图像

仿射变换

在仿射变换中,原始图像中的所有平行线在输出图像中仍将保持平行。要找到变换矩阵,我们需要从输入图像中获取三个点及其在输出图像中的对应位置。然后,cv.getAffineTransform 将创建一个 2x3 矩阵,然后将其传递给 cv.warpAffine

查看以下示例,并查看我选择的点(以绿色标示)

img = cv.imread('drawing.png')
assert img is not None, "文件无法读取,请使用 os.path.exists() 来检查"
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('输入')
plt.subplot(122),plt.imshow(dst),plt.title('输出')
plt.show()
Mat getAffineTransform(const Point2f src[], const Point2f dst[])
根据三对对应点计算仿射变换。

查看结果

图像

透视变换

对于透视变换,你需要一个 3x3 变换矩阵。即使经过变换,直线仍将保持直线。要找到此变换矩阵,你需要获取输入图像上的 4 个点,以及输出图像上的对应点。在这 4 个点中,其中 3 个点不应共线。然后,可以使用函数 cv.getPerspectiveTransform 找到变换矩阵。然后,使用此 3x3 变换矩阵应用 cv.warpPerspective

参见以下代码

img = cv.imread('sudoku.png')
assert img is not None, "文件无法读取,请使用 os.path.exists() 来检查"
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]])
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('输入')
plt.subplot(122),plt.imshow(dst),plt.title('输出')
plt.show()
Mat getPerspectiveTransform(InputArray src, InputArray dst, int solveMethod=DECOMP_LU)
从四对相应点计算透视变换。
void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar &borderValue=Scalar())
对图像应用透视变换。

结果

图像

其他资源

  1. "计算机视觉:算法及应用",理查德·斯泽利斯基

练习