【翻譯:OpenCV-Python教程】圖像金字塔

⚠️由於自己的拖延症,3.4.3翻到一半,OpenCV發佈了4.0.0了正式版,所以接下來是按照4.0.0翻譯的。

⚠️除了版本之外,其他還是照舊,Image Pyramids,原文

目標

在這個章節,

  • 我們會學到圖像金字塔
  • 我們將會使用圖像金字塔來創造一個新的水果,“橘果”
  • 我們會遇到這些方法:cv.pyrUp()cv.pyrDown()

理論

通常情況下,我們處理的是大小不變的圖像。但在某些情況下,我們需要處理同一張圖像只是它的分辨率不同。例如,在檢索圖像中的某些對象時,比如臉,我們不確定該對象在我們提到的這張圖像中的大小。在這種情況下,我們需要創建一組具有不同分辨率的相同圖像,並在所有圖像中搜索對象。這組具有不同分辨率的圖像集合,我們稱之爲圖像金字塔(因爲當它們被保存在一個棧中時,分辨率最高的圖像位於底部,分辨率最低的圖像位於頂部(譯者注:因爲棧頂的數據先出,我們總是用較小分辨率的圖像先拿出來對比),看起來就像金字塔一樣)。

有兩種圖像金字塔。1) 高斯金字塔 和 2) 拉普拉斯金字塔
高斯金字塔高層(低分辨率)是通過除去低層中連續的行和列來構建起來的。每個處於高層的像素點是由這層下面的一層通過5像素內核用高斯權重算出來的。這麼做了之後,一個 M×N 的圖像就會變成 M/2×N/2 的圖像。因此面積也降到了原圖的 1/4。這就被稱爲一階。同樣的(變化)模式在不斷的往金字塔頂端前進的同時重複着(例如,分辨率降低)。同樣,圖像擴展時,面積會變成每一級增加至 4 倍。我們可以獲取到高斯金字塔(的某一階),通過函數 cv.pyrDown()cv.pyrUp()

img = cv.imread('messi5.jpg')
lower_reso = cv.pyrDown(higher_reso)

以下是一個圖像金字塔往上爬的4階:

messipyr.jpg

現在你可以往下爬金字塔,通過 cv.pyrUp() 函數。

(譯者注:OpenCV這個倆方法的命名Up和Down明顯不是針對這個金字塔的上下,而是針對圖像大小的上下。)

higher_reso2 = cv.pyrUp(lower_reso)

要記住的是,higher_reso2 和 higher_reso, 並不相等。因爲一旦你(往上爬一層)降低了分辨率之後,你就丟棄了部分圖像信息。以下圖像是用之前的示例中最小的圖像再往下爬三階之後的結果,用它和原圖比較:

messiup.jpg

拉普拉斯金字塔其實就是基於高斯金字塔構建起來的。它並沒有一個專門對應的函數。拉普拉斯金字塔就好像只有邊緣的圖像。它其中大部分的元素都是 0(譯者注:意思就是每一階看起來都是一片黑)。它被用於圖像壓縮,拉普拉斯金字塔中的某一階,等於這一階的高斯金字塔與這一階高斯金字塔的上一階的擴展版本之差(譯者注:意思就是拉普拉斯=高斯-高斯.down.up)。三階拉普拉斯金字塔看起來就如下圖所示(調整了對比度來增強圖像內容):

lap.jpg

用金字塔來混合圖像

圖像金字塔的其中一個應用就是用來混合圖像。例如,在縫合圖像的過程中,需要將兩幅圖像堆疊在一起,但由於圖像之間的不連續,可能一看就覺得不妥。在這種情況下,圖像與金字塔能讓圖像無縫的混合,而不會在圖像中留下太多數據。一個經典的例子是把兩種水果,橘子和蘋果混合在一起。看一下結果,理解我在說什麼:

orapple.jpg

請先查看附加資源中的參考資料,它提供了關於圖像混合、拉普拉斯金字塔等的完整的圖表細節。

簡單的說它是這麼做的:

  1. 加在蘋果和橘子這兩張圖
  2. 拿到蘋果和橘子的高斯金字塔(在這個例子中,金字塔的階數是6)
  3. 再通過高斯金字塔,算出拉普拉斯金字塔
  4. 現在把拉普拉斯金字塔每一階左邊的蘋果和右邊的橘子拼在一起
  5. 最後,通過這個拼接起來的金字塔,重構出一張“橘果”原圖

以下是完整代碼。(爲了易懂,每一個步驟被分開做了,這可能需要花更多的內存,如果想要的話,你可以自己優化一下。)

import cv2 as cv
import numpy as np,sys
A = cv.imread('apple.jpg')
B = cv.imread('orange.jpg')
# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in xrange(6):
    G = cv.pyrDown(G)
    gpA.append(G)
# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in xrange(6):
    G = cv.pyrDown(G)
    gpB.append(G)
# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in xrange(5,0,-1):
    GE = cv.pyrUp(gpA[i])
    L = cv.subtract(gpA[i-1],GE)
    lpA.append(L)
# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in xrange(5,0,-1):
    GE = cv.pyrUp(gpB[i])
    L = cv.subtract(gpB[i-1],GE)
    lpB.append(L)
# Now add left and right halves of images in each level
LS = []
for la,lb in zip(lpA,lpB):
    rows,cols,dpt = la.shape
    ls = np.hstack((la[:,0:cols/2], lb[:,cols/2:]))
    LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in xrange(1,6):
    ls_ = cv.pyrUp(ls_)
    ls_ = cv.add(ls_, LS[i])
# image with direct connecting each half
real = np.hstack((A[:,:cols/2],B[:,cols/2:]))
cv.imwrite('Pyramid_blending2.jpg',ls_)
cv.imwrite('Direct_blending.jpg',real)

額外資源

練習


上篇:【翻譯:OpenCV-Python教程】坎尼邊緣檢測

下篇:【翻譯:OpenCV-Python教程】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章