我如何高斯模糊图像,而不使用任何内置的高斯函数?
我想使用本机高斯模糊公式模糊我的图像。 我读了这个 ,但我不知道如何实现这一点。
我如何使用公式来决定权重?
我不想使用像MATLAB那样的任何内置函数
写一个朴素的高斯模糊其实很简单。 这与其他卷积滤波器完全相同。 盒子和高斯滤波器之间唯一的区别就是你使用的matrix。
想象一下,你有一个图像定义如下:
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
一个3×3盒式filtermatrix定义如下:
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。
然后您将像素0乘以3×3模糊滤镜的左上部分。 由顶部中间的像素1,像素2,像素3,像素3,像素10,像素10,中间左边等。
然后将它们完全相加,并将结果写入像素11.正如您所看到的,像素11现在是其本身和周围像素的平均值。
边缘情况确实有点复杂。 你使用什么值的纹理的边缘值? 一种方法可以绕到另一边。 这对于稍后平铺的图像看起来很好。 另一种方法是将像素推入周围的地方。
所以左上方可能会放置样品如下:
0 0 1 0 0 1 10 10 11
我希望你能看到如何很容易地扩展到大的filter内核(即5×5或9×9等)。
高斯滤波器和盒式滤波器之间的区别在于matrix中的数字。 高斯滤波器在行和列上使用高斯分布。
例如对于任意定义的filter(即,这不是高斯的,但可能不是很远)
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.上述滤波器与原始盒式滤波器之间的差别在于,所写入的结束像素将具有朝向中央像素(即处于该位置的像素)的权重已经)。 模糊发生的原因是周围的像素确实模糊了该像素,但不是那么多。 使用这种filter,你会得到一个模糊,但不会破坏高频率(即像素之间的颜色快速变化)的信息。
这些filter可以做很多有趣的事情。 你可以通过从当前像素中减去周围的像素来使用这种滤波器来进行边缘检测。 这只会留下颜色(高频)真正的巨大变化。
编辑:一个5×5的filter内核是完全按照上面定义的。
例如,如果你的行是0.1 0.2 0.4 0.2 0.1,那么如果你乘以它们的第一个项目中的每个值形成一个列,然后乘以第二个项目,以形成第二个列,等等,你会得到一个filter的
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 * sqrtTwoPiTimesRadiusRecip); r++; } double div = Sum(kernel); for (int i = 0; i < kernel.Length; i++) { kernel[i] /= div; }
希望这可以帮助。
要使用维基百科文章中讨论的filter内核,您需要实现(离散) 卷积 。 这个想法是,你有一个小的matrix的值(内核),你移动这个核心从像素到像素在图像(即使matrix的中心是在像素上),matrix元素乘以重叠的图像元素,结果中的所有值,并用这个和来replace旧的像素值。
高斯模糊可以分成两个一维卷积(一个垂直和一个水平),而不是二维卷积,这也加快了一点。
我不清楚你是否想限制这种技术,但如果不是SVG(ScalableVectorGraphics)有一个高斯模糊的实现。 我相信它适用于包括像素在内的所有图元。 SVG具有开放标准和广泛实施的优点。
那么,高斯内核是一个可分离的内核。
因此,所有你需要的是支持可分离二维卷积的函数 – ImageConvolutionSeparableKernel()
。
一旦你有了它,所有需要的是一个生成一维高斯内核的包装,并发送到ImageConvolutionGaussianKernel()
完成的function。
该代码是由SIMD(SSE)和multithreading(OpenMP)加速的2D图像卷积的直接C实现。
整个项目是由 – 图像卷积 – GitHub 。