在这种情况下,卷积处理提取目标图像像素周围的图像像素块。当您执行图像卷积时,您使用所谓的 mask 或 point spread function 或 kernel 来执行此操作,这通常比图像本身的大小。
对于输出图像中的每个目标图像像素,您从输入中获取像素值的邻域,包括输入中位于相同目标坐标的像素。这个邻域的大小与掩码的大小完全相同。此时,您旋转遮罩,使其为 180 度,然后将遮罩中的每个值与邻域中每个位置重合的像素值逐个元素相乘。你把所有这些加起来,就是目标图像中目标像素的输出。
例如,假设我有这个小图像:
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
假设我想在 3 x 3 窗口内执行平均,所以我的掩码都是:
[1 1 1]
1/9*[1 1 1]
[1 1 1]
要执行 2D 图像卷积,将蒙版旋转 180 度仍会得到相同的蒙版,因此假设我想在第 2 行第 2 列找到输出。我要提取的 3 x 3 邻域是:
1 2 3
6 7 8
11 12 13
要找到输出,我会将掩码中的每个值乘以邻域的相同位置:
[1 2 3 ] [1 1 1]
[6 7 8 ] ** (1/9)*[1 1 1]
[11 12 13] [1 1 1]
执行逐点乘法并添加值会给我们:
1(1/9) + 2(1/9) + 3(1/9) + 6(1/9) + 7(1/9) + 8(1/9) + 11(1/9) + 12(1/9) + 13(1/9) = 63/9 = 7
输出图像中位置 (2,2) 的输出将为 7。
请记住,我没有解决面具超出范围的情况。具体来说,例如,如果我试图在第 1 行第 1 列找到输出,则掩码将在五个位置超出范围。有很多方法可以处理这个问题。有些人认为外面的那些像素为零。其他人喜欢复制图像边框,以便将边框像素复制到图像尺寸之外。有些人喜欢使用更复杂的技术来填充图像,例如进行对称填充,其中边框像素是图像内部内容的镜像,或者使用圆形填充,其中边框像素是从图像的另一侧复制而来的。
这超出了本文的范围,但在您的情况下,从最简单的情况开始,当您收集社区时,任何超出图像边界的像素都设置为零。
现在,k1 和 k2 是什么意思? k1 和 k2 表示相对于邻域和掩码中心的偏移。请注意,n1 - k1 和 n2 - k2 在总和中很重要。输出位置由n1 和n2 表示。因此,n1 - k1 和n2 - k2 是相对于该中心在水平方向n1 - k1 和垂直方向n2 - k2 上的偏移量。如果我们有一个3 x 3 掩码,则中心将是k1 = k2 = 0。左上角是k1 = k2 = -1。右下角是k1 = k2 = 1。它们趋于无穷大的原因是因为我们需要确保覆盖掩码中的所有元素。掩码的大小是有限的,所以这只是为了确保我们覆盖所有的掩码元素。因此,上面的总和简化为我之前所说的逐点求和。
下面是一个更好的例子,其中掩码是一个垂直 Sobel 滤波器,它可以在图像中找到垂直梯度:
来源:http://blog.saush.com/2011/04/20/edge-detection-with-the-sobel-operator-in-ruby/
如您所见,对于目标图像中的每个输出像素,我们查看输入图像中相同空间位置的像素邻域,在这种情况下为 3 x 3,我们执行加权元素通过掩码和邻域之间的元素总和,我们将输出像素设置为这些加权元素的总和。请记住,此示例不会将遮罩旋转 180 度,但这就是您在卷积时所做的。
希望这会有所帮助!