一、圖像金字塔原理
圖像縮小(先高斯模糊,再降采樣,需要一次次重復,不能一次到底)
圖像擴大(先擴大,再卷積或者使用拉普拉斯金字塔)
圖像金字塔是圖像中多尺度表達的一種,最主要用於圖像的分割,是一種以多分辨率來解釋圖像的有效但概念簡單的結構。簡單來說,圖像金字塔就是用來進行圖像縮放的。
進行圖像縮放可以用圖像金字塔,也可以使用resize函數進行縮放,后者效果更好。這里只是對圖像金字塔做一些簡單了解。
二、金字塔類型:高斯和拉普拉斯
①高斯金字塔:用於下采樣。高斯金字塔是最基本的圖像塔。
原理:首先將原圖像作為最底層圖像G0(高斯金字塔的第0層),利用高斯核(5*5)對其進行卷積,然后對卷積后的圖像進行下采樣(去除偶數行和列)得到上一層圖像G1,
將此圖像作為輸入,重復卷積和下采樣操作得到更上一層圖像,反復迭代多次,形成一個金字塔形的圖像數據結構,即高斯金字塔。
②拉普拉斯金字塔:用於重建圖像,也就是預測殘差,對圖像進行最大程度的還原。比如一幅小圖像重建為一幅大圖,
原理:用高斯金字塔的每一層圖像減去其上一層圖像上采樣並高斯卷積之后的預測圖像,得到一系列的差值圖像即為 LP 分解圖像。
三、采樣類型:上采樣和下采樣
①上采樣:就是圖片放大(所謂上嘛,就是變大),使用PryUp函數。
上采樣步驟:先將圖像在每個方向放大為原來的兩倍,新增的行和列用0填充,再使用先前同樣的內核與放大后的圖像卷積,獲得新增像素的近似值。
②下采樣:就是圖片縮小(所謂下嘛,就是變小),使用PryDown函數。下采樣將步驟:先對圖像進行高斯內核卷積 ,再將所有偶數行和列去除。
總之,上、下采樣都存在一個嚴重的問題,那就是圖像變模糊了,因為縮放的過程中發生了信息丟失的問題。要解決這個問題,就得用拉普拉斯金字塔。
四、使用高斯金字塔實現下采樣pyrDown
1、函數
pyrDown降采樣
def pyrDown(src, dst=None, dstsize=None, borderType=None): # real signature unknown; restored from __doc__ --->dst
opencv的pyrDown函數先對圖像進行高斯平滑,然后再進行降采樣(將圖像尺寸行和列方向縮減一半)。
src參數表示輸入圖像。
dst參數表示輸出圖像,它與src類型、大小相同。
dstsize參數表示降采樣之后的目標圖像的大小。
- 它是有默認值的,如果我們調用函數的時候不指定第三個參數,那么這個值是按照 Size((src.cols+1)/2, (src.rows+1)/2) 計算的。而且不管你自己如何指定這個參數,一定必須保證滿足以下關系式:|dstsize.width * 2 - src.cols| ≤ 2; |dstsize.height * 2 - src.rows| ≤ 2。
- 也就是說降采樣的意思其實是把圖像的尺寸縮減一半,行和列同時縮減一半。
borderType參數表示表示圖像邊界的處理方式。
2、代碼實現
1 import cv2 as cv 2 import numpy as np 3 4 def demo(image): 5 level = 3 6 temp = image.copy() 7 cv.imshow('temp',temp) 8 demo_image = [] #一共有三個元素,元素類型是ndarray,shape分別為(288, 512, 3),(144, 256, 3),(72, 128, 3) 9 for i in range(level): 10 # 先對圖像進行高斯平滑,然后再進行降采樣(將圖像尺寸行和列方向縮減一半) 11 dst = cv.pyrDown(temp) 12 demo_image.append(dst) 13 cv.imshow('demo%d'%i,dst) 14 temp = dst.copy() 15 print(demo_image.shape()) 16 src = cv.imread('1.jpg') 17 demo(src) 18 cv.waitKey(0) 19 cv.destroyAllWindows()
五、使用拉普拉斯金字塔
1、pyrUp上采樣
def pyrUp(src, dst=None, dstsize=None, borderType=None): # ---> dst
opencv的pyrUp函數先對圖像進行升采樣(將圖像尺寸行和列方向增大一倍),然后再進行高斯平滑。
src參數表示輸入圖像。
dst參數表示輸出圖像,它與src類型、大小相同。
dstsize參數表示降采樣之后的目標圖像的大小。
- 在默認的情況下,這個尺寸大小是按照 Size(src.cols*2, (src.rows*2) 來計算的。如果你自己要指定大小,那么一定要滿足下面的條件:
- |dstsize.width - src.cols * 2| ≤ (dstsize.width mod 2); //如果width是偶數,那么必須dstsize.width是src.cols的2倍
- |dstsize.height - src.rows * 2| ≤ (dstsize.height mod 2);
borderType參數表示表示圖像邊界的處理方式。
2、代碼實現
1 import cv2 as cv 2 import numpy as np 3 4 def demo(image): 5 level = 3 6 temp = image.copy() 7 cv.imshow('temp',temp) 8 demo_image = [] 9 for i in range(level): 10 # 先對圖像進行高斯平滑,然后再進行降采樣(將圖像尺寸行和列方向縮減一半) 11 dst = cv.pyrDown(temp) 12 demo_image.append(dst) 13 cv.imshow('demo%d'%i,dst) 14 temp = dst.copy() 15 return demo_image 16 17 def lap(image): 18 lap_image = demo(image) #拉普拉斯需要用到高斯金字塔結果 19 level = len(lap_image) 20 for i in range(level-1,-1,-1): #從后向前2,1,0 21 if (i-1) < 0 : 22 expand = cv.pyrUp(lap_image[i],dstsize=image.shape[:2]) #先上采樣 23 lapls = cv.subtract(image,expand) #使用高斯金字塔上一個減去當前上采樣獲取的結果,才是拉普拉斯金字塔 24 else: 25 expand = cv.pyrUp(lap_image[i],dstsize=lap_image[i-1].shape[:2]) 26 lapls = cv.subtract(lap_image[i-1],expand) 27 cv.imshow('lapls%s'%i,lapls) 28 29 src = cv.imread('1_512_512.jpg') #圖片大小是512*512 30 cv.imshow('input',src) 31 lap(src) 32 cv.waitKey(0) 33 cv.destroyAllWindows()
嘗試直接輸出expand不去subtract,會發現變模糊了
cv.imshow("lapls%s"%i,expand)