1.原理
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声。高斯滤波对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到,只不过在高斯滤波中,会将中心点的权重值加大,远离中心点的权重值减小。由此,正态分布对这一要求符合的很好,图像是二维的,选择二维的高斯函数:
通过选择不同的sigma和矩阵大小可以得到卷积模板(以下sigma=1.0,高斯核3*3):
但是通过这种方式计算到的矩阵内每个元素之和不为1,导致卷积得到的图像亮度会变化。小于1图像会变暗,大于1图像会变暗。
所以需要归一化这个矩阵,通过每一个元素除以总元素之和得到:
最后通过得到的矩阵与图像进行卷积运算。
2.算法流程及实现
高斯滤波会计算得到一个矩阵,来与图像进行卷积运算:
1).输入参数,矩阵大小、sigma、高斯函数;
2).计算得到卷积矩阵并进行归一化;
3).选取图像与矩阵大小的像素点与图像数据进行卷积运算,图像边缘补零;
4).迭代步骤3),直至所有像素遍历完全。
3.关键代码
// 高斯滤波
void guassBlur(unsigned char *data, unsigned char *dst, int width, int height, int kernel_size, float sigma)
{
int pad = floor(kernel_size / 2); // 用于坐标系转换
int _x = 0, _y = 0;
double kernel_sum = 0;
// get gaussian kernel
float kernel[kernel_size][kernel_size];
for (int y = 0; y < kernel_size; y++)
{
for (int x = 0; x < kernel_size; x++)
{
_y = y - pad;
_x = x - pad;
kernel[y][x] = 1 / (2 * PI * sigma * sigma) * exp(-(_x * _x + _y * _y) / (2 * sigma * sigma));
kernel_sum += kernel[y][x];
}
}
printf("kernel:\n");
// 归一化到1,并输出矩阵,如果不归一化,如果和小于1会导致图像变暗,如果和大于1会导致图像变亮
for (int y = 0; y < kernel_size; y++)
{
for (int x = 0; x < kernel_size; x++)
{
kernel[y][x] /= kernel_sum;
printf("%f ", kernel[y][x]);
}
printf("\n");
}
// guassianBlur
int _x1 = 0, _y1 = 0;
double sum = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
sum = 0;
for (int j = 0; j < kernel_size; j++)
{
for (int i = 0; i < kernel_size; i++)
{
_y1 = y + j - pad;
_x1 = x + i - pad;
if (_y1 >= 0 && _y1 < height && _x1 >= 0 && _x1 < width)
{
sum += data[_y1 * width + _x1] * kernel[j][i];
}
}
}
dst[y * width + x] = (unsigned char)sum;
}
}
}