1. 程式人生 > >【影象處理】OpenCV+Python影象處理入門教程(四)幾何變換

【影象處理】OpenCV+Python影象處理入門教程(四)幾何變換

       這篇隨筆介紹使用OpenCV進行影象處理的第四章 幾何變換。

4  幾何變換

       影象的幾何變換是指將一幅影象對映到另一幅影象內。有縮放、翻轉、仿射變換、透視、重對映等操作。

4.1  縮放

使用cv2.resize()函式實現對影象的縮放,但要注意cv2.resize()函式內的dsize引數與原影象的行列屬性是相反的,也就是:目標影象的行數是原始影象的列數,目標影象的列數是原始影象的行數。

下面舉例說明cv2.resize()函式的用法:

1 import cv2
2 img=cv2.imread('E:/python_opencv/tupian.jpg')
3 rows,cols=img.shape[0:2]   #行數和列數等於img的長度和寬度
4 size=(int(cols*0.9),int(rows*0.5))   #比例:列變為原來0.9倍,行變為0.5倍
5 rst=cv2.resize(img,size)   #將img按size比例縮放
6 print('img.shape=',img.shape)
7 print('rst.shape=',rst.shape)

執行程式的結果如下:

img.shape=(600,60,3)
rst.shape=(300,54,3)

可以看出,行數變為原來的0.5倍,列數變為原來的0.9倍。程式碼中size的行列位置發生了交換。

 

4.2  翻轉

使用cv2.flip()函式對影象翻轉,能夠實現水平方向翻轉、垂直方向翻轉、兩個方向同時翻轉。

下面舉例說明cv2.flip()函式的用法:

 1 import cv2
 2 img=cv2.imread('E:/python_opencv/tupian.jpg')
 3 x=cv2.flip(img,0)      #圖x對原影象繞x軸翻轉
 4 y=cv2.flip(img,1)      #圖y對原影象繞y軸翻轉
 5 xy=cv2.flip(img,-1)    #圖xy對原影象繞x軸y軸同時翻轉
 6 cv2.imshow('img',img)
 7 cv2.imshow('x',x)
 8 cv2.imshow('y',y)
 9 cv2.imshow('xy',xy)
10 cv2.waitKey()
11 cv2.destroyAllWindows()

程式執行結果如下四幅圖,第一幅是原圖,第二幅是繞x軸翻轉,第三幅是繞y軸翻轉,第四幅是繞x軸y軸同時翻轉。

 

4.3  仿射

仿射變換是指影象實現平移、旋轉等操作。

先設定一個變換矩陣M,然後使用cv2.warpAffine()函式對原影象和變換矩陣M進行仿射操作。

(一)平移

要實現影象的平移,我們先自定義一個轉換矩陣,再進行仿射平移變換。例程如下:

 1 import cv2
 2 import numpy as np
 3 img=cv2.imread('E:\python_opencv/tupian.jpg')
 4 height,width=img.shape[:2]         #讀取原影象的長和寬
 5 x=100                                           #自定義轉換矩陣M的x軸移動值
 6 y=200                                           #自定義轉換矩陣M的y軸移動值
 7 M=np.float32([[1,0,x],[0,1,y]])       #構造轉換矩陣M
 8 move=cv2.warpAffine(img,M,(width,height))   #平移對映
 9 cv2.imshow('orginal',img)
10 cv2.imshow('move',move)
11 cv2.waitKey()
12 cv2.destroyAllWindows()

程式執行結果如下圖所示,左為原圖,右為平移後的圖。

(二)旋轉

使用函式cv2.getRotationMatrix2D()獲得轉移矩陣M,然後使用函式cv2.warpAffine()進行仿射旋轉變換。例程如下:

1 import cv2
2 img=cv2.imread('E:\python_opencv/tupian.jpg')
3 height,width=img.shape[:2]   #讀取原影象的長和寬
4 M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6)   #以中心為原點,逆時針旋轉45°,且縮小為原圖的0.6倍,獲得轉移矩陣M
5 rotate=cv2.warpAffine(img,M,(width,height))   #旋轉對映
6 cv2.imshow('original',img)
7 cv2.imshow('rotation',rotate)
8 cv2.waitKey()
9 cv2.destroyAllWindows()

程式執行結果如下圖所示,左為原圖,右為旋轉後的圖。

 

4.4  透視

透視變換是指將矩陣圖形投影到另一個視平面,可以對映為任意四邊形,所以透視變換也被稱為投影對映(Projection Mapping),並不是字面意義上的“透視”。透視與上節的仿射不同,仿射可以將矩陣對映為任意平行四邊形。

使用cv2.warpPerspective()函式實現透視變換。例程如下:

 1 #完成影象透視
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:/python_opencv/tupian.jpg')
 5 rows,cols=img.shape[:2]      #讀取原影象的長和寬
 6 print(rows,cols)
 7 #生成旋轉矩陣M
 8 pts1=np.float32([[150,50],[400,50],[60,450],[310,450]])
 9 pts2=np.float32([[50,50],[rows-50,50],[50,cols-50],[rows-50,cols-50]])
10 M=cv2.getPerspectiveTransform(pts1,pts2)
11 #使用函式cv2.warpPerspective()進行透視變換
12 dst=cv2.warpPerspective(img,M,(cols,rows))
13 cv2.imshow('img',img)
14 cv2.imshow('dst',dst)
15 cv2.waitKey()
16 cv2.destroyAllWindows()

程式執行結果如下圖所示,左為原圖,右為透視變換的圖。

我們可以看到,原圖片經過透視對映後,變成另一個視角下的任意四邊形了。

 

4.5  重對映

重對映是修改了畫素點的位置,從而生成一幅新的影象,包括:複製、繞x軸y軸翻轉,x軸y軸互換,影象縮放等。

