雙邊濾波


1 雙邊濾波簡介

  雙邊濾波(Bilateral filter)是一種非線性的濾波方法,是結合圖像的空間鄰近度和像素值相似度的一種折衷處理,同時考慮空域信息和灰度相似性,達到保邊去噪的目的。具有簡單、非迭代、局部的特點。

  雙邊濾波器的好處是可以做邊緣保存(edge preserving),一般過去用的維納濾波或者高斯濾波去降噪,都會較明顯地模糊邊緣,對於高頻細節的保護效果並不明顯。雙邊濾波器顧名思義比高斯濾波多了一個高斯方差sigma-d,它是基於空間分布的高斯濾波函數,所以在邊緣附近,離的較遠的像素不會太多影響到邊緣上的像素值,這樣就保證了邊緣附近像素值的保存。但是由於保存了過多的高頻信息,對於彩色圖像里的高頻噪聲,雙邊濾波器不能夠干凈的濾掉,只能夠對於低頻信息進行較好的濾波。

2 雙邊濾波原理

  濾波算法中,目標點上的像素值通常是由其所在位置上的周圍的一個小局部鄰居像素的值所決定。在2D高斯濾波中的具體實現就是對周圍的一定范圍內的像素值分別賦以不同的高斯權重值,並在加權平均后得到當前點的最終結果。而這里的高斯權重因子是利用兩個像素之間的空間距離(在圖像中為2D)關系來生成。通過高斯分布的曲線可以發現,離目標像素越近的點對最終結果的貢獻越大,反之則越小。其公式化的描述一般如下所述:

                     

   其中的c即為基於空間距離的高斯權重,而用來對結果進行單位化。

  高斯濾波在低通濾波算法中有不錯的表現,但是其卻有另外一個問題,那就是只考慮了像素間的空間位置上的關系,因此濾波的結果會丟失邊緣的信息。這里的邊緣主要是指圖像中主要的不同顏色區域(比如藍色的天空,黑色的頭發等),而Bilateral就是在Gaussian blur中加入了另外的一個權重分部來解決這一問題。Bilateral濾波中對於邊緣的保持通過下述表達式來實現:

                     

                    

  其中的s為基於像素間相似程度的高斯權重,同樣用來對結果進行單位化。對兩者進行結合即可以得到基於空間距離、相似程度綜合考量的Bilateral濾波:

                  

  上式中的單位化分部綜合了兩種高斯權重於一起而得到,其中的c與s計算可以詳細描述如下:

                  

   且有

                   

   且有

  上述給出的表達式均是在空間上的無限積分,而在像素化的圖像中當然無法這么做,而且也沒必要如此做,因而在使用前需要對其進行離散化。而且也不需要對於每個局部像素從整張圖像上進行加權操作,距離超過一定程度的像素實際上對當前的目標像素影響很小,可以忽略的。限定局部子區域后的離散化公就可以簡化為如下形式:

                   

  上述理論公式就構成了Bilateral濾波實現的基礎。為了直觀地了解高斯濾波與雙邊濾波的區別,我們可以從下列圖示中看出依據。假設目標源圖像為下述左右區域分明的帶有噪聲的圖像(由程序自動生成),藍色框的中心即為目標像素所在的位置,那么當前像素處所對應的高斯權重與雙邊權重因子3D可視化后的形狀如后邊兩圖所示:

                   

  左圖為原始的噪聲圖像;中間為高斯采樣的權重;右圖為Bilateral采樣的權重。從圖中可以看出Bilateral加入了相似程度分部以后可以將源圖像左側那些跟當前像素差值過大的點給濾去,這樣就很好地保持了邊緣。為了更加形象地觀察兩者間的區別,使用Matlab將該圖在兩種不同方式下的高度圖3D繪制出來,如下:

                 

  上述三圖從左到右依次為:雙邊濾波,原始圖像,高斯濾波。從高度圖中可以明顯看出Bilateral和Gaussian兩種方法的區別,前者較好地保持了邊緣處的梯度,而在高斯濾波中,由於其在邊緣處的變化是線性的,因而就使用連累的梯度呈現出漸變的狀態,而這表現在圖像中的話就是邊界的丟失(圖像的示例可見於后述)。         

