双边滤波

原文地址:双边滤波

文中出现的2范数:

文中代码

//-------------------------------------------------------------
//作者:不用先生,2018.11.26
//自实现的图像双边滤波算法
//bilateral.cpp
//-------------------------------------------------------------
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <cmath>

using namespace std;
using namespace cv;



//--------------------------------------------------------------
//函数名:my_Bilateral
//函数功能:自己编写的可用于灰度图及彩色图的双边滤波函数;
//参数:Mat &scr:输入图像,为单通道灰度图或三通道彩色图;
//参数:Mat &dst:输出图像,尺寸与通道数与输入图像吻合;
//参数:int d:滤波器大小,应该保证为奇数;
//参数:double sigmaColor:颜色域/像素值域方差,sigmaColor越大,平滑效果越好,对边缘的保护越弱;
//参数:double sigmaSpace:空间域方差,sigmaSpace越大,结果越平滑;
//--------------------------------------------------------------
bool my_Bilateral(Mat &scr, Mat &dst, int d,  double sigmaColor, double sigmaSpace)
{
    if (!scr.data)
    {
        cerr << "输入图像错误,请检查" << endl;;
        return false;
    }
    if (d % 2 == 0)
    {
        cerr << "输入窗口大小应该为奇数,请修改"<<endl;
        return false;
    }


    dst = scr.clone();

    int row = dst.rows;       //获取图像大小;
    int col = dst.cols;

    int copyBorderSize =floor(0.5+ d / 2);
    Mat copyBorder_dst;
    copyMakeBorder(dst, copyBorder_dst, copyBorderSize, copyBorderSize, copyBorderSize, copyBorderSize, BORDER_REFLECT);

    int channels = dst.channels();
    if (channels == 1)     //如果是灰度图像
    {
        
        for (int i = 0; i < row; i++)    //对每一个点进行处理
        {
            for (int j = 0; j < col; j++)
            {
                double weightSum = 0;
                double filterValue = 0;
                for (int row_d = -(d / 2); row_d <= (d / 2); row_d++)   //以图像中的一点为中心,d为边长的方形区域内进行计算
                {
                    for (int col_d = -(d / 2); col_d <= (d / 2); col_d++)
                    {
                        double distance_Square = row_d*row_d + col_d*col_d;//row_d和col_d就是离中心点的距离
                        double value_Square = pow((scr.at<uchar>(i, j) - copyBorder_dst.at<uchar>(i + (d / 2) + row_d, j + (d / 2) + col_d)), 2);
                        double weight = exp(-1 * (distance_Square / (2 * sigmaSpace*sigmaSpace) + value_Square / (2 * sigmaColor*sigmaColor)));
                        weightSum += weight;               //求滤波窗口内的权重和,用于归一化;
                        filterValue += (weight*copyBorder_dst.at<uchar>(i + (d / 2) + row_d, j + (d / 2) + col_d));

                    }
                }
                dst.at<uchar>(i, j) = filterValue / weightSum;
                
            }
        }

        return true;
    }
    else if (channels == 3)     //如果是RGB图像
    {

        for (int c = 0; c < channels; c++)   //逐通道进行处理
        {
            for (int i = 0; i < row; i++)
            {
                for (int j = 0; j < col; j++)
                {
                    double weightSum = 0;
                    double filterValue = 0;
                    for (int row_d = -(d / 2); row_d <= (d / 2); row_d++)
                    {
                        for (int col_d = -(d / 2); col_d <= (d / 2); col_d++)
                        {
                            double distance_Square = row_d*row_d + col_d*col_d;
                            double value_Square = pow((scr.at<Vec3b>(i, j)[c] - copyBorder_dst.at<Vec3b>(i + (d / 2) + row_d, j + (d / 2) + col_d)[c]), 2);
                            double weight = exp(-1 * (distance_Square / (2 * sigmaSpace*sigmaSpace) + value_Square / (2 * sigmaColor*sigmaColor)));
                            weightSum += weight;
                            filterValue += (weight*copyBorder_dst.at<Vec3b>(i + (d / 2) + row_d, j + (d / 2) + col_d)[c]);

                        }
                    }
                    dst.at<Vec3b>(i, j)[c] = filterValue / weightSum;
                    
                }
            }
        }
        return true;

    }
    else
    {
        cerr << "图像通道数有误,请确定";
        return false;
    }

}

//----------------
//主函数
//----------------
void main()
{
    Mat scr = imread("03.jpg", IMREAD_UNCHANGED);  //以默认的方式读入图像

    if (!scr.data)               //判断图像是否被正确读取;
    {
        return;
    }

    int half_Window_Size = 10;   //窗口半宽大小
    int window_Size = 2 * half_Window_Size + 1;   //窗口大小,应该为奇数;
    double sigmaColor = 10;      //像素值域的方差
    double sigmaSpace = 10;      //空间域的方差


    //使用自实现的双边滤波对结果进行处理
    Mat my_dst = scr.clone();
    if (!my_Bilateral(scr, my_dst, window_Size, sigmaColor, sigmaSpace))
    {
        cerr << "自编写的双边滤波再计算过程中出差,请查验" << endl;
    }


    //用OpenCV自带的双边滤波函数进行处理
    Mat auto_dst = scr.clone();
    bilateralFilter(scr, auto_dst, window_Size, sigmaColor, sigmaSpace);

    //用高斯函数记性处理
    Mat gau_dst = scr.clone();
    Size gauSize(window_Size, window_Size);
    GaussianBlur(scr, gau_dst, gauSize, sigmaSpace);

    imwrite("temp1.jpg", my_dst);
    imwrite("temp2.jpg", auto_dst);
    imwrite("temp3.jpg", gau_dst);

    system("pause");
    return;

}
View Code

 

posted @ 2020-12-17 22:06  AI_ON  阅读(104)  评论(0)    收藏  举报