图像的二维卷积如何工作?
How does 2D convolution for images work?
最近在学图像处理,初学。我陷入了卷积的主题以及如何为图像实现它。让我简要介绍一下 - 图像的卷积通用公式如下:
x(n1,n2)
表示输出图像中的一个像素,但我不知道k1
和k2
代表什么。其实,这就是想学的东西。为了用某种编程语言实现这一点,我需要知道 k1
和 k2
代表什么。有人可以向我解释一下或引导我阅读一篇文章吗?如果有任何帮助,我将不胜感激。
$k_1$ 和 $k_2$ 是应该覆盖内核的整个定义区域的变量。
查看维基百科以获取更多描述:
http://en.wikipedia.org/wiki/Kernel_%28image_processing%29
在这种情况下,卷积处理提取出目标图像像素周围的图像像素块。当您执行图像卷积时,您使用所谓的 mask 或 point spread function 或 kernel[=79] 执行此操作=] 这通常比图像本身的大小小得多。
对于输出图像中的每个目标图像像素,您从输入中获取像素值的邻域,包括输入中位于相同目标坐标的像素。这个邻域的大小与掩码的大小完全相同。在这一点上,您 旋转 蒙版使其成为 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 window 内进行平均,所以我的掩码将全部为:
[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 列找到输出,例如,掩码将有五个位置超出范围。有很多方法可以处理这个问题。有些人认为外面的那些像素为零。其他人喜欢 复制 图像边框,以便在图像尺寸之外复制边框像素。有些人喜欢使用更复杂的技术来填充图像,例如进行对称填充,其中边界像素是图像内部内容的镜像,或者圆形填充,其中边界像素是从图像的另一侧复制的。
这超出了本 post 的范围,但在您的情况下,从最简单的情况开始,即在您收集邻域时超出图像边界的任何像素,将它们设置为零.
现在,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
。他们走向无穷大的原因是因为我们需要确保我们覆盖掩码中的 all 元素。面具的大小是有限的,所以这只是为了确保我们覆盖所有的面具元素。因此,上面的总和简化为我之前所说的逐点求和。
这是一个更好的说明,其中掩码是一个垂直的 Sobel 滤波器,它在图像中找到垂直梯度:
来源:http://blog.saush.com/2011/04/20/edge-detection-with-the-sobel-operator-in-ruby/
如您所见,对于目标图像中的每个输出像素,我们查看输入图像中相同空间位置的像素邻域,在本例中为 3 x 3,我们执行在掩码和邻域之间逐元素加权和,我们将输出像素设置为这些加权元素的总和。请记住,此示例 不会 将蒙版旋转 180 度,但这是您在卷积时所做的。
希望对您有所帮助!
最近在学图像处理,初学。我陷入了卷积的主题以及如何为图像实现它。让我简要介绍一下 - 图像的卷积通用公式如下:
x(n1,n2)
表示输出图像中的一个像素,但我不知道k1
和k2
代表什么。其实,这就是想学的东西。为了用某种编程语言实现这一点,我需要知道 k1
和 k2
代表什么。有人可以向我解释一下或引导我阅读一篇文章吗?如果有任何帮助,我将不胜感激。
$k_1$ 和 $k_2$ 是应该覆盖内核的整个定义区域的变量。 查看维基百科以获取更多描述: http://en.wikipedia.org/wiki/Kernel_%28image_processing%29
在这种情况下,卷积处理提取出目标图像像素周围的图像像素块。当您执行图像卷积时,您使用所谓的 mask 或 point spread function 或 kernel[=79] 执行此操作=] 这通常比图像本身的大小小得多。
对于输出图像中的每个目标图像像素,您从输入中获取像素值的邻域,包括输入中位于相同目标坐标的像素。这个邻域的大小与掩码的大小完全相同。在这一点上,您 旋转 蒙版使其成为 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 window 内进行平均,所以我的掩码将全部为:
[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 列找到输出,例如,掩码将有五个位置超出范围。有很多方法可以处理这个问题。有些人认为外面的那些像素为零。其他人喜欢 复制 图像边框,以便在图像尺寸之外复制边框像素。有些人喜欢使用更复杂的技术来填充图像,例如进行对称填充,其中边界像素是图像内部内容的镜像,或者圆形填充,其中边界像素是从图像的另一侧复制的。
这超出了本 post 的范围,但在您的情况下,从最简单的情况开始,即在您收集邻域时超出图像边界的任何像素,将它们设置为零.
现在,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
。他们走向无穷大的原因是因为我们需要确保我们覆盖掩码中的 all 元素。面具的大小是有限的,所以这只是为了确保我们覆盖所有的面具元素。因此,上面的总和简化为我之前所说的逐点求和。
这是一个更好的说明,其中掩码是一个垂直的 Sobel 滤波器,它在图像中找到垂直梯度:
来源:http://blog.saush.com/2011/04/20/edge-detection-with-the-sobel-operator-in-ruby/
如您所见,对于目标图像中的每个输出像素,我们查看输入图像中相同空间位置的像素邻域,在本例中为 3 x 3,我们执行在掩码和邻域之间逐元素加权和,我们将输出像素设置为这些加权元素的总和。请记住,此示例 不会 将蒙版旋转 180 度,但这是您在卷积时所做的。
希望对您有所帮助!