3 雙邊濾波實現步驟

  有了上述理論以后實現Bilateral Filter就比較簡單了,其實它也與普通的Gaussian Blur沒有太大的區別。這里主要包括3部分的操作: 基於空間距離的權重因子生成;基於相似度的權重因子的生成;最終filter顏色的計算。

3.1Spatial Weight

  這就是通常的Gaussian Blur中使用的計算高斯權重的方法,其主要通過兩個pixel之間的距離並使用如下公式計算而來:

                 

3.1Similarity Weight

  與基於距離的高斯權重計算類似,只不過此處不再根據兩個pixel之間的空間距離,而是根據其相似程度(或者兩個pixel的值之間的距離)。

            

   其中的表示兩個像素值之間的距離,可以直接使用其灰度值之間的差值或者RGB向量之間的歐氏距離。

 

/**
            * 雙邊濾波
            */
       function BBcolor(imgData, radius, sigma, sigma_color, channels) {
           var pixes = imgData.data,
               width = imgData.width,
               height = imgData.height,
               color_weight = [],
               channels = channels || 3,
               sigma_color = sigma_color || (radius / 3),
               coeff_color = -1 / (2 * sigma_color * sigma_color),
               radius = radius || 5;
 
           sigma = sigma || (radius / 3);
 
 
           var gaussEdge = radius * 2 + 1; // 高斯矩陣的邊長
           for (var i = 0; i < channels * 256; i++) {
               color_weight[i] = Math.exp(i * i * coeff_color);
           }
           var gaussMatrix = [],
               gaussSum = 0,
               a = 1 / (2 * sigma * sigma * Math.PI),
               b = -a * Math.PI;
 
           for (var i = -radius; i <= radius; i++) {
               for (var j = -radius; j <= radius; j++) {
                   var gxy = a * Math.exp((i * i + j * j) * b);
                   gaussMatrix.push(gxy);
                   // gaussSum += gxy; // 得到高斯矩陣的和,用來歸一化
               }
           }
 
           // 循環計算整個圖像每個像素高斯處理之后的值
           for (var x = 0; x < width; x++) {
               for (var y = 0; y < height; y++) {
                   var r = 0,
                       g = 0,
                       b = 0,
                       wsum = 0,
                       currentPixId0 = (y * width + x) * 4,
                       r0 = pixes[currentPixId0],
                       g0 = pixes[currentPixId0 + 1],
                       b0 = pixes[currentPixId0 + 2];
                   // 計算每個點的高斯處理之后的值
                   for (var i = -radius; i <= radius; i++) {
                       // 處理邊緣
                       var m = handleEdge(i, x, width);
                       for (var j = -radius; j <= radius; j++) {
                           // 處理邊緣
                           var mm = handleEdge(j, y, height);
 
                           var currentPixId = (mm * width + m) * 4;
 
                           var jj = j + radius,
                               ii = i + radius,
                               r1 = pixes[currentPixId],
                               g1 = pixes[currentPixId + 1],
                               b1 = pixes[currentPixId + 2];
 
                           var weight = gaussMatrix[jj * gaussEdge + ii] * color_weight[Math.abs(r1 - r0) + Math.abs(g1 - g0) + Math.abs(b1 - b0)];
                           r += pixes[currentPixId] * weight;
                           g += pixes[currentPixId + 1] * weight;
                           b += pixes[currentPixId + 2] * weight;
                           wsum += weight;
                       }
                   }
                   wsum = 1 / wsum;
                   var pixId = (y * width + x) * 4;
                   pixes[pixId] = ~~(wsum * r);
                   pixes[pixId + 1] = ~~(wsum * g);
                   pixes[pixId + 2] = ~~(wsum * b);
               }
           }
           imgData.data = pixes;
           return imgData;
       }
       function handleEdge(i, x, w) {
            var m = x + i;
            if (m < 0) {
                m = -m;
            } else if (m >= w) {
                m = w + i - x;
            }
            return m;
        }

 


免責聲明!

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



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