【翻譯: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教程】圖像閾值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章