【学习opencv】高斯滤波及其实现

高斯滤波及其实现

1.创建高斯滤波核

高斯滤波模板是通过二维高斯函数计算出来的:

G(x,y)=12πσ2ex2+y22σ2

高斯模板需要知道模板大小及σ值,再通过上述高斯函数来确定模板系数。例现有3x3高斯模板如下,以模板中心为坐标原点,其高斯函数中的 x2+y2 就是指模板在坐标系中离原点的距离。

模板的分类:有小数模板和整数模板
小数模板计算方法:利用高斯分布函数求得后,对其中每个元素的值除以模板系数和.
整数模板计算方法:利用高斯分布函数求得后,先归一化(左上角的元素为1),取整,再乘以模板取整后的系数和。

Note:高斯模板的大小与σ的选择:高斯核的宽度应该为方差σ的3倍,原理是因为高斯正态分布中的3σ原则。

2.用滑动窗体进行卷积滤波

Note:注意3通道的卷积运算,是分别选取该通道的进行运算。

效果

这里写图片描述

代码:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace std;
using namespace cv;
/*
*生成高斯滤波的模板
*function return 整型模板
@param: windowsize 模板的大小 奇数
@param: sigma 方差的大小
*/
vector<vector<int>> createGussInt(int windowsize,double sigma)
{
    /*计算小数模板
    *此时计算出来的小数模板不能直接用于高斯滤波,还需要进一步处理
    */
    vector<vector<double> > GussinDouble(windowsize, vector<double>(windowsize));
    int std = windowsize / 2;

    for (int i = 0; i < windowsize; i++)
    {
        for (int j = 0; j < windowsize; j++)
        {
            int tem = (i - std)*(i - std) + (j - std)*(j - std);
            //GussinDouble[i][j] = (1 / 2.0*pi*sigma)*exp(-tem / (2.0*sigma*sigma));
            GussinDouble[i][j] =exp(-tem / (2.0*sigma*sigma));
            cout << GussinDouble[i][j] << " ";
            if (j == windowsize - 1)cout << "\n";
        }
    }

    //变为整数模板:归一化,向下取整
    double k = 1 / GussinDouble[0][0];
    vector<vector<int>>GussinInt(windowsize, vector<int>(windowsize));
    for (int i = 0; i < windowsize; i++)
    {
        for (int j = 0; j < windowsize; j++)
        {
            GussinDouble[i][j] = GussinDouble[i][j] * k;
            GussinInt[i][j] = floor(GussinDouble[i][j]);
            cout << GussinInt[i][j] << " ";
            if (j == windowsize - 1)cout << "\n";
        }
    }

    return GussinInt;
}

/*
*高斯滤波
**采用滑动模板窗口的方法滤波处理图片,图片最外层因为滤波窗口的大小会出现没有计算的情况,这里选用opencv自带的边界扩展函数
@param: img 支持单通道和3通道的输入图像
@param: kernel 整型滤波核
*/
void Guss(Mat src,Mat &dst,vector<vector<int>>kernel)
{
    cout << "src.rows" << src.rows << endl;
    cout << "src.cols" << src.cols << endl;

    int std = kernel.size()/2;
    Mat tem;
    copyMakeBorder(src,tem,std,std,std,std, BORDER_REPLICATE);

    cout << "tem col:" << tem.cols << endl;
    cout << "tem.rows:" << tem.rows << endl;
    cout << "tem channels:" << tem.channels() << endl;
    uchar *p = tem.data;
    int step = tem.step[0];
    int channels = tem.channels();

    for (int i = std; i < tem.rows-std; i++)
    {
        for (int j = std*channels; j < (tem.rows - std)*channels; j = j + channels)//保证一列的遍历
        {
            double sum[3] = { 0 };
            for (int m = -std; m <= std; m++)
            {
                for (int n = -std; n <= std; n++)
                {

                    if(channels==1)sum[0]+= p[(i + m)*step + j + n] * kernel[std + m][std + n];
                    if (channels == 3) {
                        sum[0] += p[(i + m)*step + j + n*channels] * kernel[std + m][std + n];
                        sum[1] += p[(i + m)*step + j+1 + n*channels] * kernel[std + m][std + n];
                        sum[2] += p[(i + m)*step + j+2 + n*channels] * kernel[std + m][std + n];

                    }

                }
            }

            //饱和处理
        /*  for (int i = 0; i < 3; i++)
            {
                if (sum[i] > 255)sum[i] = 255;
                else if (sum[i] < 0)sum[0] = 0;
            }*/

            //赋值
            if (channels == 1)p[i*step + j] = sum[0];
            if (channels == 3) {
                p[i*step + j] = sum[0];
                p[i*step + j + 1] = sum[1];
                p[i*step + j + 2] = sum[2];
            }

        }

    }


    //range左包含右不包含
    dst = tem(Range(std, tem.rows - std),Range(std, tem.cols - std));
}

/*主函数*/
int main()
{

    Mat img = imread("test.jpg",1);
    vector<vector<int>>kernel;
    kernel=createGussDouble(3,0.8);
    Mat dst;
    imshow("img",img);
    Guss(img, dst,kernel);
    imshow("dst",dst);
    waitKey(0);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值