第十一章: 圖像金字塔
一、什么是圖像金字塔?
同一張圖片不同分辨率的子圖的集合。
圖像金字塔底部是待處理的高分辨率圖像,也就是原始圖像,頂部是低分辨率的近似圖像。一般情況下,都是每向上移動(dòng)一級(jí),圖像的寬和高都降低為原來(lái)的1/2 。
二、為什么要生成圖像金字塔,圖像金字塔能干啥?
- 1、我們可以提取更'有用'的特征。如果一張圖片是1024x1024大小的,那么它就有100萬(wàn)多個(gè)像素點(diǎn),如果我們把圖片的原始數(shù)據(jù)喂入神經(jīng)網(wǎng)絡(luò)模型,光輸入的神經(jīng)元數(shù)量都要100多萬(wàn)個(gè),計(jì)算資源會(huì)迅速崩掉。圖像金字塔是對(duì)圖像尺寸進(jìn)行的處理,這樣有利于我們提取最'有用'的特征,或者說(shuō)進(jìn)行降維操作。
- 2、可以避免模型過(guò)擬合。在某些圖像處理的算法中,圖像金字塔這種的多分辨率運(yùn)算可以避免陷入局部點(diǎn),增強(qiáng)模型魯棒性。
- 3、圖像金字塔底層是清晰的原始圖像,越往上圖像越模糊,因此我們可以通俗的理解:在底層可以看清楚更多的圖像細(xì)節(jié),在高層只可以看到輪廓。所以,在目標(biāo)檢測(cè)領(lǐng)域,圖像中的物體通常很可能是遠(yuǎn)近不一,大小不一的,此時(shí)我們就可以利用金字塔來(lái)檢測(cè)不同尺度下的物體。這種方法要比使用不同大小的sliding window在原圖上做檢測(cè)節(jié)省太多的算力!并且效果也要好很多!
- 4、對(duì)一張圖像構(gòu)建不同的尺度空間,這種操作在目標(biāo)檢測(cè)中非常有用,比如最簡(jiǎn)單的Viola的人臉檢測(cè)器就是用的這個(gè)技術(shù)。
- 5、圖像金字塔從另外一個(gè)角度理解就是:它將原圖像分別分解到不同的空間頻帶上,所以可以用在多分辨率融合算法中,融合過(guò)程是在各空間頻率層上分別進(jìn)行的,這樣就可以針對(duì)不同分解層的不同頻帶上的特征與細(xì)節(jié),采用不同的融合算子以達(dá)到突出特定頻帶上特征與細(xì)節(jié)的目的。也就是有可能將來(lái)自不同圖像的特征與細(xì)節(jié)融合在一起。
- 6、圖像金字塔用的最多的就是用在SIFT算法中,在SIFT提取的時(shí)候,因?yàn)閠emplate上的局部特征跟目標(biāo)圖像上的實(shí)際特征可能存在尺度上的差異,使用尺度空間是為了達(dá)到尺度不變性。
- 7、在ORB的改進(jìn)算法中也可以運(yùn)用圖像金字塔解決尺度不變換特性。
- 8、SURF算法中也用到了圖像金字塔的思想。
小結(jié):要找原因,原因很多,也說(shuō)明圖像金字塔應(yīng)用很廣泛,是一個(gè)基礎(chǔ)理論和技術(shù)。其實(shí)在計(jì)算機(jī)視覺(jué)里,很多看似直觀且簡(jiǎn)單的東西往往有層出不窮用法,除了本章的金字塔,還有比如直方圖,比如二值化,比如卷積,比如積分圖,比如距離變換……等等。雖然都不是什么高級(jí)的難以理解的東西,但一旦用到巧處,就非常耐人尋味!
三、理論基礎(chǔ):下采樣、上采樣、濾波器
- 下采樣:自下而上生成一個(gè)圖像金字塔,最下面一般就是原圖,依次往上的圖片尺寸減半。
- 上采樣:自上而下生成一個(gè)圖像金字塔,最上面一般是一個(gè)尺寸較小的特征圖,依次往下的圖片尺寸變?yōu)樵瓉?lái)的二倍。
如果我們通過(guò)下采樣生成一個(gè)金字塔,最簡(jiǎn)單的做法就是:不斷地刪除圖像的偶數(shù)行和偶數(shù)列,重復(fù)這個(gè)過(guò)程,就得到一個(gè)金字塔。
如果我們通過(guò)上采樣生成一個(gè)金字塔,最簡(jiǎn)單的就是:在每列像素點(diǎn)的右邊插入值為0的列,在每行像素點(diǎn)下面插入值為0的行,不斷重復(fù),就生成一個(gè)金字塔了。
小結(jié):
1、下采樣是圖像不斷變小的過(guò)程,上采樣是圖像不斷變大的過(guò)程。
2、一個(gè)圖像下采樣一次,在執(zhí)行一次上采樣,雖然尺寸恢復(fù)到原圖像的尺寸,但像素值已經(jīng)改變?。?!也就是這兩種操作是不可逆的。
- 濾波器
為什么要用濾波器?
我們下采樣生成金字塔圖像時(shí),是直接刪除偶數(shù)行偶數(shù)列的操作,但這種操作意味著直接丟棄圖像中的信息!為了減輕圖像信息的丟失,我們?cè)谙虏蓸硬僮髦跋扔脼V波器對(duì)原始圖像濾波操作一遍,這樣濾波后的圖像就是原始圖像的近似圖像,此時(shí)我們?cè)趧h偶數(shù)行偶數(shù)列,就沒(méi)有直接的信息損失了。而對(duì)原始圖像進(jìn)行濾波操作有很多方法,比如我們可以用鄰域?yàn)V波器進(jìn)行操作,這樣生成的圖像就是平均金字塔。如果我們用高斯濾波器處理,我們就生成的是高斯金字塔?。
同理,當(dāng)我們上采樣生成圖像金字塔時(shí),我們直接右插入列下插入行操作,這種操作會(huì)生成大量的0值像素點(diǎn),這些0值像素點(diǎn)毫無(wú)意義,我們就需要對(duì)0值像素點(diǎn)進(jìn)行賦值。而賦值就是插值處理。插值處理也有很多方法,比如用區(qū)域均值補(bǔ)充,那生成的就是平均金字塔,如果用高斯核填充就是高斯金字塔。
四、上下采樣API:
下采樣:cv2.pyrDown(img [, dstsize, borderType])
上采樣:cv2.pyrUp(img [, dstsize, borderType])
默認(rèn)的尺寸都是一半一半的減小,或者一倍一倍的增加。
默認(rèn)的濾波器都是高斯濾波器。
五、高斯金字塔
#例11.1 對(duì)lena進(jìn)行下采樣
import cv2
import numpy as np
import matplotlib.pyplot as plt
lena0 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0)
lena1 = cv2.pyrDown(lena0)
lena2 = cv2.pyrDown(lena1)
lena3 = cv2.pyrDown(lena2)
lena4 = cv2.pyrDown(lena3)
Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(33,33)
axes1=Fig.add_subplot(Grid[:17,:17]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[:9,17:25]), plt.imshow(lena1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:5,25:29]), plt.imshow(lena2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[:3,29:31]), plt.imshow(lena3, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes5=Fig.add_subplot(Grid[:1,31:32]), plt.imshow(lena4, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()
#例11.2 對(duì)lena進(jìn)行上采樣
import cv2
import numpy as np
import matplotlib.pyplot as plt
lena0 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0) #512
lena1 = cv2.pyrUp(lena0) #1024
lena2 = cv2.pyrUp(lena1) #2048
lena3 = cv2.pyrUp(lena2) #4096
Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(16,16)
axes1=Fig.add_subplot(Grid[0,0]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[0:3,1:3]), plt.imshow(lena1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[0:5,3:7]), plt.imshow(lena2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[0:9,7:15]), plt.imshow(lena3, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()
#例11.3 對(duì)lena先下采樣再上采樣,看結(jié)果圖核原始圖的差異,然后再lena先上采樣再下采樣,看結(jié)果圖和原始圖的差異
import cv2
import numpy as np
import matplotlib.pyplot as plt
lena0 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0) #512
lena1 = cv2.pyrDown(lena0) #216
lena2 = cv2.pyrUp(lena1) #512
diff1 = lena2-lena0
lena11 = cv2.pyrUp(lena0) #1024
lena22 = cv2.pyrDown(lena11) #512
diff2 = lena22-lena0
Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(6,10)
axes1=Fig.add_subplot(Grid[:2,:2]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[0,2]), plt.imshow(lena1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:2,3:5]), plt.imshow(lena2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[:2,5:7]), plt.imshow(diff1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes21=Fig.add_subplot(Grid[2:4,:2]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes22=Fig.add_subplot(Grid[2:6,2:6]), plt.imshow(lena11, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes23=Fig.add_subplot(Grid[2:4,6:8]), plt.imshow(lena22, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes24=Fig.add_subplot(Grid[2:4,8:10]), plt.imshow(diff2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()
六、拉普拉斯金字塔
拉普拉斯金字塔是在高斯金字塔的基礎(chǔ)上生成的。
為啥要發(fā)明拉普拉斯金字塔?還是因?yàn)楦咚菇鹱炙?,雖然它用高斯核過(guò)濾了一遍,但或多或少還是有信息丟失,而這些丟失的信息就是拉普拉斯金字塔?。所以拉普拉斯金字塔的作用就在于能夠恢復(fù)圖像的細(xì)節(jié),就是我們從高層的尺寸小的特征圖中提取特征后,我們還能通過(guò)拉普拉斯金字塔數(shù)據(jù)找回高層像素點(diǎn)對(duì)應(yīng)的底層清晰度更高的圖像,就是返回來(lái)找到更多圖像的細(xì)節(jié)。
Li = Gi - PyrUp( PyrDown(Gi) )
其中,Gi:原始圖像 ; Li:拉普拉斯金字塔圖像文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-768572.html
#例11.4 對(duì)lena圖片構(gòu)造拉普拉斯金字塔
import cv2
import numpy as np
import matplotlib.pyplot as plt
lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0) #512
G0 = lena
G1 = cv2.pyrDown(G0)
G2 = cv2.pyrDown(G1)
G3 = cv2.pyrDown(G2)
L0 = G0 - cv2.pyrUp(G1)
L1 = G1 - cv2.pyrUp(G2)
L2 = G2 - cv2.pyrUp(G3)
Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(33,33)
axes1=Fig.add_subplot(Grid[:17,:17]), plt.imshow(G0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[:9,17:25]), plt.imshow(G1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:5,25:29]), plt.imshow(G2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[:3,29:31]), plt.imshow(G3, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(33,33)
axes1=Fig.add_subplot(Grid[:17,:17]), plt.imshow(L0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[:9,17:25]), plt.imshow(L1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:5,25:29]), plt.imshow(L2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-768572.html
#例11.5 使用拉普拉斯金字塔和高斯金字塔恢復(fù)原始圖像
import cv2
import numpy as np
import matplotlib.pyplot as plt
lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0) #512
#生成高斯金字塔
G0 = lena
G1 = cv2.pyrDown(G0)
G2 = cv2.pyrDown(G1)
G3 = cv2.pyrDown(G2)
#生成拉普拉斯金字塔
L0 = G0 - cv2.pyrUp(G1)
L1 = G1 - cv2.pyrUp(G2)
L2 = G2 - cv2.pyrUp(G3)
#恢復(fù)原始圖像
G0_1 = L0 + cv2.pyrUp(G1)
G1_1 = L1 + cv2.pyrUp(G2)
G2_1 = L2 + cv2.pyrUp(G3)
#確認(rèn)每層是否真的復(fù)原
f0 = G0_1 - G0
f1 = G1_1 - G1
f2 = G2_1 - G2
print(np.sum(abs(f0)))
print(np.sum(abs(f1)))
print(np.sum(abs(f2)))
0 0 0
到了這里,關(guān)于【OpenCV】第十一章: 圖像金字塔的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!