1. 程式人生 > >【翻譯:OpenCV-Python教程】影象的幾何變換

【翻譯: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 輕靈劃譯 資料來源: