opencv學習記錄之幾何變換


------------恢復內容開始------------

幾何變換是指將一幅圖像映射到另外一幅圖像內的操作

一、縮放

函數具體形式為

dst = cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])

dst代表輸出的目標圖像,類型與src相同,大小為dsize 或可以通過src.size() ,fx,fy計算得到

src代表需要縮放的原始圖像

dsize代表輸出圖像大小

fx表示水平方向的縮放比例

fy表示垂直方向的縮放比例

interpolation代表插值方式

當縮小圖像時,使用區域插值方式(INTER_AREA)能夠得到最好的效果

當放大圖像時,使用三次樣條插值(INTER_CUBIC)方式和雙線性插值(INTER_LINEAR)方式能夠取的較好的結果,

1 import cv2
2 img = cv2.imread("/home/miao/dog.jpg")
3 rows,cols = img.shape[:2]
4 size = (int( cols*0.9) , int(rows * 0.5))
5 rst = cv2.resize( img , size)
6 print("img.shape=" , img.shape)
7 print("rst.shape=" , rst.shape)
img.shape= (200, 300, 3)
rst.shape= (100, 270, 3)

列數變為原來0.9倍,行數變為原來0.5倍

1 import cv2                                                                                                                                       
2 img = cv2.imread("/home/miao/dog.jpg")
3 rst = cv2.resize(img , None , fx = 2 , fy = 0.5)
4 print("img.shape= " , img.shape)
5 print("rst.shape= " , rst.shape)
img.shape=  (200, 300, 3)
rst.shape=  (100, 600, 3)

fx是水平方向的縮放,將列數變為原來的2倍

fy是垂直方向的縮放,將行數變為原來的0.5倍

 

二、翻轉

該函數可以實現垂直方向、水平方向和兩個方向同時翻轉

函數形式為

dst = cv2.flip( src , flipCode)

flipCode代表旋轉類型,參數意義如下

參數值 說明 意義
0 只能是0 繞着x軸翻轉
正數 1、2、3等任意正數 繞着y軸翻轉
負數 -1、-2、-3等任意負數 圍繞x軸,y軸同時翻轉

 

 

 

 

 

 1 import cv2                                                                                                                                       
 2 img = cv2.imread("/home/miao/dog.jpg")
 3 x = cv2.flip(img , 0) 
 4 y = cv2.flip(img , 1) 
 5 xy = cv2.flip(img , -1)
 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

 

 

xy

 

 

 

 

 

三、仿射

通過一系列的幾何變換來實現平移、旋轉等多種操作。該變換保持圖像的平直性和平行性,

平直性是指在經過變換后直線仍然是直線

平行性是指在完成仿射變換后,平行線仍然是平行線

函數形式為

dst = cv2.warpAffine( src , M , dsize [, flags [, borderMode [, borderValue]]])

dst代表仿射后的輸出圖像

src代表要仿射的原始圖像

M代表一個2x3的變換矩陣

dsize代表要輸出圖像的尺寸

flags代表插值方法,默認為INTER_LINEAR

borderMode代表邊類型,默認為DORDER_CONSTANT

borderValue代表邊界值,默認為0 

通過轉換矩陣M將原始圖像src轉換為目標圖像dst

dst(x,y) = src(M11*x + M12 *y + M13 ,M21 * x + M22 * y + M23)

平移

 1 import cv2                                                                                                                                       
 2 import numpy as np 
 3 img = cv2.imread("/home/miao/dog.jpg")
 4 height , width = img.shape[:2]
 5 x = 50 
 6 y = 100
 7 M = np.float32([[1,0,x] , [0 , 1, y]])
 8 move = cv2.warpAffine(img , M ,(width , height))
 9 cv2.imshow("original" , img )
10 cv2.imshow("move" , move)
11 cv2.waitKey()
12 cv2.destroyAllWindows()

由上的公式可得

dst( x , y) = src(1*x + 0 * y + 50 , 0 * x + 1 * y +100)

即可得到圖像的平移

 

 

 

 

旋轉需要調用函數來生成轉換矩陣M

函數形式如下

cv2.getRotationMatrix2D(center , angel , scale)

center為旋轉中心點

angel為旋轉角度,整數表示逆時針旋轉,負數表示順時針旋轉

scale為變換尺度(縮放大小)

1 import cv2                                                                                                                                       
2 img = cv2.imread("/home/miao/dog.jpg")
3 height , width = img.shape[:2]
4 M = cv2.getRotationMatrix2D((width/2 , height/2) , 45 , 0.6 )
5 rotate = cv2.warpAffine(img , M , (width , height))
6 cv2.imshow("original" , img)
7 cv2.imshow("rotation" , rotate)
8 cv2.waitKey()
9 cv2.destroyAllWindows()

函數是以圖中心為原點,逆時針旋轉45度,並將目標圖像縮小為原始圖像的0.6倍

 

 

更復雜的仿射變換

通過函數

cv2.getAffineTransform( src , dst)

src為輸入圖像的三個點坐標

dst為輸出圖像的三個點坐標

三個點坐標為對應平行四邊形的左上角,右上角和左下角三個點

 

 1 import cv2
 2 import numpy as np                                                                                                                               
 3 img = cv2.imread("/home/miao/dog.jpg")
 4 rows , cols, ch = img.shape
 5 p1 = np.float32([[0,0],[cols-1,0] , [0,rows-1]])
 6 p2 = np.float32([[0,rows*0.33],[cols*0.85, rows*0.25],[cols*0.15,rows*0.71]])
 7 M = cv2.getAffineTransform(p1 , p2) 
 8 dst = cv2.warpAffine(img , M ,(cols , rows))
 9 cv2.imshow("original" , img)
