Practical Python and OpenCV,3rd Edition 04

圖像轉換(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)

運行結果:

Practical Python and OpenCV,3rd Edition 04

旋轉(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以及圖像的輸出尺寸(寬度和高度)。然後,顯示旋轉了的圖像。

顯示效果為:

Practical Python and OpenCV,3rd Edition 04

接下來為了讓代碼更加的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)

運行結果:

Practical Python and OpenCV,3rd Edition 04

確實很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。

顯示效果:

Practical Python and OpenCV,3rd Edition 04

Flipping

接下來我們要探索的圖像轉換是翻轉圖像。 我們可以圍繞x或者翻轉圖像y軸,甚至兩者。查看下圖理解一下水平和垂直翻轉的區別。

Practical Python and OpenCV,3rd Edition 04

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軸垂直翻轉圖像。最後,使用負翻轉代碼翻轉兩個軸圖像。

顯示效果:

Practical Python and OpenCV,3rd Edition 04

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需要四個索引:

  1. 開始y:起始y座標。在這種情況下,我們從y=30開始。
  2. 結束y:結束y座標。我們將在y=120時結束我們的裁剪。
  3. 開始x:切片的起始x座標。我們在x=240時開始裁剪
  4. 結束x:切片的結束x軸座標。我們的切片在x=335處結束

顯示效果:

Practical Python and OpenCV,3rd Edition 04

更多參考:https://0leo0.github.io/2018/OpenCV_python3_04.html

關注不迷路哦!!


分享到:


相關文章: