1. 程式人生 > >雙邊濾波原理及Opencv實現

雙邊濾波原理及Opencv實現

演算法原理

雙邊濾波是一種非線性濾波方法,是結合了影象的鄰近度和畫素值相似度的一種折中,在濾除噪聲的同時可以保留原圖的邊緣資訊。整個雙邊濾波是由兩個函式構成:一個函式是由空間距離決定的濾波器係數,另外一個詩由畫素差值決定的濾波器係數。整個雙邊濾波的公式如下:
g ( i , .

j ) = k , l
f ( k , l ) w ( i
, j , k , l )
k , l w ( i , j , k , l )
g(i,.j)=\frac{\sum_{k,l}f(k,l)w(i,j,k,l)}{\sum_{k,l}w(i,j,k,l)} ,權重係數 w ( i , j , k , l ) w(i,j,k,l) 取決於定義域核 d ( i , j , k , l ) = e x p ( ( i k ) 2 + ( j l ) 2 2 σ d 2 ) d(i,j,k,l)=exp(-\frac{(i-k)^2+(j-l)^2}{2\sigma_d^{2}}) 和值域核 r ( i , j , k , l ) = e x p ( f ( i , j ) f ( k , l ) 2 2 σ r 2 ) r(i,j,k,l)=exp(-\frac{||f(i,j)-f(k,l)||^2}{2\sigma_r^{2}}) 的乘積。
w ( i , j , k , l ) = e x p ( ( i k ) 2 + ( j l ) 2 2 σ d 2 f ( i , j ) f ( k , l ) 2 2 σ r 2 ) w(i,j,k,l)=exp(-\frac{(i-k)^2+(j-l)^2}{2\sigma_d^{2}}-\frac{||f(i,j)-f(k,l)||^2}{2\sigma_r^{2}}) ,其中第一個模板是全域性模板,只需要生成就可以了。第二個模板需要對每個畫素點滑動進行計算。雙邊濾波相對於高斯濾波多了一個高斯方差 σ d \sigma_d ,它是給予空間分佈的高斯濾波函式,所以在邊緣附近,離得較遠的畫素不會太多影響到邊緣的畫素,所以可以更好的保留邊緣資訊,但是由於保留了過多高頻資訊,對於RGB影象中的高頻噪聲,雙邊濾波不能幹淨的濾掉,只能對低頻噪聲較好的濾除。

演算法實現

OpenCV中提供了雙邊濾波的實現,我們直接呼叫即可。

void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );

其中:

  • InputArray src: 輸入影象,可以是Mat型別,影象必須是8位或浮點型單通道、三通道的影象。
  • OutputArray dst: 輸出影象,和原影象有相同的尺寸和型別。
  • int d: 表示在過濾過程中每個畫素鄰域的直徑範圍。如果這個值是非正數,則函式會從第五個引數sigmaSpace計算該值。
  • double sigmaColor: 顏色空間過濾器的sigma值,這個引數的值越大,表明該畫素鄰域內有越寬廣的顏色會被混合到一起,產生較大的半相等顏色區域。
  • double sigmaSpace: 座標空間中濾波器的sigma值,如果該值較大,則意味著顏色相近的較遠的畫素將相互影響,從而使更大的區域中足夠相似的顏色獲取相同的顏色。當d>0時,d指定了鄰域大小且與sigmaSpace無關,否則d正比於sigmaSpace.
  • int borderType=BORDER_DEFAULT: 用於推斷影象外部畫素的某種邊界模式,有預設值BORDER_DEFAULT.
    \quad 雙邊濾波的複雜度相對於其他濾波器也是比較高的,我呼叫Opencv實現了一個可以調節雙邊濾波3個可變引數進行濾波的程式放在下面。

程式碼

#include "opencv2/opencv.hpp"
#include "iostream"
#include "algorithm"
#include "vector"
using namespace std;
using namespace cv;

const int g_ndMaxValue = 100;
const int g_nsigmaColorMaxValue = 200;
const int g_nsigmaSpaceMaxValue = 200;
int g_ndValue, g_nsigmaColorValue, g_nsigmaSpaceValue;
Mat src, dst;
void on_bilateralFilterTrackbar(int, void*){
    bilateralFilter(src, dst, g_ndValue, g_nsigmaColorValue, g_nsigmaSpaceValue);
    imshow("filtering", dst);
}

int main(){
//    Mat src = imread("/home/streamax/CLionProjects/Paper/101507_588686279_15.jpg");
//    Mat dst;
//    bilateralFilter(src, dst, 9, 50, 50);
//    imshow("src", src);
//    imshow("dst", dst);
//    imwrite("../result.jpg", dst);
//    waitKey(0);
    src = imread("../101507_588686279_15.jpg");
    namedWindow("origin", WINDOW_AUTOSIZE);
    imshow("origin", src);
    g_ndValue = 9;
    g_nsigmaColorValue = 50;
    g_nsigmaSpaceValue = 50;
    namedWindow("filtering", WINDOW_AUTOSIZE);
    char dname[20];
    sprintf(dname, "Neighborhood diamter %d", g_ndMaxValue);
    char sigmaColorName[20];
    sprintf(sigmaColorName, "sigmaColor %d", g_nsigmaColorMaxValue);
    char sigmaSpaceName[20];
    sprintf(sigmaSpaceName, "sigmaSpace %d", g_nsigmaSpaceMaxValue);
    //建立軌跡條
    createTrackbar(dname, "filtering", &g_ndValue, g_ndMaxValue, on_bilateralFilterTrackbar);
    on_bilateralFilterTrackbar(g_ndValue, 0);
    createTrackbar(sigmaColorName, "filtering", &g_nsigmaColorValue, g_nsigmaColorMaxValue, on_bilateralFilterTrackbar);
    on_bilateralFilterTrackbar(g_nsigmaColorValue, 0);
    createTrackbar(sigmaSpaceName, "filtering", &g_nsigmaSpaceValue, g_nsigmaSpaceMaxValue, on_bilateralFilterTrackbar);
    on_bilateralFilterTrackbar(g_nsigmaSpaceValue, 0);
    waitKey(0);
    return 0;
}