積分圖像的應用(二):非局部均值去噪(NL-means)

非局部均值去噪(NL-means)一文介紹了NL-means基本算法,同時指出了該算法效率低的問題,本文將使用積分圖像技術對該算法進行加速。

假設圖像共像個素點,搜索窗口大小,領域窗口大小, 計算兩個矩形鄰域間相似度的時間爲,對於每個像素點需要計算它與搜索窗口內個像素間的相似度,故NL-means複雜度爲

經過分析可以發現,該算法可以提高之處只有鄰域間相似度的計算,即耗時的操作。基本算法中,每次計算鄰域間距離時都需要遍歷兩個鄰域,逐對像素點求差值。

如果我們先構造一個關於像素差值的積分圖像:


其中

這樣在計算兩個鄰域 間的距離時,就可以在常量時間內完成:


這樣,整個算法複雜度將降爲

具體的算法描述可以參考[1]中:


爲了降低空間複雜度,上述算法將偏移量作爲最外層循環,即每次只需要在一個偏移方向上求取積分圖像,並對該積分圖像進行處理。而不需要一次性求取出所有積分圖像。

程序:

close all;
clear all;
clc
I=double(imread('lena.tif'));
I=I+10*randn(size(I));
tic
O1=NLmeans(I,2,5,10);
toc
tic
O2=fastNLmeans(I,2,5,10);
toc
figure;
imshow([I,O1,O2],[]);
function DenoisedImg=fastNLmeans(I,ds,Ds,h)
%I:含噪聲圖像
%ds:鄰域窗口半徑
%Ds:搜索窗口半徑
%h:高斯函數平滑參數
%DenoisedImg:去噪圖像
I=double(I);
[m,n]=size(I);
PaddedImg = padarray(I,[Ds+ds+1,Ds+ds+1],'symmetric','both');
PaddedV = padarray(I,[Ds,Ds],'symmetric','both');
average=zeros(m,n);
sweight=average;
wmax=average;
h2=h*h;
d2=(2*ds+1)^2;
for t1=-Ds:Ds
    for t2=-Ds:Ds
        if(t1==0&&t2==0)
            continue;
        end
        St=integralImgSqDiff(PaddedImg,Ds,t1,t2);
        v = PaddedV(1+Ds+t1:end-Ds+t1,1+Ds+t2:end-Ds+t2);
        w=zeros(m,n);
        for i=1:m
            for j=1:n
                i1=i+ds+1;
                j1=j+ds+1;
                Dist2=St(i1+ds,j1+ds)+St(i1-ds-1,j1-ds-1)-St(i1+ds,j1-ds-1)-St(i1-ds-1,j1+ds);
                Dist2=Dist2/d2;
                w(i,j)=exp(-Dist2/h2);
                sweight(i,j)=sweight(i,j)+w(i,j);
                average(i,j)=average(i,j)+w(i,j)*v(i,j);
            end
        end
        wmax=max(wmax,w);
    end
end
average=average+wmax.*I;
sweight=sweight+wmax;
DenoisedImg=average./sweight;

function Sd = integralImgSqDiff(PaddedImg,Ds,t1,t2)
%PaddedImg:邊緣填充後的圖像
%Ds:搜索窗口半徑
%(t1,t2):偏移量
%Sd:積分圖像
[m,n]=size(PaddedImg);
m1=m-2*Ds;
n1=n-2*Ds;
Sd=zeros(m1,n1);
Dist2=(PaddedImg(1+Ds:end-Ds,1+Ds:end-Ds)-PaddedImg(1+Ds+t1:end-Ds+t1,1+Ds+t2:end-Ds+t2)).^2;
for i=1:m1
    for j=1:n1
         if i==1 && j==1
             Sd(i,j)=Dist2(i,j);
         elseif i==1 && j~=1
             Sd(i,j)=Sd(i,j-1)+Dist2(i,j); 
         elseif i~=1 && j==1
             Sd(i,j)=Sd(i-1,j)+Dist2(i,j);
         else
             Sd(i,j)=Dist2(i,j)+Sd(i-1,j)+Sd(i,j-1)-Sd(i-1,j-1);
         end
     end
end

結果:


三幅圖像依次是含噪聲原圖,原始NL-means算法去噪結果、使用積分圖像加速的NL-means算法去噪結果。對於256*256的lena圖,原始算法耗時 36.251389s,使用積分圖像加速的算法耗時 4.647372s

當然,對於Matlab而言,若充分利用它的函數和矩陣操作,可進一步在編程上加速:

function DenoisedImg=fastNLmeans2(I,ds,Ds,h)
I=double(I);
[m,n]=size(I);
PaddedImg = padarray(I,[Ds+ds+1,Ds+ds+1],'symmetric','both');
PaddedV = padarray(I,[Ds,Ds],'symmetric','both');
average=zeros(m,n);
wmax=average;
sweight=average;
h2=h*h;
d=(2*ds+1)^2;
for t1=-Ds:Ds
    for t2=-Ds:Ds
        if(t1==0&&t2==0)
            continue;
        end
        Sd=integralImgSqDiff(PaddedImg,Ds,t1,t2);
        SqDist2=Sd(2*ds+2:end-1,2*ds+2:end-1)+Sd(1:end-2*ds-2,1:end-2*ds-2)...
               -Sd(2*ds+2:end-1,1:end-2*ds-2)-Sd(1:end-2*ds-2,2*ds+2:end-1);
        SqDist2=SqDist2/d;
        w=exp(-SqDist2/h2);
        v = PaddedV(1+Ds+t1:end-Ds+t1,1+Ds+t2:end-Ds+t2);
        average=average+w.*v;
        wmax=max(wmax,w);
        sweight=sweight+w;
    end
end
average=average+wmax.*I;
average=average./(wmax+sweight);
DenoisedImg = average;

function Sd = integralImgSqDiff(PaddedImg,Ds,t1,t2)
Dist2=(PaddedImg(1+Ds:end-Ds,1+Ds:end-Ds)-PaddedImg(1+Ds+t1:end-Ds+t1,1+Ds+t2:end-Ds+t2)).^2;
Sd = cumsum(Dist2,1);
Sd = cumsum(Sd,2);
使用上述fastNLmeans2函數對該lena圖處理僅耗時0.416442s

參考:

[1]FromentJ. Parameter-Free Fast Pixelwise Non-Local Means Denoising[J]. Image ProcessingOn Line, 2014, 4: 300-326
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章