OpenCV-Python系列之影象的幾何變換
影象翻轉
影象翻轉有多種方式,包括使用固定的API以及使用numpy進行操作等等。
使用flip函式實現翻轉
函式原型:
flip(src, flipCode[, dst]) -> dst
· src 輸入圖片
· flipCode 翻轉程式碼
· 1 水平翻轉 Horizontally (圖片第二維度是column)
· 0 垂直翻轉 *Vertically * (圖片第一維是row)
· -1 同時水平翻轉與垂直反轉 Horizontally & Vertically
我們來看程式碼:
import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('cat.jpg') def bgr2rbg(img): ''' 將顏色空間從BGR轉換為RBG ''' return img[:,:,::-1] # 水平翻轉 flip_h = cv2.flip(img, 1) # 垂直翻轉 flip_v = cv2.flip(img, 0) # 同時水平翻轉與垂直翻轉 flip_hv = cv2.flip(img, -1) plt.subplot(221) plt.title('SRC') plt.imshow(bgr2rbg(img)) plt.subplot(222) plt.title('Horizontally') plt.imshow(bgr2rbg(flip_h)) plt.subplot(223) plt.title('Vertically') plt.imshow(bgr2rbg(flip_v)) plt.subplot(224) plt.title('Horizontally & Vertically') plt.imshow(bgr2rbg(flip_hv)) plt.show()
程式碼實現了三種翻轉的方式:水平翻轉、垂直翻轉以及水平垂直翻轉。我們來看效果:
使用numpy的索引進行影象反轉
我們剛剛使用了OpenCV的API進行了影象翻轉的操作,實際上僅僅使用numpy也是相當的方便,在numpy中使用img[:,::-1]則代表為矩陣水平翻轉,使用img[::-1]則為矩陣垂直翻轉,所以我們不難看出,水平與垂直同時翻轉則為img[::-1, ::-1]。
我們來看程式碼:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('cat.jpg') height,width,channel = img.shape # 水平翻轉 flip_h = img[:,::-1] # 垂直翻轉 flip_v = img[::-1] # 水平垂直同時翻轉 flip_hv = img[::-1, ::-1] def bgr2rbg(img): ''' 將顏色空間從BGR轉換為RBG ''' return img[:,:,::-1] plt.subplot(221) plt.title('SRC') plt.imshow(bgr2rbg(img)) plt.subplot(222) plt.title('Horizontally') plt.imshow(bgr2rbg(flip_h)) plt.subplot(223) plt.title('Vertically') plt.imshow(bgr2rbg(flip_v)) plt.subplot(224) plt.title('Horizontally & Vertically') plt.imshow(bgr2rbg(flip_hv)) plt.show()
效果仍然相同:
利用wrapAffine實現翻轉
事實上,利用OpenCV的wrapAffine也可以進行影象的翻轉,在上一節的教程中,我們已經講述了利用相關函式實現旋轉以及平移的操作,從本質上來講,它們的原理基本上相同,現在我們來看一下用它實現翻轉的原理:
我們假設width 代表影象的寬度 height代表影象的高度:
水平翻轉的變換矩陣為:
垂直翻轉的變換矩陣則為:
如若同時進行水平翻轉與垂直翻轉,那麼有:
據此我們來看實現的程式碼:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('cat.jpg') height,width,channel = img.shape # 水平翻轉 M1 = np.float32([[-1, 0, width], [0, 1, 0]]) flip_h = cv2.warpAffine(img, M1, (width, height)) # 垂直翻轉 M2 = np.float32([[1, 0, 0], [0, -1, height]]) flip_v = cv2.warpAffine(img, M2, (width, height)) # 水平垂直同時翻轉 M3 = np.float32([[-1, 0, width], [0, -1, height]]) flip_hv = cv2.warpAffine(img, M3, (width, height)) def bgr2rbg(img): ''' 將顏色空間從BGR轉換為RBG ''' return img[:,:,::-1] plt.subplot(221) plt.title('SRC') plt.imshow(bgr2rbg(img)) plt.subplot(222) plt.title('Horizontally') plt.imshow(bgr2rbg(flip_h)) plt.subplot(223) plt.title('Vertically') plt.imshow(bgr2rbg(flip_v)) plt.subplot(224) plt.title('Horizontally & Vertically') plt.imshow(bgr2rbg(flip_hv)) plt.show()
- plt.show()
實驗效果仍然跟之前兩種方法的一樣,在這裡就不一一演示了。
仿射變換
實際上,之前我們講過的縮放旋轉平移以及剛剛講述的翻轉它們本質上都屬於影象的仿射變換,現在我們討論一個函式,算是對仿射變換的一個總結:
M=cv2.GetAffineTransform(src, dst)
src:原始影象中的三個點的座標
dst:變換後的這三個點對應的座標
M:根據三個對應點求出的仿射變換矩陣
在前面原理的講述中,我們也知道了仿射變換通常是對於一個2*3的矩陣:
考慮到我們要使用矩陣 和 對二維向量 做變換, 所以也能表示為下列形式:
現在我們來大致看一下程式碼:
import cv2 as cv import matplotlib.pyplot as plt import numpy as np img = cv.imread('cat.jpg') 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()
我們可以看到一隻扭曲的貓。
Perspective Transformation
我們平時可能用過各種掃描的軟體,比如像掃描全能王這種軟體,我們在使用的過程中會發現,即便是你圖片拍的比較斜,軟體後期仍然可以對你的圖片進行校正,然後從而進行影象增強處理,這種影象矯正操作,實際上就是影象的Perspective變換(關鍵字遮蔽,大家自行了解)。現在的很多案例比如車牌識別,答題卡判卷以及文字識別等等,它們都是以影象的Perspective變換將影象矯正之後才進行下一步的操作的。
之前我們在 仿射變換簡介 裡面講解的是仿射變換AffineTransform。那麼Perspective變換與仿射變換之間最大的區別是什麼呢?仿射變換可以用三個點確定一個變換,而Perspective換則不一定,所以可以將仿射變換作為投影變換的一個特例。 需要四個點,才能確定Perspective變換。
OpenCV提供了warpPerspective( )函式來實現圖片的Perspective變換,只需要輸入梯形四個頂點的座標和目標畫布四個角的座標,即可自動完成轉換。核心程式碼只有兩行:首先讀取兩個座標陣列,計算變換矩陣;然後根據變換矩陣對原圖進行Perspective變換,並輸出到目標畫布。
函式原型:
cv2.getPerspectiveTransform(src, dst) → retval
src:源影象中待測矩形的四點座標
sdt:目標影象中矩形的四點座標
返回由源影象中矩形到目標影象矩形變換的矩陣,接下來引出下面這個函式:
cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
src:輸入影象
M:變換矩陣
dsize:目標影象shape
flags:插值方式,interpolation方法INTER_LINEAR或INTER_NEAREST
borderMode:邊界補償方式,BORDER_CONSTANT or BORDER_REPLICATE
borderValue:邊界補償大小,常值,預設為0
或者我們可以使用另一個函式:
cv2.perspectiveTransform(src, m[, dst]) → dst
src:輸入的2通道或者3通道的圖片
m:變換矩陣
這兩個函式返回的相同的規格的圖片。
對於Perspective變換,我們需要3x3變換矩陣。即使在轉換後,直線也將保持直線。要找到此變換矩陣,在輸入影象上有4個點,在輸出影象上需要相應的點。在這4個點中,其中3個不應共線。然後可以通過函式cv.getPerspectiveTransform找到轉換矩陣。然後將cv.warpPerspective應用於此3x3轉換矩陣,我們來看程式碼:
import cv2 as cv import matplotlib.pyplot as plt import numpy as np 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()
可以看到,影象對於給定的座標已經進行了矯正,這對於之後的形態學的操作是相當方便的。
天道酬勤 循序漸進 技壓群雄