conv2
函数。假设我们有一个尺寸为5 x 5
的图像I
和一个尺寸为3 x 3
的卷积核K
。
conv2(I,K)
将返回一个7 x 7
的矩阵。我不知道还进行了哪些额外的操作?从数学角度来看,我完全可以理解conv2(I,K,'valid')
和conv2(I,K,'same')
的工作原理。然而,默认操作会返回一个更大的矩阵。有人知道它实际上是做什么吗?conv2
函数。假设我们有一个尺寸为5 x 5
的图像I
和一个尺寸为3 x 3
的卷积核K
。
conv2(I,K)
将返回一个7 x 7
的矩阵。我不知道还进行了哪些额外的操作?从数学角度来看,我完全可以理解conv2(I,K,'valid')
和conv2(I,K,'same')
的工作原理。然而,默认操作会返回一个更大的矩阵。有人知道它实际上是做什么吗?如果你知道'valid'
标志和'same'
标志的工作原理,那么默认选项'full'
就不难理解了。当滑动卷积核穿过图像/矩阵时,只要卷积核上至少有一个元素与图像/矩阵中的任何元素相接触,那么这就被视为有效输出。操作的输出由卷积核的中心位置决定,当有有效输出时。例如,看一下下面的5 x 5图像I
,以及一个3 x 3卷积核K
:
I = [1 2 3 4 5 ] K = [1 0 1]
[6 7 8 9 10] [1 0 1]
[11 12 13 14 15] [1 0 1]
[16 17 18 19 20]
[21 22 23 24 25]
注意数字并不是很重要,但它们用于说明。另外请注意核函数是对称的,因此进行180度旋转会得到相同的核函数。这是在开始卷积之前所要求的。在“full”配置中,我们从左上角向右下方以从左到右、从上到下的方式滑动核函数。当核函数的右下角接触图像/矩阵的左上角时,输出矩阵中第一个元素的输出就会出现:
[1 0 1]
[1 `0` 1]
[1 0 [1*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]
注意,当我们在图像上扫过卷积核的中心时,需要输出到图像中的位置用 `` 符号表示。请记住,在此处计算卷积时,我们找到卷积核中每个元素与其接触的矩阵/图像中的位置之间的加权和乘积。
请注意,对于超出边界的卷积核的任何元素,我们将忽略它们,因此输出仅为卷积核的右下角与图像左上角接触的位置,并将这些元素相乘。输出仅为1*1 = 1
。现在让我们移动到下一个元素,即向右移动1个单位:
[ 1 0 1]
[ 1 `0` 1]
[1 [0*1] [2*1] 3 4 5 ]
[6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]
[21 22 23 24 25]
注意中心点在哪里以及内核与矩阵接触的元素。因此,输出结果为0*1 + 2*1 = 2
。您将继续进行操作,直到到达该行末尾,其中内核的左下角接触到图像的右上角。然后,您将向下移动到下一行,在所有列上重复扫描,并继续上移,直到内核的左上角接触到图像/矩阵的右下角。
这里还有几个例子,只是为了确保您掌握了理论。让我们做内核接触到图像/矩阵顶部右侧的点。
[ 1 0 1]
[ 1 `0` 1]
[1 2 3 4 [5*1]] 0 1]
[6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]
[21 22 23 24 25]
请记住,我们忽略内核未接触图像/矩阵的所有位置。在这种情况下,输出将仅为5,并注意输出位置。以下是另一个示例:
[1 2 3 4 5 ]
[6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]
[1 0 [[21*1] 22 23 24 25]
[1 `0` 1]
[1 0 1]
这个位置位于图像/矩阵的左下角,输出结果仅为21*1
。再举一个例子以确保:
[1 2 3 4 5]
[6 7 8 9 10]
[11 12 13 14 [1*15]] 0 1]
[16 17 18 19 [1*20]] `0` 1]
[21 22 23 24 [1*25]] 0 1]
这个位置有点复杂。内核通过其第一列完全重叠图像/矩阵,因此输出仅为1*15 + 1*20 + 1*25 = 60
。还要注意输出位置位于倒数第三行,因为仍需执行两行过滤操作。其中一行是内核的前两行与图像/矩阵底部的最后两行接触,另一行是内核的第一行与图像/矩阵底部的最后一行接触。
因此,最终的输出矩阵可能类似于这样。
[1 2 * * * * 5 ]
[* * * * * * * ]
[* * * * * * * ]
[* * * * * * * ]
[* * * * * * 60]
[* * * * * * *]
[21 * * * * * *]
标有*
的元素是未知的,因为我还没有计算它们,但重点是要注意矩阵的最终大小。具体来说,请注意上面几个情况中需要将结果写入矩阵的输出位置。这就是您获得更大的矩阵的原因——以适应核不完全包含在图像/矩阵内但仍执行有效操作时的结果。正如您所看到的,您将需要两个额外的行:顶部和底部各1个,以及两个额外的列:左侧和右侧各1个。这导致一个 (5 + 2) x (5 + 2) = 7 x 7
的输出矩阵。通常情况下,如果核大小为奇数,则使用 'full'
2D 卷积得到的输出通常为 (rows + 2*floor(kernel_rows/2)) x (cols + 2*floor(kernel_cols/2))
,其中 rows
和 cols
是要过滤的图像/矩阵的行和列,而 kernel_rows
和 kernel_cols
则是核的行和列。
如果您想看一下 MATLAB 实际生成的内容,我们可以看看。使用我之前定义的输入图像/矩阵和核心,我们获得以下结果:
>> I = reshape(1:25,5,5).'; %'
>> K = [1 0 1; 1 0 1; 1 0 1];
>> out = conv2(I,K)
out =
`1` `2` 4 6 8 4 `5`
7 9 18 22 26 13 15
18 21 42 48 54 27 30
33 36 72 78 84 42 45
48 51 102 108 114 57 `60`
37 39 78 82 86 43 45
`21` 22 44 46 48 24 25
请注意,我已经在 MATLAB 输出的示例计算中标记了“``”字符。这与计算结果一致。
现在你真正想知道的是什么是“valid”和“same”。它们是“full”卷积的简化版本。“same”会输出与要过滤的图像/矩阵大小相同的输出,“valid”会输出仅包含核完全包含在图像/矩阵内的输出。当核超出图像/矩阵范围时,我们不将这些输出作为最终输出的一部分。简而言之,“valid”和“same”使用“full”结果,但移除结果的某些边框部分,以便于您选择的选项。