圖像轉換(image transformations)
本節中,我們將介紹基本的圖像轉換。 這些是您可能應用於圖像的常用技術,包括平移,旋轉,調整大小,翻轉和裁剪。
平移(Translation)
我們首先介紹的是Translation。Trans Latino是沿x和y軸移動圖像。 使用Translation,我們可以向上,向下,向左或向右移動圖像,以及上述任意組合!請看下面的代碼(translation.py):
import numpy as np
import argparse
import imutils
import cv2
ap = argparse.ArgumentParser()
ap.add_argument('-i',"--image",required=True,
help="path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Original",image)
M = np.float32([[1,0,25],[0,1,50]])
shifted = cv2.warpAffine(image,M,(image.shape[1],image.shape[0]))
cv2.imshow("Shifted Down and Right",shifted)
M = np.float32([[1,0,-50],[0,1,-90]])
shifted = cv2.warpAffine(image,M,(image.shape[1],image.shape[0]))
cv2.imshow("Shifted Up and Left",shifted)
解釋:
主要從M——我們的的translation matrix講起,該矩陣告訴我們的圖像要進行平移多少像素(從左到右,從上到下)。該矩陣被定義為float32類型的數組,因為OpenCV希望該矩陣是一個float類型。The first row of the matrix is [1,0,tx],其中t
x是the number of pixels we will shift the image left or right,而負值則表示圖像將向左平移,正值表示圖像將向右平移。然後我們定義the second row of the matrix as [0,1,ty],其中,ty是the number of pixels we will shift the image up or down。其中,負值表示圖像向上平移,正值表示圖像向下平移。使用了上面的那個標記,我們看代碼中,將tx=25,ty=50則意味著,我們將圖像向右平移25個像素,向下平移50個像素。
我們定義好了平移矩陣之後,圖像的實際平移是使用了cv2.warpAffine函數來執行,該函數的第一個參數是我們要進行平移的圖像,第二個參數是我們的平移矩陣M,最後我們需要手動地提供圖像的尺寸(width and height)作為第三個參數。
前面實現了圖像的平移,但是代碼太過冗餘,我們新建一個.py文件來實現平移功能(imutils.py)
import numpy as np
import cv2
def translate(image,x,y):
M = np.float32([[1,0,x],[0,1,y]])
shifted = cv2.warpAffine(image,M,(image.shape[1],image.shape[0]))
return shifted
解釋 :
我們的平移方法有三個參數:我們要平移的圖像,我們沿x軸移動的像素數,以及我們將沿y軸移動的像素數。然後,此方法定義我們的平移矩陣M,然後再應用實際移位。最後,我們返回移位後的圖像。
修改translation.py的內容
shifted = imutils.translate(image,0,100)
cv2.imshow("Shifted Down",shifted)
cv2.waitKey(0)
運行結果:
旋轉(Rotation)
在這裡,我們將使用θ來表示要旋轉多少度。
rotate.py
import numpy as np
import argparse
import imutils
import cv2
ap = argparse.ArgumentParser()
ap.add_argument('-i',"--image",required=True,
help="Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Original",image)
(h,w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center,45,1.0)
rotated = cv2.warpAffine(image,M,(w,h))
cv2.imshow("Rotated by 45 Degrees",rotated)
M = cv2.getRotationMatrix2D(center,-90,1.0)
rotated = cv2.warpAffine(image,M,(w,h))
cv2.imshow("Rotated by -90 Degrees",rotated)
解釋:
前面還是導入必要的包以及解析輸入參數和顯示原始圖像。
當我們旋轉圖像時,我們需要指定我們想要旋轉的點。 在大多數情況下,您需要圍繞圖像的中心旋轉; 我們首先獲取圖像的寬度和高度,因為OpenCV將圖像讀取為一個numpy數組,所以和矩陣類似,矩陣的行對應著高,也就是height=image.shape[0],矩陣的列對應著圖像的寬,也就是width=image.shape[1],然後我們除以2,確定圖像的中心位置。這裡我們使用和C語言一樣的除法,//表示整除法,以確保我們得到的是整數。
就像我們定義一個矩陣來平移圖像一樣,我們也定義了一個矩陣來旋轉圖像。 不是使用NumPy手動構造矩陣,而是調用cv2.getRotationMatrix2D方法。
cv2.getRotationMatrix2D函數有三個參數:第一個是我們想要旋轉圖像的點,在這裡是圖像的中心位置,然後我們指定需要旋轉的角度θ,我們第一次是旋轉了45度,最後一個參數圖像的比例。我們還沒有討論調整圖像的大小,但是在這裡你可以指定浮點值,其中1.0表示使用相同的圖像尺寸。 但是,如果指定值為2.0,則圖像的大小將加倍。 類似地,值0.5將圖像的大小減半。
一旦我們從cv2.getRotationMatrix2D函數獲得旋轉矩陣M,我們就可以使用cv2.warpAffine方法將旋轉應用於我們的圖像。此函數的第一個參數是我們想要旋轉的圖像。然後,我們指定旋轉矩陣M以及圖像的輸出尺寸(寬度和高度)。然後,顯示旋轉了的圖像。
顯示效果為:
接下來為了讓代碼更加的pretty and Pythonic,我們在imutils.py中添加一個rotate方法
def rotate(image,angle,center=None,scale=1.0):
(h,w) = image.shape[:2]
if center is None:
center = (w // 2 , h // 2)
M = cv2.getRotationMatrix2D(center,angle,scale)
rotated = cv2.warpAffine(image,M,(w,h))
return rotated
解釋:
我們的rotate方法有四個參數。第一個是你的image。第二個是我們想要旋轉圖像的角度θ。我們提供兩個可選的關鍵字參數,center和scale。center參數是我們希望旋轉圖像的點。如果提供了值None,則該方法自動選圖像中心為旋轉點。最後,scale參數用於處理在旋轉期間是否應更改圖像的大小。scale參數的默認值為1.0,這意味著不應調整大小。
再次修改rotate.py文件,
rotated = imutils.rotate(image,180)
cv2.imshow("Rotated by 180 Degrees",rotated)
cv2.waitKey(0)
運行結果:
確實很pythonic!!!
Resizing
import numpy as np
import argparse
import imutils
import cv2
ap = argparse.ArgumentParser()
ap.add_argument('-i',"--image",required=True,help="Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Original",image)
解釋:
這個和前面一樣,解析參數,讀取圖片並顯示圖片
r = 150.0 / image.shape[1]
dim = (150,int(image.shape[0] * r))
resized = cv2.resize(image,dim,interpolation=cv2.INTER_AREA)
cv2.imshow("Resized (Width)",resized)
解釋:
r表示the aspect ratio。這裡image.shape[1]表示我們圖片的寬度,上面的代碼我們設置我們圖片的新寬度為150個pixels,為了計算新高度與舊高度的比率,我們簡單地將比率r定義為新寬度(150像素)除以舊寬度,接著為了保持寬高比,我們計算出高度(height)的變化為 height / width * 150。接下來調用resize函數,該函數的第一個參數是我們希望調整大小的圖像,第二個參數是我們為新圖像計算的尺寸。最後一個參數是我們的插值方法,這是在背後工作的算法 處理實際圖像的大小調整方式。一般來說,我發現使用cv2.INTER
AREA在調整大小時獲得最佳效果; 但是,其他適當的選擇包括cv2.INTERLINEAR,cv2.INTERCUBIC和cv2.INTERNEAREST。r = 50.0 / image.shape[0]
dim = (int(image.shape[1] * r),50)
resized = cv2.resize(image,dim,interpolation=cv2.INTER_AREA)
cv2.imshow("Resized (Height)",resized)
cv2.waitKey(0)
解釋:
這一段代碼和前一段類似,只不過這一次是固定高度為50個像素,然後保持寬高比計算出寬度,顯示圖像。
resized = imutils.resize(image,width = 100)
cv2.imshow("Resized via Function",resized)
cv2.waitKey(0)
解釋:
前面都是用了三行代碼實現圖像的resize,我們可以利用imutils.resize函數只需要一行即可實現一樣的功能。
在imutils.py函數中實現:
def resize(image,width=None,height=None,inter=cv2.INTER_AREA):
dim = None
(h,w) = image.shape[:2]
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r),height)
else:
r = width / float(w)
dim = (width,int(h * r))
resized = cv2.resize(image,dim,interpolation=inter)
return resized
解釋:
第一個參數是我們想要調整大小的圖像。然後,我們定義兩個關鍵字參數,寬度和高度。這兩個參數都不能為None,否則我們將不知道如何調整圖像大小。我們還提供inter,這是我們的插值方法,默認為cv2.INTER_AREA。
顯示效果:
Flipping
接下來我們要探索的圖像轉換是翻轉圖像。 我們可以圍繞x或者翻轉圖像y軸,甚至兩者。查看下圖理解一下水平和垂直翻轉的區別。
import argparse
import cv2
ap = argparse.ArgumentParser()
ap.add_argument('-i',"--image",required=True,
help="Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Original",image)
解釋: 和前面一樣,解析參數,顯示原始圖片
flipped = cv2.flip(image,1)
cv2.imshow("Flipped Horizontally",flipped)
flipped = cv2.flip(image,0)
cv2.imshow("Flipped Vertically",flipped)
flipped = cv2.flip(image,-1)
cv2.imshow("Flipped Horizontally & Vertically",flipped)
cv2.waitKey(0)
我們通過調用cv2.flip函數來完成圖像的翻轉。cv2.flip方法需要兩個參數:我們要翻轉的圖像和a flip code,用於確定我們如何翻轉圖片。
使用翻轉代碼值1表示我們將圍繞y軸水平翻轉圖像。指定翻轉代碼為0表示我們想要圍繞x軸垂直翻轉圖像。最後,使用負翻轉代碼翻轉兩個軸圖像。
顯示效果:
Cropping
當我們裁剪圖像時,我們想要刪除我們不感興趣的圖像的外部部分。我們可以使用NumPy數組切片來完成圖像裁剪。
import numpy as np
import argparse
import cv2
ap = argparse.ArgumentParser()
ap.add_argument('-i',"--image",required=True,
help="Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Original",image)
cropped = image[30:120,240:335]
cv2.imshow("T-Rex Face",cropped)
cv2.waitKey(0)
解釋:
實際裁剪在一行代碼上進行。我們提供NumPy數組切片以提取圖像的矩形區域,從(240,30)開始到(335,120)結束。The order in which we supply the indexes to the crop may seem counterintuitive(有悖常理); 但請記住,OpenCV將圖像表示為NumPy數組,其高度優先,寬度為次之。這意味著我們需要在x軸之前提供y軸值.
為了執行我們的裁剪,NumPy需要四個索引:
- 開始y:起始y座標。在這種情況下,我們從y=30開始。
- 結束y:結束y座標。我們將在y=120時結束我們的裁剪。
- 開始x:切片的起始x座標。我們在x=240時開始裁剪
- 結束x:切片的結束x軸座標。我們的切片在x=335處結束
顯示效果:
更多參考:https://0leo0.github.io/2018/OpenCV_python3_04.html
關注不迷路哦!!
閱讀更多 lovesLife 的文章