如何在不使用任何内置高斯函数的情况下对图像进行高斯模糊?

Posted

技术标签:

【中文标题】如何在不使用任何内置高斯函数的情况下对图像进行高斯模糊?【英文标题】:How do I gaussian blur an image without using any in-built gaussian functions? 【发布时间】:2010-12-14 08:16:24 【问题描述】:

我想使用原生高斯模糊公式来模糊我的图像。我读了the Wikipedia article,但我不确定如何实现。

如何使用公式确定权重?

我不想使用任何像 MATLAB 那样的内置函数

【问题讨论】:

基本上你需要在MATLAB中实现一个相当于conv2()函数的卷积算子。然而,由于 2D Gaussian 可以分成两个 1D Gaussian,您只需要在 1D 上实现卷积函数,再加上正确的核矩阵。 【参考方案1】:

写一个简单的高斯模糊实际上很容易。它的完成方式与任何其他卷积滤波器完全相同。盒子和高斯滤波器之间的唯一区别是您使用的矩阵。

假设您有一个如下定义的图像:

 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的box filter矩阵定义如下:

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 乘以 3x3 模糊滤镜的左上部分。顶部中间的像素 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。

我希望这能给你一个足够好的解释。

【讨论】:

@Goz 假设我想使用一个 5x5 的过滤器内核,我该如何计算应该进入过滤器的权重? 可以提到关键字:神经网络分别是人工神经网络 @bitterblue:你能解释一下为什么神经网络与图像空间过滤有关吗? @Bitterblue:真的。如何?神经网络是一种机器学习算法。这是关于 2D 图像空间过滤。 @Bitterblue:公平点,你可以使用过滤器来提取机器学习的特征。它仍然与这个问题完全无关,但是......【参考方案2】:

这是我在 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); 根本不需要乘以sqrtTwoPiTimesRadiusRecip ,因为无论如何都要对内核进行规范化。 @Simson,我不确定你的编辑做了什么,除了在我同事的代码遇到相同问题后正式提出建议之外,我不相信你 @Charlie 我的编辑让您的声誉立即获得了 +2,因为当我点击“改进编辑”时,您的编辑无需等待第二位审阅者得到确认。当审核队列中的帖子有更多工作要做时,这是修复它的方法。检查编辑历史,没有任何信用被盗。 @Simson 我明白了,但我正在经历一场关于让我的名字/图片出现在问题页面上的权力之旅,而不仅仅是在历史上:(哈哈,哦,谢谢你的解释【参考方案3】:

要使用***文章中讨论的过滤器内核,您需要实现(离散)convolution。这个想法是你有一个小的值矩阵(内核),你在图像中从一个像素到另一个像素移动这个内核(即矩阵的中心在像素上),将矩阵元素与重叠的图像相乘元素,对结果中的所有值求和,并用这个和替换旧的像素值。

高斯模糊可以分成两个 1D 卷积(一个垂直和一个水平)而不是 2D 卷积,这也加快了速度。

【讨论】:

【参考方案4】:

我不清楚你是否想将这个限制在某些技术,但如果不是,SVG (ScalableVectorGraphics) 有一个高斯模糊的实现。我相信它适用于包括像素在内的所有基元。 SVG 具有作为开放标准和广泛实施的优势。

【讨论】:

我想使用高斯滤波器的基本定义,没有内置实现。我想自己实现它。【参考方案5】:

好吧,高斯核是一个可分离的核。 因此,您只需要一个支持可分离 2D 卷积的函数,例如 - ImageConvolutionSeparableKernel()

一旦你有了它,只需要一个包装器来生成一维高斯内核并将其发送到ImageConvolutionGaussianKernel()中所做的函数。

代码是由 SIMD (SSE) 和多线程 (OpenMP) 加速的 2D 图像卷积的直接 C 实现。

整个项目由-Image Convolution - GitHub给出。

【讨论】:

以上是关于如何在不使用任何内置高斯函数的情况下对图像进行高斯模糊?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不获取“TypeError:字符串索引必须是整数”的情况下对图像进行 numpy 切片

如何使用 OpenCV 在 Python 中为图像添加噪声(高斯/盐和胡椒等)[重复]

如何在不使用 OpenCV 中的内置函数翻转的情况下进行翻转?

利用OpenCV的函数GaussianBlur()对图像进行高斯滤波

如何在 MATLAB 中绘制显示二维高斯函数总和的图像?

在不使用 Java 中的内置排序方法的情况下对用户输入进行动态排序