如何使用 MATLAB 的 conv2 函数执行全卷积?

How is full convolution performed using MATLAB's conv2 function?

我正在尝试获取有关 MATLAB 的 conv2 函数的一些输入。假设我们有一个尺寸 5 x 5 的图像 I 和一个 3 x 3 的内核 K

conv2(I,K) 会 return 一个 7 x 7 矩阵。正在进行哪些我不知道的额外操作?我完全可以从数学的角度理解 conv2(I,K,'valid')conv2(I,K,'same') 是如何工作的。但是,默认操作 returns 是一个更大的矩阵。有谁知道它实际上是做什么的?

如果您知道 '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] 

请注意,当我们扫过图像时,内核的 centre 是我们需要在图像中输出的位置,用 `` 符号表示。请记住,要在这里计算卷积,我们会找到内核中每个元素与它在矩阵/图像中接触的位置之间的乘积的加权和逐元素总和。

请注意,对于超出边界的内核元素,我们将忽略,因此输出只是内核右下角和图像左上角接触的位置,我们将这些元素相乘。输出只是 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。另请注意,输出位置在 third-last 行,因为还有两行过滤要执行。内核的前两行接触图像/矩阵的底部最后两行,内核的第一行接触图像/矩阵的底部最后一行。

因此,最终的输出矩阵看起来像这样。

[1 2 * * * * 5 ]
[* * * * * * * ]
[* * * * * * * ]
[* * * * * * * ]
[* * * * * * 60]
[* * * * * *  *]
[21 * * * * * *]

标记为 * 的元素是未知的,因为我还没有计算它们,但关键是要注意矩阵的最终大小。具体来说,请注意输出位置是我们需要为您在上面看到的前几种情况写入矩阵的位置。这就是为什么你得到一个更大的矩阵的原因——当内核没有完全包含在图像/矩阵本身但仍然执行有效操作时,以适应结果。如您所见,您需要另外两行:顶部 1 行和底部 1 行,以及另外两列:左侧 1 列,右侧 1 列。这导致 (5 + 2) x (5 + 2) = 7 x 7 输出矩阵。一般来说,如果内核大小是奇数,使用 'full' 二维卷积得到的输出通常是 (rows + 2*floor(kernel_rows/2)) x (cols + 2*floor(kernel_cols/2)),其中 rowscols 是图像的行和列 /要过滤的矩阵,kernel_rowskernel_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' 如何影响这一切。 'valid''same' 进来的地方只是 截断 版本的 'full' 卷积。 'same' 给你一个与要过滤的图像/矩阵大小相同的输出,'valid' 给你一个输出,这样你只提供内核 完全包含在里面的输出图像/矩阵。任何时候内核超出图像/矩阵的界限,我们都不会将这些输出作为最终输出的一部分。简单地说,'valid''same' 使用 'full' 结果,但删除结果边框的某些部分以方便您选择的选项。