談談快速非局部去噪算法


        圖像去噪是一個經典的課題。然而,對於真實數碼照片,要想達到良好的去噪效果,且非易事。尤其是對於手機拍攝的照片,更是如此。如果你在光線不好的環境下,用手機前置攝像頭拍照,往往會有很多的噪聲。

   

        我們可以在任何一本關於數字圖像處理的教材上找到多種圖像去噪的方法。但是,這些經典的方法,對於真實圖像去噪的效果很不好。這些方法都會讓圖像變得模糊而導致很差的視覺效果。盡管用雙邊濾波可以達到較高的信噪比,但是其視覺效果依然很差。


       后來,人們提出了一種有效的去噪算法,這就是非局部均值。非局部均值是一種基於快匹配來確定濾波權值的。即先確定一個塊的大小,例如7x7,然后在確定一個搜索區域,例如15x15,在15x15這個搜索區域中的每一個點,計算7x7的窗口與當前濾波點7x7窗口的絕對差值和,然后在計算一個指數函數,所有的搜索點都用指數函數計算出一個權值,當然還有權值的歸一化。根據這個權值進行點的濾波操作。更具體的實現代碼如下:

 

function [output]=NLmeansfilter(input,t,f,h)


 % Size of the image
 [m n]=size(input);
 
 
 % Memory for the output
 Output=zeros(m,n);

 % Replicate the boundaries of the input image
 input2 = padarray(input,[f f],'symmetric');
 
 % Used kernel
 kernel = make_kernel(f);
 kernel = kernel / sum(sum(kernel));
 
 h=h*h;
 
 for i=1:m
 for j=1:n
                 
         i1 = i+ f;
         j1 = j+ f;
                
         W1= input2(i1-f:i1+f , j1-f:j1+f);
         
         wmax=0; 
         average=0;
         sweight=0;
         
         rmin = max(i1-t,f+1);
         rmax = min(i1+t,m+f);
         smin = max(j1-t,f+1);
         smax = min(j1+t,n+f);
         
         for r=rmin:1:rmax
         for s=smin:1:smax
                                               
                if(r==i1 && s==j1) continue; end;
                                
                W2= input2(r-f:r+f , s-f:s+f);                
                 
                d = sum(sum(kernel.*(W1-W2).*(W1-W2)));
                                               
                w=exp(-d/h);                 
                                 
                if w>wmax                
                    wmax=w;                   
                end
                
                sweight = sweight + w;
                average = average + w*input2(r,s);                                  
         end 
         end
             
        average = average + wmax*input2(i1,j1);
        sweight = sweight + wmax;
                   
        if sweight > 0
            output(i,j) = average / sweight;
        else
            output(i,j) = input(i,j);
        end                
 end
 end
 
function [kernel] = make_kernel(f)              
 
kernel=zeros(2*f+1,2*f+1);   
for d=1:f    
  value= 1 / (2*d+1)^2 ;    
  for i=-d:d
  for j=-d:d
    kernel(f+1-i,f+1-j)= kernel(f+1-i,f+1-j) + value ;
  end
  end
end
kernel = kernel ./ f;

        


 

       非局部算法獲得的信噪比比雙邊濾波略高,有時候還不如雙邊濾波。但是,非局部濾波是一種基於快的匹配度來計算濾波權值的,所以能獲得比較好的視覺效果。然而,它的計算復雜度實在是太高了。最原始非局部均值算法是在整個圖片中進行塊搜索,根據塊的匹配度來計算權值。實際執行過程,都會把搜索區域限定在一個局部的搜索窗口中,例如上面的代碼演示的就是這個過程。

        根據快匹配的思路,人們提出了很多種有效的去噪算法,這包括BM3D去噪算法。它的去噪效果比非局部去噪效果更好。還有另外一些基於快匹配的思路,例如DCT。由於傳統的非局部均值比較塊的相似度時用的是時域差值比較,如果我們在DCT域去比較相似度會更合理一些。並且,網上早已經有基於DCT域非局部均值的PhotoShop插件,這個插件的速度相當的慢。對於一般720p的圖像,在普通pc上都要半分鍾。由此可見,這類算法,如果沒有用GPU加速,要想實時,那是根本不可能的。

     於是,就有一些快速算法。主要的快速算法相關的文獻如下:

     1. FAST IMAGE AND VIDEO  DENOISING VIA NON-LOCAL MEANS OF SIMILAR  NEIGHBORHOOD, Mona Mahmoudi and Guillermo Saporo

     2. FAST NON-NOCAL ALGORITHM FOR IMAGE DENOISING, Jin Wang,Yanwen Guo 等

     3. FAST NON-NOCAL ALGORITHM FOR IMAGE DENOISING, Venkateswarlu Karnati,Mithun Uliyar, Sumit Dey


     其中:

        第一篇文獻的思路是用梯度和均值減少不必要的搜索點,其性能提高了不少,但還是沒法處理實時視頻。雖然他文獻中說是拿來處理視頻。

        第二篇文獻的思路是用FFT來計算的,其文中聲稱處理30w像素只需要350ms,而相對以原始的非局部方法28.16s,加速了80倍。對這個結果,我個人持懷疑態度。首先,他文中描述的原始NL算法的時間28.16s就有問題。在我們機器上,跑上述matlab代碼,需要2分鍾。一種可能的解釋是這篇文獻的FFT代碼可能是經過GPU加速過的。對於浙大的這篇文章,求實新聞網上曾津津樂道的報道過。

       第三篇文獻的思路,是用積分圖。單純的積分圖,明顯不行。但這篇文章的作者用的是多分辨率的積分圖。

     

       我覺得第三篇文獻的思路是比較靠譜的,所以就實現了下。但是發現這篇文獻的里面有一個公式5可能有點問題。如果按照公式5編程實現,效果相當的不好。於是,我根據文章的思路稍微改寫了一下公式5,效果就可以了。今后一些列的改進和優化,我的實現最終處理結果在我的I3機器上,處理30w像素的時間是700ms。本來想移植到iphone上,但是700ms的處理時間也沒法實時的處理視頻,后來就放棄了。


       本文的工作是我大約2年前做的,上述觀點只代表個人。







 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM