Python-OpenCV中的圖像處理-圖像金字塔
- 圖像金字塔
- 高斯金字塔
- 拉普拉斯金字塔
- 金字塔圖像融合
圖像金字塔
- 同一圖像的不同分辨率的子圖集合,如果把最大的圖像放在底部,最小的放在頂部,看起來像一座金字塔,故而得名圖像金字塔。
- cv2.pyrUp():上采樣
- cv2.pyrDown():下采樣
高斯金字塔
高斯金字塔的頂部是通過將底部圖像中的連續的行和列去除得到的。頂部圖像中的每個像素值等于下一層圖像中 5 個像素的高斯加權平均值。這樣操作一次一個 MxN 的圖像就變成了一個 M/2xN/2 的圖像。所以這幅圖像的面積就變為原來圖像面積的四分之一。這被稱為 Octave。連續進行這樣的操作我們就會得到一個分辨率不斷下降的圖像金字塔。我們可以使用函數cv2.pyrDown() 和 cv2.pyrUp() 構建圖像金字塔。
import numpy as np
import cv2
from matplotlib import pyplot as plt# 圖像金字塔 :同一圖像的不同分辨率的子圖集合
# 有兩種:高斯金字塔(Gaussian Pyramid) 和 拉普拉斯金字塔(Pyramid)
# 高斯金字塔 每次處理后圖像的面積變為原來的四分之一,也被稱為Octave
# cv2.pyrDown() #分辨率降低
# cv2.pyrUp() #分辨率增高img = cv2.imread('./resource/opencv/image/messi5.jpg')
lower_reso = cv2.pyrDown(img)
lower_reso2 = cv2.pyrDown(lower_reso)upper_reso = cv2.pyrUp(lower_reso2)
upper_reso2 = cv2.pyrUp(upper_reso)cv2.imshow('img', img)
cv2.imshow('lower_reso', lower_reso)
cv2.imshow('lower_reso2', lower_reso2)
cv2.imshow('upper_reso', upper_reso)
cv2.imshow('upper_reso2', upper_reso2)
cv2.waitKey(0)
cv2.destroyAllWindows()
拉普拉斯金字塔
拉普拉斯金字塔可以有高斯金字塔計算得來,公式如下:
Li = Gi - pyrUp( Gi + 1 )
式中:
- Li:表示拉普拉斯金字塔中的第i層
- Gi:表示高斯金字塔中的第i層
拉普拉金字塔的圖像看起來就像邊界圖,其中很多像素都是 0。他們經常
被用在圖像壓縮中。
圖中各標記含義如下:
- G0、G1、G2、G3分別是高斯金字塔的第0層、第1層、第2層、第3層。
- L0、L1、L2、分別是拉普拉斯金字塔的第0層、第1層、第2層。
- 向下的箭頭表示向下采樣操作(對應cv2.pyrDown()函數)
- 向右的箭頭表示向上采樣操作(對應cv2.pyrUp() 函數)
- "+"表示加法操作
- "-"表示減法操作
上圖中的操作關系有:
向下采樣:
- 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)
向上采樣恢復高分辨率圖像:
- G0 = L0 + cv2.pyrUp(G1)
- G1 = L1 + cv2.pyrUp(G2)
- G2 = L2 + cv2.pyrUp(G3)
上述關系是通過數學運算推導得到的。例如,已知L0=G0-cv2.pyrUp(G1),將表達式右側的cv2.pyrUp(G1)移到左側,就得到了表達式G0 = L0 + cv2.pyrUp(G1)。除此之外,G1和G2都可以通過拉普拉斯金字塔的構造表達式得到。如之前介紹的,拉普拉斯金字塔的目的就是為了恢復高分辨率的圖像。
# 拉普拉斯金字塔構建
G0 = cv2.imread("./resource/opencv/image/lena.jpg")
cv2.imshow("input image",G0)
G1=cv2.pyrDown(G0)
G2=cv2.pyrDown(G1)
G3=cv2.pyrDown(G2)
G4=cv2.pyrDown(G3)
L0 = cv2.subtract(G0,cv2.pyrUp(G1))
L1 = cv2.subtract(G1,cv2.pyrUp(G2))
L2 = cv2.subtract(G2,cv2.pyrUp(G3))
L3 = cv2.subtract(G3,cv2.pyrUp(G4))
cv2.imshow("G1",G1)
cv2.imshow("G2",G2)
cv2.imshow("G3",G3)
cv2.imshow("G4",G4)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np
import cv2# 拉普拉斯金字塔是由高斯金字塔計數得到,公式如下
# Li = Gi - PyrUP(PyrDown(Gi))# 拉普拉斯金字塔圖像看起來像是邊界圖,其中很多像素都是0,常被用在圖像壓縮中。import cv2 as cvif __name__ == '__main__':img = cv.imread("./resource/opencv/image/lena.jpg")down1 = cv.pyrDown(img)res = img - cv.pyrUp(down1)down2 = cv.pyrDown(down1)res2 = down1 - cv.pyrUp(down2)cv.imshow("img", img)cv.imshow("res", res)cv.imshow("res2", res2)cv.waitKey(0)cv.destroyAllWindows()
金字塔圖像融合
import numpy as np
import cv2
import sys# 實現上述效果的步驟如下:
# 1. 讀入兩幅圖像,蘋果和橘子
# 2. 構建蘋果和橘子的高斯金字塔( 6 層)
# 3. 根據高斯金字塔計算拉普拉斯金字塔
# 4. 在拉普拉斯的每一層進行圖像融合(蘋果的左邊與橘子的右邊融合)
# 5. 根據融合后的圖像金字塔重建原始圖像。A = cv2.imread('./resource/opencv/image/apple.jpg')
B = cv2.imread('./resource/opencv/image/orange.jpg')
print(A.shape)
print(B.shape)
# 生成高斯金字塔
G = A.copy()
gpA = [G]
for i in range(5):G = cv2.pyrDown(G)gpA.append(G)G = B.copy()
gpB = [G]
for i in range(5):G = cv2.pyrDown(G)gpB.append(G)
# 產生Laplacian金字塔
lpA = [gpA[5]]
for i in range(5,0,-1):GE = cv2.pyrUp(gpA[i])L = cv2.subtract(gpA[i-1],GE)lpA.append(L)lpB = [gpB[5]]
for i in range(5,0,-1):GE = cv2.pyrUp(gpB[i])L = cv2.subtract(gpB[i-1],GE)lpB.append(L)
# 合并
LS = []
for la,lb in zip(lpA,lpB):rows,cols,dpt = la.shapels = np.hstack((la[:,0:cols//2], lb[:,cols//2:]))LS.append(ls)
# 重新構建圖像
ls_ = LS[0]
for i in range(1,6):ls_ = cv2.pyrUp(ls_)ls_ = cv2.add(ls_, LS[i])
# 連接
real = np.hstack((A[:,:cols//2],B[:,cols//2:]))
cv2.imshow("apple",A)
cv2.imshow("orange",B)
cv2.imshow("LS",ls_)
cv2.imshow("Real",real)
cv2.waitKey()
cv2.destroyAllWindows()