利用拉普拉斯對高頻信息的保留,重建出原始圖像
操作過程如下
對於兩張圖像
可以看到兩張同樣的圖片一個臉部模糊一個除了臉其他地方模糊,現在我們需要通過局部能量匹配的融合方法對圖像進行增強,即基於能量特徵重建
通過一個簡單的二階差分可以看到兩幅圖邊緣差異,即一個臉部模糊一個除了臉其他地方模糊
所謂能量就是二階差分的邊緣像素強度,融合過程中對不同尺度上的兩幅圖提取能量最強的區域進行融合。
能量匹配過程如下步驟:
- 若該點匹配度M<e,則選擇該點能量大的圖,捨棄其餘。
- 若該點匹配度M>e,則根據能量大小分配權重,能量小的權重爲
能量大的權重爲
融合代碼爲
E1 = imfilter(F11.^2, f, 'replicate');%計算能量
E2 = imfilter(F12.^2, f, 'replicate');
M = imfilter(F11.*F12, f, 'replicate').^2./(E1.*E2);%計算匹配度
F11(E1<E2) = F12(E1<E2);%匹配度低時
W_min = 0.5*(1 - (1-M)./(1-e));%計算權重
W_max = 1 - W_min;
F21 = W_min.*pyr1{i}+W_max.*pyr2{i};
F22 = W_min.*pyr2{i}+W_max.*pyr1{i};
F21(E1>E2) = F22(E1>E2);%匹配度高時
F11(M>e) = F21(M>e);%按匹配度計算
試驗結果:
下面給出完整matlab代碼
%局部能量特徵
clc
clear
close all
im1 = im2double(imread('lena1.jpg'));
im2 = im2double(imread('lena2.jpg'));
im1=im1(:,:,1);
im2=im2(:,:,1);
level = 4;%金字塔層數
sigma = 1;%金字塔每層提取的細節尺度。小了可能導致細節提取不充分,大了可能會導致融合結果失真。
im1_pyr = MLPD(im1, level, sigma);
im2_pyr = MLPD(im2, level, sigma);
pyr = pyr_fusion(im1_pyr, im2_pyr);
out = pyr{level};
for i = level-1 : -1 : 1
out = pyr{i} + imresize(out,[size(pyr{i},1) size(pyr{i},2)],'bilinear');
end
imshow([im1 im2 out])
%------------------------------函數1 金字塔分解------------------------------
function pyr = MLPD(I, nlev, sigma)
%Laplacian Pyramid Decomposition
%多通道拉普拉斯金字塔分解
% nlev 金字塔層數
% sigma 高斯模糊程度
if ~exist('nlev', 'var')
nlev = 4;
end
if ~exist('sigma', 'var')
sigma = 1;
end
k = fspecial('gaussian', floor(sigma*3)*2+1, sigma);
%構建拉普拉斯金字塔
pyr = cell(nlev,1);
J = I;
for j = 1:nlev-1
J_blur = imfilter(J, k, 'replicate');
J_blur_down = J_blur(1:2:size(J_blur,1)-1,1:2:size(J_blur,2)-1, :); %downsample
J_blur_high = imresize(J_blur_down,[size(J_blur,1) size(J_blur,2)],'bilinear');
pyr{j} = J-J_blur_high;
J=J_blur_down;
end
pyr{nlev}=J_blur_down; %最上一層即爲高斯金字塔
end
%------------------------------函數2 金字塔融合------------------------------
function pyr = pyr_fusion(pyr1,pyr2, e)
%pyramid fusion
%局部能量特徵的拉普拉斯金字塔融合
if ~exist('e', 'var')
e = 0.6;
end
n = size(pyr1, 1);
pyr = cell(n, 1);
f = fspecial('average', [3 3]);
% 對每一層融合
for i=n:-1:1
F11 = pyr1{i};
F12 = pyr2{i};
E1 = imfilter(F11.^2, f, 'replicate');%計算能量
E2 = imfilter(F12.^2, f, 'replicate');
%figure()
%imshow(E1)
M = imfilter(F11.*F12, f, 'replicate').^2./(E1.*E2);%計算匹配度
F11(E1<E2) = F12(E1<E2);%匹配度低時
W_min = 0.5*(1 - (1-M)./(1-e));%計算權重
W_max = 1 - W_min;
F21 = W_min.*pyr1{i}+W_max.*pyr2{i};
F22 = W_min.*pyr2{i}+W_max.*pyr1{i};
F21(E1>E2) = F22(E1>E2);%匹配度高時
F11(M>e) = F21(M>e);%按匹配度計算
figure()
imshow((F11-min(F11))./(max(F11)-min(F11)))
pyr{i} = F11;
end
end
下面爲完整python代碼
import cv2,numpy as np
import matplotlib.pyplot as plt
萊娜1=cv2.imread('lena1.jpg')
萊娜2=cv2.imread('lena2.jpg')
萊娜1=cv2.cvtColor(萊娜1,cv2.COLOR_BGR2RGB)
萊娜2=cv2.cvtColor(萊娜2,cv2.COLOR_BGR2RGB)
plt.subplot(121)
plt.imshow(萊娜1)
plt.subplot(122)
plt.imshow(萊娜2)
萊娜1=cv2.resize(萊娜1,(256,256),interpolation=cv2.INTER_CUBIC)
萊娜2=cv2.resize(萊娜2,(256,256),interpolation=cv2.INTER_CUBIC)
層數=8
temp=萊娜1.copy()
for index in range(層數):
dst = cv2.pyrDown(temp)
def 創建拉普拉斯金字塔(path,level):
img=cv2.imread(path)
img=cv2.cvtColor(img,cv2.COLOR_RGB2BGR)
img= cv2.resize(img,(512,512),interpolation=cv2.INTER_CUBIC)
temp = img.copy()#拷貝圖像
高斯金字塔 = []
高斯金字塔.append(img)
for i in range(1,level):
下采樣 = cv2.pyrDown(temp)
高斯金字塔.append(下采樣)
temp = 下采樣.copy()
拉普拉斯金字塔 = [高斯金字塔[level-1]]
for i in range(level-1,0,-1):
上採樣 = cv2.pyrUp(高斯金字塔[i])
第L層的高斯金字塔 = cv2.subtract(高斯金字塔[i-1],上採樣)
拉普拉斯金字塔.append(第L層的高斯金字塔)
print('高斯金字塔層數:',len(高斯金字塔),'拉普拉斯金字塔:',len(拉普拉斯金字塔))
return 拉普拉斯金字塔
def 拉普拉斯卷積(原圖,卷積核大小):
卷積核=np.ones([卷積核大小,卷積核大小])*1/(卷積核大小*卷積核大小)
卷積圖 = np.zeros([原圖.shape[0]-(卷積核大小-卷積核大小//2),原圖.shape[1]-(卷積核大小-卷積核大小//2)])
print(原圖.shape)
原圖行數,原圖列數=原圖.shape
for y in range(卷積核大小//2,原圖行數-(卷積核大小-卷積核大小//2)):
for x in range(卷積核大小//2,原圖列數-(卷積核大小-卷積核大小//2)):
半徑=卷積核大小//2
拉普拉斯核 = np.array(([-1,-1,-1],[-1,8,-1],[-1,-1,-1]))
窗口=np.sum(原圖[x-半徑:x+半徑+1,y-半徑:y+半徑+1]*拉普拉斯核)
卷積圖[x, y] = 窗口
return 卷積圖
萊娜1灰度=cv2.cvtColor(萊娜1,cv2.COLOR_RGB2GRAY)
萊娜1卷積圖=拉普拉斯卷積(萊娜1灰度,3)
萊娜2灰度=cv2.cvtColor(萊娜2,cv2.COLOR_RGB2GRAY)
萊娜2卷積圖=拉普拉斯卷積(萊娜2灰度,3)
plt.subplot(121)
plt.imshow(萊娜1卷積圖,'gray')
plt.subplot(122)
plt.imshow(萊娜2卷積圖,'gray')
def 平均值卷積(原圖,卷積核大小,通道):
def 單通道卷積(原圖,卷積核大小):
原圖=cv2.copyMakeBorder(原圖,卷積核大小//2,卷積核大小//2,卷積核大小//2,卷積核大小//2,cv2.BORDER_CONSTANT,0)
卷積核=np.ones([卷積核大小,卷積核大小])*1/(卷積核大小*卷積核大小)
卷積圖 = np.zeros([原圖.shape[0]-(卷積核大小-卷積核大小//2),原圖.shape[1]-(卷積核大小-卷積核大小//2)])
原圖行數,原圖列數=原圖.shape
for y in range(卷積核大小//2,原圖行數-(卷積核大小-卷積核大小//2)):
for x in range(卷積核大小//2,原圖列數-(卷積核大小-卷積核大小//2)):
半徑=卷積核大小//2
窗口=原圖[x-半徑:x+半徑+1,y-半徑:y+半徑+1]
卷積圖[x-1, y-1] = np.mean(窗口)
return 卷積圖
if 通道==3:
for chanel in range(通道):
原圖[:,:,chanel]=單通道卷積(原圖[:,:,chanel],卷積核大小)
return 原圖
return 單通道卷積(原圖,卷積核大小)
層數=3
萊娜=cv2.cvtColor(cv2.imread('lena.jpg'),cv2.COLOR_RGB2BGR)
拉普拉斯金字塔1=創建拉普拉斯金字塔('lena1.jpg',層數)
拉普拉斯金字塔2=創建拉普拉斯金字塔('lena2.jpg',層數)
萊娜灰度1=cv2.cvtColor(cv2.imread('lena1.jpg'),cv2.COLOR_BGR2GRAY)
萊娜灰度2=cv2.cvtColor(cv2.imread('lena2.jpg'),cv2.COLOR_BGR2GRAY)
萊娜1=cv2.cvtColor(cv2.imread('lena1.jpg'),cv2.COLOR_RGB2BGR)
萊娜2=cv2.cvtColor(cv2.imread('lena2.jpg'),cv2.COLOR_RGB2BGR)
萊娜灰度卷積=平均值卷積(萊娜灰度1,3,1)
print(萊娜灰度卷積.shape)
plt.figure('萊娜灰度卷積')
plt.imshow(萊娜灰度卷積,'gray')
能量復原算法
拉普拉斯金字塔4=[]
通道數=3
e=0.6
for i in range(0,層數):
F=np.zeros(拉普拉斯金字塔1[i].shape)
for chanel in range(通道數):
F12=拉普拉斯金字塔1[i][:,:,chanel]
F11=拉普拉斯金字塔2[i][:,:,chanel]
E1 = 平均值卷積(F11,3,1)
E2 = 平均值卷積(F12,3,1)
M = np.power(平均值卷積(np.dot(F11,F12),3,1),2)/np.dot(E1,E2)
F11[E1<E2] = F12[E1<E2] #匹配度低時
W_min = 0.5*(1 - (1-M)/(1-e))
W_max = 1 - W_min
print(拉普拉斯金字塔1[i].shape,拉普拉斯金字塔2[i].shape)
# 兩圖分別乘以權值
F21 = np.dot(W_min,拉普拉斯金字塔1[i][:,:,chanel])+np.dot(W_max,拉普拉斯金字塔2[i][:,:,chanel])
F22 = np.dot(W_min,拉普拉斯金字塔2[i][:,:,chanel])+np.dot(W_max,拉普拉斯金字塔1[i][:,:,chanel])
#匹配度高時
F21[E1>E2] = F22[E1>E2]
F11[M>e] = F21[M>e] #按匹配度計算
print(F11.shape,F12.shape,E1.shape,E2.shape)
F[:,:,chanel]=F11
F=(F-np.min(F))/(np.max(F)-np.min(F))
plt.figure()
plt.imshow(F)
拉普拉斯金字塔4.append(F)
#融合
ls_ = 拉普拉斯金字塔4[0]
for i in range(1,層數-1):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, 拉普拉斯金字塔4[i])
python結果
注:這裏我用的是jupyter,所以函數定義並沒那麼集中,以及爲了方便明確算法步驟,命名我故意使用的中文,至於爲什麼融合結果python和matlab有那麼大差異我也不太清楚