好吧,这是一个相当复杂的问题。我将尝试将其分解为单独的部分,并分别回答每个问题。
问题#1
blockproc
可用于使用以下方法在滑动窗口上实现我的功能BorderSize
and TrimBorder
论据。
B = blockproc(A,[64,64],fun,'BorderSize',[5,5], 'TrimBorder', 'false');
我意识到这会创建一个块[64 + 2*5, 64 + 2*5]
并应用该函数@fun
在每个块上。但由于我无法进入我的功能@fun
在调试以验证正确操作时,我无法确定这就是我所需要的。我上面的代码是否适合我的需要?我知道我得到了一个串联结果B
但它应该位于重叠的滑块上。这能达到我所需要的吗?
经过一番尝试后blockproc
,这确实是正确的,您可以使用它来使滑动邻域处理工作。但是,您将需要一个额外的标志,即PadPartialBlocks
。此标志的目的是,如果您要提取位于图像外边缘的块,并且无法制作指定大小的块,则这将对该部分块进行零填充,使其符合到相同的大小。这是一个使用滑动窗口进行此操作的小示例。假设我们有一个矩阵:
>> 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
像素更多,其中M
and N
是您想要的水平和垂直边框尺寸。这将使我们能够捕获M
原始块上方和下方有更多像素,并且N
原始块左侧和右侧有更多像素。
因此,对于 1 的值A
,如果块大小为 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
is 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 http://www.mathworks.com/help/images/ref/nlfilter.html我们可以将平均值应用于 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
to be floor(K/2) x floor(K/2)
分别。如果K
很奇怪。
例如,如果您想要一个5 x 5
表示基于滑动窗口的过滤操作,您可以设置BorderSize
to [2 2]
, as K = 5
and floor(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
复制这个nlfilter
大小为 5 x 5 还给出:
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
我正在做一些计时测试,看来blockproc
在这种情况下使用比nlfilter
.
问题2
第二个是im2col
. im2col(A,[m n],block_type)
会将块分成 m × n 块,并将它们排列成列,那么每一列都是一个块?如果是这样,重叠是如何控制的?如果每个块都是一列,我可以成功应用dct2
每列的功能?因为我怀疑它会接受向量作为输入吗?
你是对的im2col
将每个像素邻域或块转换为单列,这些列的串联形成输出矩阵。您可以通过以下方式控制块是否重叠或不同block_type
范围。指定distinct
or sliding
(默认)来控制它。您还可以控制每个邻域的大小m
and n
.
但是,如果您的目标是申请dct2
输出为im2col
,那么你将得不到你想要的。具体来说,dct2
考虑 2D 数据中每个数据点的空间位置,并用作转换的一部分。通过将每个像素邻域转换为单列,每个块最初存在的 2D 空间关系现在消失了。dct2
需要 2D 空间数据,但您将指定 1D 数据。像这样,im2col
可能不是您要找的。如果我正确理解你想要什么,你会想要使用blockproc
反而。
希望这可以帮助!