10 cv2.imshow("result" , dst)
11 cv2.waitKey()
12 cv2.destroyAllWindows()

 

 

 四、重映射

將一幅圖像內的像素點放置到另外一幅圖像內的指定位置即為重映射

函數形式為

dst = cv2.remap( src , map1 , map2 ,interpolation [, borderMode [ , borderValue]])

dst 代表目標圖像,它和src具有相同的大小和類型

src代表原始圖像

map1

1.表示(x,y)點的一個映射

2.表示CV _16SC2 , CV_32FC1 ,CV_32FC2類型(x,y)點的x值

map2

1.當map1表示(x,y)時,該值為空

2.當map1表示(x,y)點的x值時,該值是CV_16UC1,CV_32FC1類型(x,y)點的y值

interpolation代表插值方式,這里不支持INTER_AREA

borderMode代表邊界模式,

borderValue代表邊界值,該值默認為0

以下為將原始圖像內第0行第3列上的像素值映射到所有像素點,即map1為3,map2為0

其映射關系即為map1和map2對應的像素位置對應圖像的像素點的位置,即map1和map2的[0,0]對應圖像的[0,0],然后將結果位置值存入該點,即map1存第幾列,map2存第幾行。對應以下代碼即每個點映射的都是[0,3]的值

 1 import cv2                                                                       
 2 import numpy as np 
 3 img = np.random.randint( 0 ,256 , size = [4,5] , dtype = np.uint8)
 4 rows , cols = img.shape
 5 mapx = np.ones(img.shape , np.float32) * 3
 6 mapy = np.ones(img.shape , np.float32) * 0
 7 rst = cv2.remap( img , mapx ,mapy ,cv2.INTER_LINEAR)
 8 print("img = \n" , img)
 9 print("mapx = \n" , mapx)
10 print("mapy = \n" , mapy)
11 print("rst = \n" , rst)

 

img = 
 [[150 228 176  51  98]
 [126 172 203 204  89]
 [ 84  31 202 132  61]
 [ 85  44  44 169 204]]
mapx = 
 [[3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]]
mapy = 
 [[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]
rst = 
 [[51 51 51 51 51]
 [51 51 51 51 51]
 [51 51 51 51 51]
 [51 51 51 51 51]]

結果即為全是51

 

 

 

 1 import cv2
 2 import numpy as np
 3 #img = np.random.randint( 0 , 256 , size = [9,9] , dtype = np.uint8)
 4 img = cv2.imread("/home/miao/dog.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) , j)
11         mapy.itemset((i,j) , i)
12 rst_copy = cv2.remap(img , mapx , mapy , cv2.INTER_LINEAR)
13 
14 for i in range(rows):
15     for j in range(cols):
16         mapx.itemset((i,j) , j)
17         mapy.itemset((i,j) , rows - 1 -i)
18 rst_x = cv2.remap(img , mapx , mapy , cv2.INTER_LINEAR)
19 
20 for i in range(rows):
21     for j in range(cols):
22         mapx.itemset((i,j) ,cols - 1-  j)
23         mapy.itemset((i,j) , i)
24 rst_y = cv2.remap(img , mapx , mapy , cv2.INTER_LINEAR)
25 
26 for i in range(rows):
27     for j in range(cols):
28         mapx.itemset((i,j) ,cols - 1 - j)
29         mapy.itemset((i,j) ,rows - 1 - i)
30 rst_xy = cv2.remap(img , mapx , mapy , cv2.INTER_LINEAR)
31 
32 for i in range(rows):
33     for j in range(cols):
34         mapx.itemset((i,j) ,i )
35         mapy.itemset((i,j) ,j )
36 rst_x_y = cv2.remap(img , mapx , mapy , cv2.INTER_LINEAR)
37 
38 for i in range(rows):
39     for j in range(cols):                                                        
40         if 0.25*cols<j<0.75*cols and 0.25*rows<i<0.75*rows:
41             mapx.itemset((i,j) , 2*(j - 0.25*cols)  + 0.5)
42             mapy.itemset((i,j) , 2*(i - 0.25*rows)  + 0.5)
43 
44         else :
45             mapx.itemset((i,j) , 0)
46             mapy.itemset((i,j) , 0)
47 
48 rst = cv2.remap(img , mapx , mapy , cv2.INTER_LINEAR)
49 cv2.imshow("original" , img)
50 cv2.imshow("rst_x" , rst_x)
51 cv2.imshow("rst_y" , rst_y)
52 cv2.imshow("rst_xy" , rst_xy)
53 cv2.imshow("rst_x_y" , rst_x_y)
54 cv2.imshow("result" , rst)
55 cv2.waitKey()
56 cv2.destroyAllWindows()

原圖

復制(第一個for循環)

 

 繞x軸旋轉(第二個for循環)

 

 繞y軸旋轉(第三個for循環)

 

 繞x軸、y軸(第四個for循環)

 

 x軸、y軸交換(第五個for循環)

 

 圖像縮放(第六個for循環)

 

 

 圖像縮放的for循環中

if 0.25*cols<j<0.75*cols and 0.25*rows<i<0.75*rows:
    mapx.itemset((i,j) , 2*(j - 0.25*cols)  + 0.5)
    mapy.itemset((i,j) , 2*(i - 0.25*rows)  + 0.5)
else :
   mapx.itemset((i,j) , 0)  
   mapy.itemset((i,j) , 0) 

將列值和行值取在0.25-0.75的范圍內,其他范圍取值為(0,0)的值

在該范圍內j減去0.25cols是為了可以從0到cols-1,乘2是每2個點取一次

加0.5是取兩個像素點之間的位置,該點是不存在像素值的,可以采用不同的方法實現插值

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

------------恢復內容結束------------

file:///home/miao/桌面/y.png


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM