图像的双边滤波原理及C++代码实现

“双边”,顾名思义,两个方面,维度,双边滤波不仅考虑了空间位置,而且还考虑到了值域的相似性,在对图像进行滤波处理时,依据这两个标准来计算每个邻域中其它像素对目标像素(中心像素)的贡献,正是这种双重考量机制,使得双边滤波能够在平滑图像的同时,有效地保留边缘信息。

如下为双边滤波的实现原理图,其核心思想为双重权重,即图中的空间与亮度核,同时考虑两重因素,双维度对图像进行滤波处理,如左图中的input经双边滤波后,最终output既有效地保留了边缘,也对图像进行了平滑处理。

    1.空间相似性

    与目标像素 I(x, y) 物理位置越近的像素,其权重越大,与高斯滤波中的高斯核相同。

    如下为3×3邻域内,高斯模板的权重大小,越靠近目标(中心)像素,权重值越大

    (-1,1)

    (0,1)

    (1,1)

    0.0453542

    0.0566406

    0.0453542

    (-1,0)

    (0,0)

    (1,0)

    =>

    0.0566406

    0.0707355

    0.0566406

    (-1,-1)

    (0,-1)

    (1,-1)

    0.0453542

    0.0566406

    0.0453542

    一般在双边滤波中构建空间模板时,利用公式

    2.亮度相似性

    与目标像素 I(x, y) 亮度值越接近的像素,其权重越大。

    举个例子:如图中红色框邻域内的像素矩阵,取其中心3×3的邻域

    0

    0

    0

    0.8007374

    0.8007374

    0.8007374

    1

    1

    1

    =>

    1

    1

    1

    1

    1

    1

    1

    1

    1

    一般在双边滤波中构建亮度模板时,利用公式

    如高斯与双边滤波分别处理同一张图像,可明显看到高斯滤波模糊了大部分边缘细节,双边滤波在平滑图像的同时也有效地保留了边缘信息。

    //双边滤波
    void Bilateral_filter(Mat& src,Mat& dst,float sigma0,float sigma1,int kernel_size){
            int x = 0,y = 0;
            int offset = floor(kernel_size/2);
            float kernel[kernel_size][kernel_size];
            double kernel_sum = 0;
            //根据空间距离构建模板
            cout << "origin distance kernel value :"<< endl;
            for(int y = 0;y < kernel_size;y++){
                for(int x = 0;x < kernel_size;x++){
                    kernel[y][x] = exp(-((x-offset) * (x-offset) + (y-offset) * (y-offset))/(2 * sigma0 * sigma0));
                    cout << fixed << setprecision(7) << kernel[y][x] << " ";
                    kernel_sum += kernel[y][x];
                }
                cout << endl;
            }
            //利用灰度值构建模板
            unordered_map<int,float> map;//建立哈希表,方便查表使用
            for(int i = 0;i < 256;i++){
                map.insert({i,exp(-1.0*(i*i)/(2*sigma1*sigma1))});
            }
            int height = src.rows;
            int width = src.cols;
            for(int y = 0;y < height;y++){
                for(int x = 0;x < width;x++){
                    if(y-offset >= 0 && y + offset < height && x- offset >= 0 && x + offset < width){
                        float temp = 0,weight_sum = 0;
                        for(int yy = 0;yy < kernel_size;yy++){
                            for(int xx = 0;xx < kernel_size;xx++){
                                float element = src.at<uchar>(y-offset+yy,x- offset+xx) * 1.0;
                                float weight =  kernel[yy][xx]  * map.at(abs(src.at<uchar>(y-offset+yy,x- offset+xx) - src.at<uchar>(y,x)));
                                temp += element * weight;
                                weight_sum += weight;
                            }
                        }
                        temp /= weight_sum;//归一化 
                        dst.at<uchar>(y,x) = temp;
                    }
                } 
            }
            
    }

    谢谢观看!

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值