本文介紹幾種常見的影像幾何變換方法。
1. 影像縮放
影像縮放就是將源影像中的畫素點經過演算法對映到目標影像的畫素點的過程,即找出目標影像中的畫素點Pd(Xd,Yd)對應的源影像的畫素點Ps(Xs,Ys),然後將源影像畫素點填充到對應目標影像的畫素點,最終形成目標影像。常見的影像縮放演算法有最鄰近點插值法、雙線性插值法和BiCubic卷積插值法等。
在OpenCV中提供函式cv2.resize()實現對影像的縮放,該函式原型如下:
dst = cv2.resize( src, dsize[, fx[, fy[, interpolation]]] )
引數說明:
dst:輸出的目標影像,其型別與src相同,大小為dsize(當該值非零時),或者可以透過src.size()、fx、fy計算得到;
src:需要進行縮放的原始影像;
dsize:輸出影像的大小;
x:水平方向的縮放比例;
y:垂直方向的縮放比例;
interpolation:插值方式。
插值是指影像在進行幾何處理時,給無法直接透過對映得到的值的畫素點賦值。比如,將原始影像放大為原來的2倍,必然會多出一些無法被直接對映值的畫素點,對於這些畫素點,插值方式決定了如何確定它們的值。當縮小影像時,使用區域插值方式(INTER_AREA)能夠得到最好的效果;當放大影像時,使用三次樣條插值(INTER_CUBIC)方式和雙線性插值(INTER_LINEAR)方式都能夠取得較好的效果。三次樣條插值方式速度較慢,雙線性插值方式速度相對較快且效果並不遜色。
測試程式碼如下:
img = cv2.imread("lenna.jpg")
height, width = img.shape[:2] # 獲取影像的高度和寬度
cv2.imshow('src', img)
# 縮放到原來的二分之一
img_test1 = cv2.resize(img, (int(height / 2), int(width / 2)))
cv2.imshow('resize1', img_test1)
# 最近鄰插值法縮放,縮放到原來的四分之一
img_test2 = cv2.resize(img, (0, 0), fx=0.25, fy=0.25, interpolation=cv2.INTER_NEAREST)
cv2.imshow('resize2', img_test2)
cv2.waitKey()
cv2.destroyAllWindows()
效果如下:
2 影像旋轉
影像旋轉是指將影像繞某個中心點旋轉一定角度後,得到一幅新的影像。
Python中imutils工具包提供瞭如下函式實現影像旋轉:
imutils.rotate:實現了在旋轉完成圖解析度不調整的情況下,對原影像內容旋轉,可能區域性丟失,缺失部分用黑色填充。
imutils.rotate_bound:保持原圖完整,旋轉完成圖解析度會改變。
測試程式碼如下:
import imutils
img = cv2.imread("lenna.jpg")
cv2.imshow('src', img)
# 旋轉45度,可能區域性丟失,缺失部分用黑色填充
rot1 = imutils.rotate(img, angle=45)
cv2.imshow("Rotated1", rot1)
# 旋轉45度,保持原圖完整,旋轉完成圖解析度會改變
rot2 = imutils.rotate_bound(img, angle=45)
cv2.imshow("Rotated2", rot2)
cv2.waitKey()
cv2.destroyAllWindows()
效果如下:
3 影像翻轉
翻轉也稱映象,是指將影像沿軸線進行軸對稱變換。水平映象是將影像沿垂直中軸線進行左右翻轉,垂直映象是將影像沿水平中軸線進行上下翻轉,水平垂直映象是水平映象和垂直映象的疊加。
OpenCV提供了cv2.flip函式,可以將影像沿水平方向、垂直方向、或水平/垂直方向同時進行翻轉。其函式原型如下:
cv2.flip(src, flipCode[, dst]) -> dst
引數說明:
scr:變換操作的輸入影像;
flipCode:控制引數,整型(int),flipCode>0 水平翻轉,flipCode=0 垂直翻轉,flipCode<0 水平和垂直翻轉;
dst:變換操作的輸出影像,可選項。
測試程式碼如下:
img = cv2.imread("lenna.jpg") # 讀取彩色影像(BGR)
imgFlip1 = cv2.flip(img, 0) # 垂直翻轉
imgFlip2 = cv2.flip(img, 1) # 水平翻轉
imgFlip3 = cv2.flip(img, -1) # 水平和垂直翻轉
plt.subplot(221), plt.axis('off'), plt.title("Original")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 原始影像
plt.subplot(222), plt.axis('off'), plt.title("Flipped Horizontally")
plt.imshow(cv2.cvtColor(imgFlip2, cv2.COLOR_BGR2RGB)) # 水平翻轉
plt.subplot(223), plt.axis('off'), plt.title("Flipped Vertically")
plt.imshow(cv2.cvtColor(imgFlip1, cv2.COLOR_BGR2RGB)) # 垂直翻轉
plt.subplot(224), plt.axis('off'), plt.title("Flipped Horizontally & Vertically")
plt.imshow(cv2.cvtColor(imgFlip3, cv2.COLOR_BGR2RGB)) # 水平垂直翻轉
plt.show()
效果如下:
4 影像平移
影像的平移就是將影像上的畫素點整體移動。影像平移首先定義平移矩陣M,再呼叫warpAffine()函式實現平移,函式原型如下:
M = np.float32([[1, 0, x], [0, 1, y]])
shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
測試程式碼如下:
img = cv2.imread('lenna.jpg')
image = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
# 影像下、上、右、左平移
M = np.float32([[1, 0, 0], [0, 1, 100]])
img1 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
M = np.float32([[1, 0, 0], [0, 1, -100]])
img2 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
M = np.float32([[1, 0, 100], [0, 1, 0]])
img3 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
M = np.float32([[1, 0, -100], [0, 1, 0]])
img4 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
# 顯示圖形
titles = [ 'Image-down', 'Image-up', 'Image-right', 'Image-left']
images = [img1, img2, img3, img4]
for i in range(4):
plt.subplot(2,2,i+1), plt.imshow(images[i]), plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
效果如下: