为什么高斯核值不是由等式生成并在书中给出?
我使用以下代码创建了高斯内核.
double gaussian(double x, double mu, double sigma) {
return std::exp(-(((x - mu) / (sigma))*((x - mu) / (sigma))) / 2.0);
}
typedef std::vector<double> kernel_row;
typedef std::vector<kernel_row> kernel_type;
kernel_type produce2dGaussianKernel(int kernelRadius) {
double sigma = kernelRadius / 2.;
kernel_type kernel2d(2 * kernelRadius + 1, kernel_row(2 * kernelRadius + 1));
double sum = 0;
// compute values
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++) {
double x = gaussian(row, kernelRadius, sigma)
* gaussian(col, kernelRadius, sigma);
kernel2d[row][col] = x;
sum += x;
}
// normalize
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++) {
kernel2d[row][col] /= sum;
}
}
return kernel2d;
}
结果是
0.01134 0.08382 0.01134
0.08382 0.61935 0.08382
0.01134 0.08382 0.01134
Press any key to continue . . .
这本书中给出了3×3高斯内核
{1 / 16.0f, 2 / 16.0f, 1 / 16.0f,
2 / 16.0f, 4 / 16.0f, 2 / 16.0f,
1 / 16.0f, 2 / 16.0f, 1 / 16.0f };
我徘徊为什么不是两个系数都相同.以及西格玛的哪个值,高斯内核(书中给出)掩码生成?
注意:我使用高斯方程生成高斯核
编辑:我在我的代码中添加了高斯函数.
最佳答案 好吧,本书的内核是一个二项式加权内核,可以在Pascal的三角形中找到,在3个系数的行上:1 2 1.矩阵中的每个单元格是对应于其行索引的系数,乘以对应的系数它的列索引,然后整个事情被规范化.
不幸的是,我找不到你的高斯函数的来源.我可以将你的函数输出与我猜测它的作用进行比较,但我真的不想花时间去做.
为什么这很重要,实际上有两种类型的高斯核.我怀疑你的内核使用熟悉的基于指数的高斯,一个标准化的exp(-x * x /(2 * s * s))或类似的东西.但是这样的内核仅在涉及连续函数的卷积中非常有效,而不是像图像数据那样的离散样本集.
所以另一个被称为“离散高斯核”.对于大sigma,它非常接近连续的Gausian内核,但对于小于4像素的sigma,离散版本与连续版本略有不同.
以下是维基百科文章的链接,其中包括离散高斯核:https://en.wikipedia.org/wiki/Scale_space_implementation#The_discrete_Gaussian_kernel
不幸的是,它很难计算,因为它依赖于修改的贝塞尔函数而不是标准数学库中提供的指数函数.
编辑
我继续挖掘我的代码来计算离散高斯核.我不能证明这个计算的算法是正确的,因为几年前我写了它,我不记得我是怎么想到的.对于固定的sigma和几个输入,下面的代码将来自Descrete高斯核的值与从高斯函数采样的值进行比较.
#include <iostream>
#include <iomanip>
#include <cmath>
// x is expected to be an integer value
double DiscreteGaussian(double x, double Sigma) {
x = std::fabs(x);
if(x > Sigma * 10) return 0;
double k = 0;
const double LnSigma_x_2 = std::log(Sigma) * 2;
const double Ca = x * (LnSigma_x_2 - std::log(2.0)) - (Sigma * Sigma);
double Ra = 0; // accumulated LnGamma(k + 1)
double Rb = std::lgamma(x + 1); // accumulated LnGamma(x + k + 1)
double Rc = 0; // accumulated k * (4*Ln(Sigma)-2*Ln(2))
const double Cc = 2.0 * (LnSigma_x_2 - std::log(2.0)); // const for Rc
double Sum;
double Next = std::exp(-Rb);
do {
Sum = Next;
k += 1;
Ra += std::log(k);
Rb += std::log(x + k);
Rc += Cc;
const double ExpTerm = Rc - Ra - Rb;
Next = Sum + std::exp(ExpTerm);
} while(Next != Sum);
return Sum * std::exp(Ca);
}
double ContinuousGaussian(double x, double Sigma) {
static const double NORMER = 0.3989422804014327; // 1/sqrt(2*pi)
const double x_as_sigmas = x / Sigma;
return std::exp(-0.5 * x_as_sigmas * x_as_sigmas) * NORMER / Sigma;
}
int main() {
// t is sigma squared, so for a t of 2, use a sigma of sqrt(2)
const double sigma = std::sqrt(0.5);
std::cout << "Sigma " << sigma << '\n';
std::cout << " x Discrete Sampled\n";
for(int x = -5; x<=5; ++x) {
const double yd = DiscreteGaussian(x, sigma);
const double yc = ContinuousGaussian(x, sigma);
std::cout << (x < 0 ? "" : " ") << x << " "
<< std::setw(14) << std::setprecision(8) << std::fixed << std::left
<< yd << " " << yc << '\n';
}
}
输出看起来像这样
Sigma 0.707107
x Discrete Sampled
-5 0.00000499 0.00000000
-4 0.00009996 0.00000006
-3 0.00160434 0.00006963
-2 0.01935206 0.01033349
-1 0.15642080 0.20755375
0 0.64503527 0.56418958
1 0.15642080 0.20755375
2 0.01935206 0.01033349
3 0.00160434 0.00006963
4 0.00009996 0.00000006
5 0.00000499 0.00000000
正如您所看到的,即使对于小sigma,差异也很小,并且根据应用的不同,可能不足以从使用采样连续高斯函数切换.