我在 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。这是一笔可观的节省!
我正在为应该表示图像的二维数组制作一个简单的高斯模糊函数。该函数只是在最后打印出数组值(这里没有进行实际的图像处理)。我很确定我已经正确实施了所有内容,但是我得到的值 (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。这是一笔可观的节省!