使用 blockproc 或 im2col 在图像上重叠滑动 window?

Overlapping sliding window over an image using blockproc or im2col?

我必须将 dct2 应用到图像的小 windows,最好使用重叠的 window。

我发现 Matlab 中有两个函数可以使这成为可能 blockprocim2col。我也无法理解,希望得到一些说明。

blockproc 可用于使用 BorderSizeTrimBorder 参数在滑动 window 上实现我的功能。

B = blockproc(A,[64,64],fun,'BorderSize',[5,5], 'TrimBorder', 'false');

我意识到这会创建一个 [64 + 2*5, 64 + 2*5] 块并在每个块上应用函数 @fun。但是由于我无法在调试中进入我的函数 @fun 以验证正确的操作,所以我不能确定这就是我需要的。 我上面的代码是否符合我的需要?我知道我在 B 中得到了一个串联结果,但它应该在重叠的滑块上。这会达到我需要的吗?

第二个是im2colim2col(A,[m n],block_type)会把块分成m×n块,然后按列排列,那么每一列就是一个块?如果是这样,如何控制重叠?如果每个块都是一列,我能否在每一列上成功应用 dct2 函数?因为我怀疑它会将向量作为输入?

如能提供一些说明,我们将不胜感激。

好的,这是一个相当复杂的问题。我会尝试将其分解成不同的部分,并分别回答每个问题。

问题 #1

blockproc can be used to implement my function on a sliding window using the BorderSize and TrimBorder arguments.

B = blockproc(A,[64,64],fun,'BorderSize',[5,5], 'TrimBorder', 'false');

I realize that this creates a block of [64 + 2*5, 64 + 2*5] and applies the function @fun on each block. But since I cannot go into my function @fun in debugging to verify proper operation I cannot be sure this is what I need. Is my above code correct for what I need? I know that I get a concatenated result in B but it should be on a overlapping sliding block. Will this achieve what I need?

在使用 blockproc 进行试验后,这确实是正确的,您可以使用它来进行滑动邻域处理。但是,您将需要一个额外的标志,即 PadPartialBlocks。此标志的目的是,如果您要提取位于图像外边缘的块并且无法制作指定大小的块,这将对该部分块进行零填充以使其符合到相同的大小。这是一个使用滑动 windows 的小例子。假设我们有一个矩阵:

>> A = reshape(1:25,5,5)

A =

     1     6    11    16    21
     2     7    12    17    22
     3     8    13    18    23
     4     9    14    19    24
     5    10    15    20    25

假设我们想要取上面矩阵中每个 3 x 3 重叠邻域的平均值,并对超出矩阵边界的那些元素进行零填充。您可以使用 blockproc:

B = blockproc(A, [1 1], @(x) mean(x.data(:)), 'BorderSize', [1 1], 'TrimBorder', false, 'PadPartialBlocks', true);

需要注意的重要一点是,块大小(在本例中为 1 x 1)和 BorderSize(在本例中为 1 x 1)的设置与您预期的 3 x 3 不同堵塞。要了解为什么会这样,我们需要进一步了解 BorderSize 的工作原理。对于给定的块中心,BorderSize 允许您捕获 超出原始 大小块尺寸的值/像素。对于那些超出矩阵边界的位置,我们默认将这些位置填充为零。 BorderSize 允许我们捕获更多 2M + 2N 像素,其中 MN 是您想要的水平和垂直边框大小。这将使我们能够在原始块的上方和下方捕获 M 个像素,在原始块的左侧和右侧捕获 N 个像素。

因此,对于A中1的值,如果块大小是1 x 1,这意味着元素只包含1,如果我们的BorderSize是1 x 1 . 这意味着我们的最终块将是:

0  0  0
0  1  6
0  2  7

因为我们的块大小是 1,下一个块将以 6 为中心,我们将得到一个 3 x 3 的像素网格等等。将 TrimBorder 设置为 false 也很重要,这样我们就可以保留那些在扩展块时最初捕获的像素。默认设置为 true。最后,PadPartialBlocks就是true,保证所有块的大小都一样。当你运行以上代码时,我们得到的结果是:

B =

    1.7778    4.3333    7.6667   11.0000    8.4444
    3.0000    7.0000   12.0000   17.0000   13.0000
    3.6667    8.0000   13.0000   18.0000   13.6667
    4.3333    9.0000   14.0000   19.0000   14.3333
    3.1111    6.3333    9.6667   13.0000    9.7778

您可以使用 nlfilter 验证我们得到相同的结果,我们可以将平均值应用于 3 x 3 滑动邻域:

C = nlfilter(A, [3 3], @(x) mean(x(:)))

C =

    1.7778    4.3333    7.6667   11.0000    8.4444
    3.0000    7.0000   12.0000   17.0000   13.0000
    3.6667    8.0000   13.0000   18.0000   13.6667
    4.3333    9.0000   14.0000   19.0000   14.3333
    3.1111    6.3333    9.6667   13.0000    9.7778

因此,如果您想正确使用blockproc进行滑动操作,您需要注意如何分别设置块大小和边框大小。在这种情况下,一般规则是始终将您的块大小设置为 1 x 1,并允许 BorderSize 指定您想要的每个块的大小。具体来说,对于大小为 K x K 的块,您可以将 BorderSize 分别设置为 floor(K/2) x floor(K/2)。如果 K 是奇数,事情就会变得简单。

例如,如果您想要在滑动 window 基础上进行 5 x 5 均值过滤操作,您可以将 BorderSize 设置为 [2 2],如 K = 5floor(K/2) = 2。因此,你会这样做:

B = blockproc(A, [1 1], @(x) mean(x.data(:)), 'BorderSize', [2 2], 'TrimBorder', false, 'PadPartialBlocks', true)

B =

    2.5200    4.5600    7.2000    6.9600    6.1200
    3.6000    6.4000   10.0000    9.6000    8.4000
    4.8000    8.4000   13.0000   12.4000   10.8000
    4.0800    7.0400   10.8000   10.2400    8.8800
    3.2400    5.5200    8.4000    7.9200    6.8400

用大小为 5 x 5 的 nlfilter 复制它也得到:

C = nlfilter(A, [5 5], @(x) mean(x(:)))

C =

    2.5200    4.5600    7.2000    6.9600    6.1200
    3.6000    6.4000   10.0000    9.6000    8.4000
    4.8000    8.4000   13.0000   12.4000   10.8000
    4.0800    7.0400   10.8000   10.2400    8.8800
    3.2400    5.5200    8.4000    7.9200    6.8400

我在做一些计时测试,似乎在这种情况下使用 blockprocnlfilter 快。

问题 #2

The second is im2col. im2col(A,[m n],block_type) will divide the block into m by n blocks and arrange them in columns, so each column is a block? If so, how is the overlapping controlled? And if each block is a column can I successfully apply the dct2 function on each column? Because I doubt it will take vectors as input?

你是正确的,im2col 将每个像素邻域或块转换为单个列,这些列的串联形成输出矩阵。您可以通过 block_type 参数控制块是重叠还是不同。指定 distinctsliding(默认)来控制它。您还可以使用 mn.

控制每个邻域的大小

但是,如果您的目标是应用 dct2im2col 的输出,那么您将得不到想要的结果。具体来说,dct2 将二维数据中每个数据点的空间位置考虑在内,并用作转换的一部分。通过将每个像素邻域转换为单个列,每个块最初存在的 2D 空间关系现在消失了。 dct2 需要 2D 空间数据,但您会指定 1D 数据。因此,im2col 可能不是您要查找的内容。如果我理解你想要的是正确的,你会想使用 blockproc 来代替。


希望对您有所帮助!