高斯滤波

高斯滤波

一、目的与原理

(1)目的:用于消除高斯噪声;

(2)原理:高斯噪声的特点是噪声分布服从正态分布,要消除这样分布的噪声那么处理的方法也需要有正态分布的思想,即对于图像而言,着重于处理图像中心,其次再稍微处理边缘,因为正态分布的特点是中间部分多,外侧比较少。所以卷积核的设计思路是中间点的权值最大,越靠近中间点的权值越大。

 

公式①:

 是一个常数,由于我们最终需要对高斯模板归一化,而常数不影响数值比例,所以可以忽略掉。我们实际要计算的部分是:

 

 

 

 

 

 

高斯滤波的步骤:

假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:

y轴水平向上,x轴水平向右。

 

根据二维高斯函数:,设定 的值,假设其=1.5可得权重矩阵:

 

 

 

归一化:

 

 

 

 

假设有九个点,灰度值如下图:

 

 

 

 

每个点乘以权重后的结果:

 

 

 

 

可得:

 这九个点的累加就是中心点的高斯模糊值。

 

 

二、算法步骤

(1)建立坐标系关系

(2)根据高斯函数计算出坐标矩阵的值

(3)对矩阵的值归一化

(4)卷积求和获得输出图像的灰度值

(5)将结果赋值到输出图像

(6)显示图像

 

三、伪代码

输入:卷积核大小wsize,高斯函数的sigma

输出:高斯模板Mask

void generateGaussMask(cv::Mat& Mask, cv::Size wsize, double sigma)

{

       for(循环处理点,生成各个坐标点){

              根据高斯函数算出坐标点对应的值

              对上一步的值归一化

              生成高斯模板Mask

  }  

}

 

输入:原图src,高斯模板Mask

输出:结果图dst

void GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat Mask)

{

       for(循环处理原图src像素点){

              if(图片为单通道){

      根据高斯模板Mask卷积求核获得输出图像的灰度值

      将灰度值赋值到输出图像中

    }

              if(图片为多通道){

      根据通道数,用高斯模板Mask卷积求核获得输出图像的各个通道的值

      将各个通道值赋值到输出图像中

    }     

  }

}

 

四、源码:

// 按二维高斯函数实现高斯滤波

void GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat kernel) {

    int hh = (kernel.rows - 1) / 2;

    int hw = (kernel.cols - 1) / 2;

    dst = cv::Mat::zeros(src.size(), src.type());

    //边界填充

    cv::Mat Newsrc;

    cv::copyMakeBorder(src, Newsrc,hh, hh, hw, hw, cv::BORDER_REPLICATE);//边界复制

 

    //高斯滤波

    for (int i = hh; i < src.rows + hh; ++i) {

        for (int j = hw; j < src.cols + hw; ++j) {

            double sum[3] = { 0 };

 

            for (int r = -hh; r <= hh; ++r) {

                for (int c = -hw; c <= hw; ++c) {

                    if (src.channels() == 1) {

                        sum[0] = sum[0] + Newsrc.at<uchar>(i + r, j + c) * kernel.at<double>(r + hh, c + hw);

                    }

                    else if (src.channels() == 3) {

                        cv::Vec3b rgb = Newsrc.at<cv::Vec3b>(i + r, j + c);

                        sum[0] = sum[0] + rgb[0] * kernel.at<double>(r + hh, c + hw);//B

                        sum[1] = sum[1] + rgb[1] * kernel.at<double>(r + hh, c + hw);//G

                        sum[2] = sum[2] + rgb[2] * kernel.at<double>(r + hh, c + hw);//R

                    }

                }

            }

 

            for (int k = 0; k < src.channels(); ++k) {

                if (sum[k] < 0)

                    sum[k] = 0;

                else if (sum[k] > 255)

                    sum[k] = 255;

            }

            if (src.channels() == 1)

            {

                dst.at<uchar>(i - hh, j - hw) = static_cast<uchar>(sum[0]);

            }

            else if (src.channels() == 3)

            {

                cv::Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };

                dst.at<cv::Vec3b>(i - hh, j - hw) = rgb;

            }

 

        }

    }

}

// x,y方向联合实现获取高斯模板

void generateGaussMask(cv::Mat& Mask, cv::Size wsize, double sigma) {

    Mask.create(wsize, CV_64F);

    int h = wsize.height;

    int w = wsize.width;

    int center_h = (h - 1) / 2;

    int center_w = (w - 1) / 2;

    double sum = 0.0;

    double x, y;

    for (int i = 0; i < h; ++i) {

        y = pow(i - center_h, 2);

        for (int j = 0; j < w; ++j) {

            x = pow(j - center_w, 2);

            //因为最后都要归一化的,常数部分可以不计算,也减少了运算量

            double g = exp(-(x + y) / (2 * sigma*sigma));

            Mask.at<double>(i, j) = g;

            sum += g;

        }

    }

    Mask = Mask / sum;

}

 

 

六、结果图

高斯模板:

 

 

 

原图、Opencv高斯函数处理结果、自定义高斯函数处理结果、原图+噪声、做差求算法区别:

 

 

 

 

posted @ 2021-04-28 10:42  will-z  阅读(1914)  评论(0编辑  收藏  举报