双边滤波是一种非线性滤波方法,是结合了图像的邻近度和像素值相似度的一种折中,在滤除噪声的同时可以保留原图的边缘信息。整个双边滤波是由两个函数构成:一个函数是由空间距离决定的滤波器系数,另外一个诗由像素差值决定的滤波器系数。整个双边滤波的公式如下:
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)} g(i,.j)=∑k,lw(i,j,k,l)∑k,lf(k,l)w(i,j,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}}) d(i,j,k,l)=exp(−2σd2(i−k)2+(j−l)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}}) r(i,j,k,l)=exp(−2σr2∣∣f(i,j)−f(k,l)∣∣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}}) w(i,j,k,l)=exp(−2σd2(i−k)2+(j−l)2−2σr2∣∣f(i,j)−f(k,l)∣∣2),其中第一个模板是全局模板,只需要生成就可以了。第二个模板需要对每个像素点滑动进行计算。双边滤波相对于高斯滤波多了一个高斯方差 σ d \sigma_d σd,它是给予空间分布的高斯滤波函数,所以在边缘附近,离得较远的像素不会太多影响到边缘的像素,所以可以更好的保留边缘信息,但是由于保留了过多高频信息,对于RGB图像中的高频噪声,双边滤波不能干净的滤掉,只能对低频噪声较好的滤除。
OpenCV中提供了双边滤波的实现,我们直接调用即可。
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
其中:
#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;
}