摘要:本篇文章主要講解圖像仿射變換和圖像透視變換,通過Python調用OpenCV函數實。
本文分享自華爲雲社區《[Python圖像處理] 十二.圖像幾何變換之圖像仿射變換、圖像透視變換和圖像校正》,作者: eastmount 。
一.圖像仿射變換
圖像仿射變換又稱爲圖像仿射映射,是指在幾何中,一個向量空間進行一次線性變換並接上一個平移,變換爲另一個向量空間。通常圖像的旋轉加上拉昇就是圖像仿射變換,仿射變換需要一個M矩陣實現,但是由於仿射變換比較複雜,很難找到這個M矩陣.
OpenCV提供了根據變換前後三個點的對應關係來自動求解M的函數——cv2.getAffineTransform(pos1,pos2),其中pos1和pos2表示變換前後的對應位置關係,輸出的結果爲仿射矩陣M,接着使用函數cv2.warpAffine()實現圖像仿射變換。圖5-14是仿射變換的前後效果圖。
圖像仿射變換的函數原型如下:
M = cv2.getAffineTransform(pos1,pos2)
- pos1表示變換前的位置
- pos2表示變換後的位置
cv2.warpAffine(src, M, (cols, rows))
- src表示原始圖像
- M表示仿射變換矩陣
- (rows,cols)表示變換後的圖像大小,rows表示行數,cols表示列數
實現代碼如下所示:
#encoding:utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取圖片 src = cv2.imread('test.bmp') #獲取圖像大小 rows, cols = src.shape[:2] #設置圖像仿射變換矩陣 pos1 = np.float32([[50,50], [200,50], [50,200]]) pos2 = np.float32([[10,100], [200,50], [100,250]]) M = cv2.getAffineTransform(pos1, pos2) #圖像仿射變換 result = cv2.warpAffine(src, M, (cols, rows)) #顯示圖像 cv2.imshow("original", src) cv2.imshow("result", result) #等待顯示 cv2.waitKey(0) cv2.destroyAllWindows()
輸出效果圖如下所示:
二.圖像透視變換
圖像透視變換(Perspective Transformation)的本質是將圖像投影到一個新的視平面,同理OpenCV通過函數cv2.getPerspectiveTransform(pos1,pos2)構造矩陣M,其中pos1和pos2分別表示變換前後的4個點對應位置。得到M後在通過函數cv2.warpPerspective(src,M,(cols,rows))進行透視變換。
圖像透視變換的函數原型如下:
M = cv2.getPerspectiveTransform(pos1, pos2)
- pos1表示透視變換前的4個點對應位置
- pos2表示透視變換後的4個點對應位置
cv2.warpPerspective(src,M,(cols,rows))
- src表示原始圖像
- M表示透視變換矩陣
- (rows,cols)表示變換後的圖像大小,rows表示行數,cols表示列數
代碼如下:
#encoding:utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取圖片 src = cv2.imread('test01.jpg') #獲取圖像大小 rows, cols = src.shape[:2] #設置圖像透視變換矩陣 pos1 = np.float32([[114, 82], [287, 156], [8, 322], [216, 333]]) pos2 = np.float32([[0, 0], [188, 0], [0, 262], [188, 262]]) M = cv2.getPerspectiveTransform(pos1, pos2) #圖像透視變換 result = cv2.warpPerspective(src, M, (190, 272)) #顯示圖像 cv2.imshow("original", src) cv2.imshow("result", result) #等待顯示 cv2.waitKey(0) cv2.destroyAllWindows()
輸出結果如下圖所示:
三.基於圖像透視變換的圖像校正
下面參考 t6_17大神 的文章,通過圖像透視變換實現圖像校正功能。
假設現在存在一張A4紙圖像,現在需要通過調用圖像透視變換校正圖像。
代碼如下所示:
#encoding:utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取圖片 src = cv2.imread('test01.jpg') #獲取圖像大小 rows, cols = src.shape[:2] #將源圖像高斯模糊 img = cv2.GaussianBlur(src, (3,3), 0) #進行灰度化處理 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #邊緣檢測(檢測出圖像的邊緣信息) edges = cv2.Canny(gray,50,250,apertureSize = 3) cv2.imwrite("canny.jpg", edges) #通過霍夫變換得到A4紙邊緣 lines = cv2.HoughLinesP(edges,1,np.pi/180,50,minLineLength=90,maxLineGap=10) #下面輸出的四個點分別爲四個頂點 for x1,y1,x2,y2 in lines[0]: print(x1,y1),(x2,y2) for x1,y1,x2,y2 in lines[1]: print(x1,y1),(x2,y2) #繪製邊緣 for x1,y1,x2,y2 in lines[0]: cv2.line(gray, (x1,y1), (x2,y2), (0,0,255), 1) #根據四個頂點設置圖像透視變換矩陣 pos1 = np.float32([[114, 82], [287, 156], [8, 322], [216, 333]]) pos2 = np.float32([[0, 0], [188, 0], [0, 262], [188, 262]]) M = cv2.getPerspectiveTransform(pos1, pos2) #圖像透視變換 result = cv2.warpPerspective(src, M, (190, 272)) #顯示圖像 cv2.imshow("original", src) cv2.imshow("result", result) #等待顯示 cv2.waitKey(0) cv2.destroyAllWindows()
運行結果如下圖所示:
四.圖像幾何變換總結
最後補充圖像幾何代碼所有變換,希望讀者能體會下相關的代碼,並動手實踐下。輸出結果以女神爲例:
完整代碼如下:
#encoding:utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取圖片 img = cv2.imread('test3.jpg') image = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #圖像平移矩陣 M = np.float32([[1, 0, 80], [0, 1, 30]]) rows, cols = image.shape[:2] img1 = cv2.warpAffine(image, M, (cols, rows)) #圖像縮小 img2 = cv2.resize(image, (200,100)) #圖像放大 img3 = cv2.resize(image, None, fx=1.1, fy=1.1) #繞圖像的中心旋轉 #源圖像的高、寬 以及通道數 rows, cols, channel = image.shape #函數參數:旋轉中心 旋轉度數 scale M = cv2.getRotationMatrix2D((cols/2, rows/2), 30, 1) #函數參數:原始圖像 旋轉參數 元素圖像寬高 img4 = cv2.warpAffine(image, M, (cols, rows)) #圖像翻轉 img5 = cv2.flip(image, 0) #參數=0以X軸爲對稱軸翻轉 img6 = cv2.flip(image, 1) #參數>0以Y軸爲對稱軸翻轉 #圖像的仿射 pts1 = np.float32([[50,50],[200,50],[50,200]]) pts2 = np.float32([[10,100],[200,50],[100,250]]) M = cv2.getAffineTransform(pts1,pts2) img7 = cv2.warpAffine(image, M, (rows,cols)) #圖像的透射 pts1 = np.float32([[56,65],[238,52],[28,237],[239,240]]) pts2 = np.float32([[0,0],[200,0],[0,200],[200,200]]) M = cv2.getPerspectiveTransform(pts1,pts2) img8 = cv2.warpPerspective(image,M,(200,200)) #循環顯示圖形 titles = [ 'source', 'shift', 'reduction', 'enlarge', 'rotation', 'flipX', 'flipY', 'affine', 'transmission'] images = [image, img1, img2, img3, img4, img5, img6, img7, img8] for i in xrange(9): plt.subplot(3, 3, i+1), plt.imshow(images[i], 'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()