均使用cv2.remap()重對映函式進行操作。

需要注意cv2.remap()中的兩個引數mapx、mapy。mapx表示對應位置上x軸座標值,mapy表示對應位置上y軸座標值。

(一)複製

使用cv2.remap()函式完成影象複製,需先定義mapx,mapy的值,然後迴圈對映每個畫素點到對應的位置上。

程式碼如下:

 1 import cv2
 2 import numpy as np
 3 img=cv2.imread('E:/python_opencv/tupian.jpg')
 4 rows,cols=img.shape[:2]                  #讀取行列數
 5 mapx=np.zeros(img.shape[:2],np.float32)  #mapx引數設定為對應位置上的x軸座標值
 6 mapy=np.zeros(img.shape[:2],np.float32)  #mapy引數設定為對應位置上的y軸座標值
 7 for i in range(rows):                    #對每個元素複製對映
 8     for j in range(cols):
 9         mapx.itemset((i,j),j)
10         mapy.itemset((i,j),i)
11 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
12 cv2.imshow('original',img)
13 cv2.imshow('result',rst)
14 cv2.waitKey()
15 cv2.destroyAllWindows()

執行後結果如下所示,可以看到,實現了影象的複製重對映。

(二)繞x軸翻轉

重對映法對影象繞x軸翻轉,表明mapx的值保持不變,mapy的值調整為總行數-1-當前行號,其餘部分程式碼不變,所以迴圈體內程式碼變為:

1 for i in range(rows):
2     for j in range(cols):
3         mapx.itemset((i,j),j)           #mapx的值保持不變
4         mapy.itemset((i,j),rows-1-i)    #mapy的值調整為總行數-1-當前行號

(三)繞y軸翻轉

重對映法對影象繞y軸翻轉,表明mapx的值調整為總行數-1-當前列號,mapy的值保持不變,所以迴圈體內程式碼變為:

1 for i in range(rows):
2     for j in range(cols): 
3         mapx.itemset((i,j),cols-1-j)    #mapx的值調整為總列數-1-當前列號
4         mapy.itemset((i,j),i)           #mapy的值保持不變

(四)繞x軸y軸翻轉

重對映也能實現影象繞x軸和y軸的同時翻轉,只需將前兩個部分合並,使mapx的值調整為總行數-1-當前列號,mapy的值調整為總行數-1-當前行號。例程如下:

 1 import cv2
 2 import numpy as np
 3 img=cv2.imread('E:\python_opencv/tupian.jpg')
 4 rows,cols=img.shape[:2]
 5 mapx=np.zeros(img.shape[:2],np.float32)
 6 mapy=np.zeros(img.shape[:2],np.float32)
 7 for i in range(rows):
 8     for j in range(cols):
 9         mapx.itemset((i,j),cols-1-j)    #mapx的值調整為總列數-1-當前列號
10         mapy.itemset((i,j),rows-1-i)   #mapy的值調整為總行數-1-當前行號
11 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
12 cv2.imshow('original',img)
13 cv2.imshow('result',rst)
14 cv2.waitKey()
15 cv2.destroyAllWindows()

執行後結果如下所示,可以看到,實現了影象的繞x軸和y軸翻轉重對映過程。

(五)x軸、y軸互換

重對映中,x軸、y軸互換表明,mapx的值變為所在行的行號,mapy的值變為所在列的列號。

但當行數和列數不一致時,行或列無法完成對映的部分就被處理為0。示例程式碼如下:

 1 #使用函式cv2.remap()實現影象繞x軸和y軸的互換
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:\python_opencv/tupian.jpg')
 5 rows,cols=img.shape[:2]
 6 mapx=np.zeros(img.shape[:2],np.float32)
 7 mapy=np.zeros(img.shape[:2],np.float32)
 8 for i in range(rows):
 9     for j in range(cols):
10         mapx.itemset((i,j),i)    #mapx的值變為所在行的行號
11         mapy.itemset((i,j),j)    #mapy的值變為所在列的列號
12 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
13 cv2.imshow('original',img)
14 cv2.imshow('result',rst)
15 cv2.waitKey()
16 cv2.destroyAllWindows()

結果如圖:

可以看到,列數多於行數的部分被置為0(黑色)。

(六)影象的縮放

重對映提供了cv2.remap()函式能夠實現影象的放大或縮小。處理影象後,可以將影象固定在圍繞其中心的某個區域。

下面例程中,x軸和y軸均縮小為原來的0.25-0.75倍之間。

 1 import cv2
 2 import numpy as np
 3 img=cv2.imread('E:\python_opencv/tupian.jpg')
 4 rows,cols=img.shape[:2]
 5 mapx=np.zeros(img.shape[:2],np.float32)
 6 mapy=np.zeros(img.shape[:2],np.float32)
 7 for i in range(rows):
 8     for j in range(cols):
 9         if 0.25*cols < i < 0.75*cols and 0.25*rows < i < 0.75*rows:
10             #在目標影象的x軸(0.25-0.75)倍之內生成縮小影象
11             mapx.itemset((i,j),2*(j-0.25*cols)+0.5)
12             #在目標影象的y軸(0.25-0.75)倍之內生成縮小影象
13             mapy.itemset((i,j),2*(i-rows*0.25)+0.5)
14         else:
15             #不在上述區域的點都取(0,0)座標點的值
16             mapx.itemset((i,j),0)
17             mapy.itemset((i,j),0)
18 rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)   #影象縮放重對映
19 cv2.imshow('original',img)
20 cv2.imshow('result',rst)
21 cv2.waitKey()
22 cv2.destroyAllWindows()
影象縮放重對映結果如下:


這次內容就分享到這裡了,下次繼續更新第5章 影象閾值處理,希望與各位老師和小夥伴們交流學習~

&n