我在 C++ 中的二维数组高斯模糊函数有什么问题?

What is wrong with my 2D Array Gaussian Blur function in C++?

我正在为应该表示图像的二维数组制作一个简单的高斯模糊函数。该函数只是在最后打印出数组值(这里没有进行实际的图像处理)。我很确定我已经正确实施了所有内容,但是我得到的值 (N=3, sigma=1.5) 比基于此计算器的预期值低得多:http://dev.theomader.com/gaussian-kernel-calculator/

我遵循这个等式:

void gaussian_filter(int N, double sigma) {
  
  double k[N][N];
  for(int i=0; i<N; i++) { //Initialize kernal to 0
    for(int j=0; j<N; j++) {
      k[i][j] = 0;
    }
  }
   
  double sum = 0.0; //There is an issue somewhere in this block of code
  int change = (N/2);
  double r, s = change * sigma * sigma;
  for (int x = -change; x <= change; x++) {
    for(int y = -change; y <= change; y++) {
      r = sqrt(x*x + y*y);
      k[x + change][y + change] = (exp(-(r*r)/s))/(M_PI * s);
      sum += k[x + change][y + change];
    }
  }
  
  for(int i = 0; i < N; ++i) { //Normalize
    for(int j = 0; j < N; ++j) {
      k[i][j] /= sum;
    }
  }
  
  for(int i = 0; i < N; ++i) { //Print out array
    for (int j = 0; j < N; ++j)
      cout<<k[i][j]<<"\t";
    }
    cout<<endl;
  }    
}

这是 N=3 和 Sigma=1.5 的预期输出

这是 N=3 和 Sigma=1.5 的当前损坏输出

为什么 s 依赖于 change?我认为你应该这样做:

double r, s = 2 * sigma * sigma;
// instead of
// double r, s = change * sigma * sigma;

That website 以非正统方式计算高斯核:

The weights are calculated by numerical integration of the continuous gaussian distribution over each discrete kernel tap.

也就是说,它对一个连续的高斯核进行采样,该核与一个 1 像素宽的均匀(“框”)滤波器进行卷积。生成的高斯分布比宣传的要宽。我反对这种方法。

创建高斯核的正确方法是仅在给定的整数位置对高斯函数进行采样,例如 x = [-3, -2, -1, 0, 1, 2, 3]

请注意,3 像素内核的宽度不足以表示高斯分布。对曲线的尾部进行采样很重要,没有它,核就没有高斯核的良好特性。我建议每边最多采样 3 西格玛,导致 2*ceil(3*sigma)+1 像素。 2 sigma 是最低限度,仅当速度比好结果更重要时才有用。

另请注意,高斯是可分离的,您可以连续应用两个 1D 内核,而不是单个 2D 内核。对于 9x9 内核,sigma=1.5,这转化为 9+9=18 次乘法和加法,而 2D 内核为 9x9=81。这是一笔可观的节省!