OpenCV每日函数 图像过滤模块 (11) getGaussianKernel函数

一、概述

        该函数返回高斯滤波器系数。

        该函数计算并返回 ksize×1 的高斯滤波器系数矩阵:

        其中i=0...ksize-1\alpha 是选择的比例因子,因此 \sum _iG_i=1。可以将两个这样的生成内核传递给 sepFilter2D。 这些函数会自动识别平滑内核(权重总和等于 1 的对称内核)并相应地处理它们。 您也可以使用更高级别的 GaussianBlur。

高斯核在每张 10 马克的德国钞票上都很明显,在他 55 岁时,它被描绘在其著名发明家旁边。现在欧元替代了马克

        高斯核在 1-D、2D 和 N-D 中分别定义为

二、getGaussianKernel函数

1、函数原型

cv::getGaussianKernel (int ksize, double sigma, int ktype=CV_64F)

2、参数详解

ksize 孔径大小。 它应该是奇数 (ksizemod2=1) 和正数。
sigma 高斯标准差。 如果它是非正数,则根据 ksize 计算为 sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8。
ktype 滤波器系数的类型。 它可以是 CV_32F 或 CV_64F 。

三、OpenCV源码

1、源码路径

opencv\modules\imgproc\src\smooth.dispatch.cpp

2、源码代码

Mat getGaussianKernel(int n, double sigma, int ktype)
{
    CV_CheckDepth(ktype, ktype == CV_32F || ktype == CV_64F, "");
    Mat kernel(n, 1, ktype);

    std::vector<softdouble> kernel_bitexact;
    getGaussianKernelBitExact(kernel_bitexact, n, sigma);

    if (ktype == CV_32F)
    {
        for (int i = 0; i < n; i++)
            kernel.at<float>(i) = (float)kernel_bitexact[i];
    }
    else
    {
        CV_DbgAssert(ktype == CV_64F);
        for (int i = 0; i < n; i++)
            kernel.at<double>(i) = kernel_bitexact[i];
    }

    return kernel;
}
static
softdouble getGaussianKernelBitExact(std::vector<softdouble>& result, int n, double sigma)
{
    CV_Assert(n > 0);
    //TODO: incorrect SURF implementation requests kernel with n = 20 (PATCH_SZ): https://github.com/opencv/opencv/issues/15856
    //CV_Assert((n & 1) == 1);  // odd

    if (sigma <= 0)
    {
        if (n == 1)
        {
            result = std::vector<softdouble>(1, softdouble::one());
            return softdouble::one();
        }
        else if (n == 3)
        {
            softdouble v3[] = {
                softdouble::fromRaw(0x3fd0000000000000),  // 0.25
                softdouble::fromRaw(0x3fe0000000000000),  // 0.5
                softdouble::fromRaw(0x3fd0000000000000)   // 0.25
            };
            result.assign(v3, v3 + 3);
            return softdouble::one();
        }
        else if (n == 5)
        {
            softdouble v5[] = {
                softdouble::fromRaw(0x3fb0000000000000),  // 0.0625
                softdouble::fromRaw(0x3fd0000000000000),  // 0.25
                softdouble::fromRaw(0x3fd8000000000000),  // 0.375
                softdouble::fromRaw(0x3fd0000000000000),  // 0.25
                softdouble::fromRaw(0x3fb0000000000000)   // 0.0625
            };
            result.assign(v5, v5 + 5);
            return softdouble::one();
        }
        else if (n == 7)
        {
            softdouble v7[] = {
                softdouble::fromRaw(0x3fa0000000000000),  // 0.03125
                softdouble::fromRaw(0x3fbc000000000000),  // 0.109375
                softdouble::fromRaw(0x3fcc000000000000),  // 0.21875
                softdouble::fromRaw(0x3fd2000000000000),  // 0.28125
                softdouble::fromRaw(0x3fcc000000000000),  // 0.21875
                softdouble::fromRaw(0x3fbc000000000000),  // 0.109375
                softdouble::fromRaw(0x3fa0000000000000)   // 0.03125
            };
            result.assign(v7, v7 + 7);
            return softdouble::one();
        }
        else if (n == 9)
        {
            softdouble v9[] = {
                softdouble::fromRaw(0x3f90000000000000),  // 4  / 256
                softdouble::fromRaw(0x3faa000000000000),  // 13 / 256
                softdouble::fromRaw(0x3fbe000000000000),  // 30 / 256
                softdouble::fromRaw(0x3fc9800000000000),  // 51 / 256
                softdouble::fromRaw(0x3fce000000000000),  // 60 / 256
                softdouble::fromRaw(0x3fc9800000000000),  // 51 / 256
                softdouble::fromRaw(0x3fbe000000000000),  // 30 / 256
                softdouble::fromRaw(0x3faa000000000000),  // 13 / 256
                softdouble::fromRaw(0x3f90000000000000)   // 4  / 256
            };
            result.assign(v9, v9 + 9);
            return softdouble::one();
        }
    }

    softdouble sd_0_15 = softdouble::fromRaw(0x3fc3333333333333);  // 0.15
    softdouble sd_0_35 = softdouble::fromRaw(0x3fd6666666666666);  // 0.35
    softdouble sd_minus_0_125 = softdouble::fromRaw(0xbfc0000000000000);  // -0.5*0.25

    softdouble sigmaX = sigma > 0 ? softdouble(sigma) : mulAdd(softdouble(n), sd_0_15, sd_0_35);// softdouble(((n-1)*0.5 - 1)*0.3 + 0.8)
    softdouble scale2X = sd_minus_0_125/(sigmaX*sigmaX);

    int n2_ = (n - 1) / 2;
    cv::AutoBuffer<softdouble> values(n2_ + 1);
    softdouble sum = softdouble::zero();
    for (int i = 0, x = 1 - n; i < n2_; i++, x+=2)
    {
        // x = i - (n - 1)*0.5
        // t = std::exp(scale2X*x*x)
        softdouble t = exp(softdouble(x*x)*scale2X);
        values[i] = t;
        sum += t;
    }
    sum *= softdouble(2);
    //values[n2_] = softdouble::one(); // x=0 in exp(softdouble(x*x)*scale2X);
    sum += softdouble::one();
    if ((n & 1) == 0)
    {
        //values[n2_ + 1] = softdouble::one();
        sum += softdouble::one();
    }

    // normalize: sum(k[i]) = 1
    softdouble mul1 = softdouble::one()/sum;

    result.resize(n);

    softdouble sum2 = softdouble::zero();
    for (int i = 0; i < n2_; i++ )
    {
        softdouble t = values[i] * mul1;
        result[i] = t;
        result[n - 1 - i] = t;
        sum2 += t;
    }
    sum2 *= softdouble(2);
    result[n2_] = /*values[n2_]*/ softdouble::one() * mul1;
    sum2 += result[n2_];
    if ((n & 1) == 0)
    {
        result[n2_ + 1] = result[n2_];
        sum2 += result[n2_];
    }

    return sum2;
}

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/125249171
今日推荐