编写一个朴素的高斯模糊其实非常容易。它与任何其他卷积滤波器一样完成。唯一不同的是盒式滤波器和高斯滤波器使用的矩阵不同。
想象一下,你有一个定义如下的图像:
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
3x3盒子滤波器矩阵定义如下:
0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111
应用高斯模糊,您需要执行以下操作:
对于像素11,您需要加载像素0、1、2、10、11、12、20、21、22。
然后,您将用3x3的模糊滤镜的左上部分乘以像素0,用顶部中间乘以像素1,用右上方乘以像素2和像素3,用中间左侧乘以像素10等等。
然后将它们全部加起来,并将结果写入像素11。如您所见,像素11现在是自身和周围像素的平均值。
边缘情况会变得更加复杂。对于纹理边缘的值,您要使用什么值呢?一种方法是将其绕到另一侧。这适用于稍后铺设的图像。另一种方法是将像素推入周围位置。
因此,对于左上角,您可以将样本放置如下:
0 0 1
0 0 1
10 10 11
我希望您能看到这如何轻松地扩展到大的滤波核(例如 5x5 或 9x9 等)。0.1 0.8 0.1
第一列将相同,但乘以上一行的第一个项目。
0.01 0.8 0.1
0.08
0.01
第二列将是相同的,但其值将乘以上面行中的0.8(依此类推)。
0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01
将上述所有内容相加的结果应为1。与原始盒式滤波器相比,上述滤波器的不同之处在于写入的最终像素会更加偏向于中心像素(即已经在该位置的像素)。这种模糊是因为周围的像素确实模糊到了该像素,尽管没有那么明显。使用这种类型的滤波器可以实现模糊效果,但不会破坏太多高频信息(即从像素到像素快速变化的颜色)。
这些滤波器可以做很多有趣的事情。您可以使用此类滤波器进行边缘检测,方法是将当前像素减去周围像素。这将只留下颜色变化很大(高频率)的部分。
编辑:5x5滤波器核完全按照上述定义。
例如,如果您的行是0.1 0.2 0.4 0.2 0.1,则如果将它们中的每个值乘以第一个项目以形成一列,然后将每个值乘以第二个项目以形成第二列,以此类推,您最终将得到一个滤波器。
0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01
在任意位置上,您可以看到0,0位置是简单的0.1*0.1。0,2位置是0.1*0.4,2,2位置是0.4*0.4,而1,2位置是0.2*0.4。
希望这能给您一个足够好的解释。
这是我在C#中用于计算内核的伪代码。虽然我不敢说我正确处理了结束条件:
double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;
int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
double x = r * radiusModifier;
x *= x;
kernel[i] = sqrtTwoPiTimesRadiusRecip * Exp(-x * twoRadiusSquaredRecip);
r++;
}
double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
kernel[i] /= div;
}
希望这能帮到你。
sqrtTwoPiTimesRadiusRecip * Exp(-x * sqrtTwoPiTimesRadiusRecip);
应该改为:
sqrtTwoPiTimesRadiusRecip * Exp(-x * twoRadiusSquaredRecip);
。 - ashagisqrtTwoPiTimesRadiusRecip
。 - Emily L.高斯模糊可以分为两个1D卷积(一个垂直和一个水平),而不是2D卷积,这也可以加快速度。
我不确定您是否想要限制这个技术只用于某些特定的技术领域,但是如果没有的话,SVG(可缩放矢量图形)有一个高斯模糊的实现。我相信它适用于所有基元,包括像素。 SVG具有开放标准和广泛实现的优势。
ImageConvolutionSeparableKernel()
。ImageConvolutionGaussianKernel()
中所做的那样将其发送到函数中。