在MATLAB中考虑连续矩阵块的最大值

时间:2012-10-25 07:17:39

标签: matlab matrix vectorization

给出矩阵:

a =
   1   1   2   2
   1   1   2   2
   3   3   4   4
   3   3   4   4

我想得到以下四个2x2矩阵:

a1 =
   1   1
   1   1

a2 =
   2   2
   2   2

a3 =
   3   3
   3   3

a4 =
   4   4
   4   4

从那里,我想取每个矩阵的最大值,然后将结果重新整形为2x2结果矩阵,如下所示:

r =
   1   2
   3   4

结果最大值相对于初始矩阵中原始位置的位置非常重要。

目前,我正在使用以下代码来完成此任务:

w = 2
S = zeros(size(A, 1)/w);
for i = 1:size(S)
  for j = 1:size(S)
    Window = A(i*w-1:i*w, j*w-1:j*w);
    S(i, j) = max(max(Window));
  end
end

这样可行,但似乎必须有一种不涉及迭代(矢量化)的方法。

我尝试使用reshape如下: reshape(max(max(reshape(A, w, w, []))), w, w, []) 然而,它取错了值的最大值并返回:

ans =
   3   4
   3   4

有没有办法在没有迭代的情况下完成此任务或以其他方式改进我的迭代方法?

5 个答案:

答案 0 :(得分:3)

更新:我不确定我是如何得到最多的选票(截至2012-10-28)。对于阅读此内容的任何人,请参阅angainor或Rody的答案,以获得不需要任何其他工具箱的更好解决方案。

这是迄今为止每个答案的赛马(不包括Nates - 抱歉,没有必要的工具箱):

Z = 1000;

A = [1 1 2 2; 1 1 2 2; 3 3 4 4; 3 3 4 4];
w = 2;

%Method 1 (OP method)
tic
for z = 1:Z
S = zeros(size(A, 1)/w);
for i = 1:size(S)
  for j = 1:size(S)
    Window = A(i*w-1:i*w, j*w-1:j*w);
    S(i, j) = max(max(Window));
  end
end
end
toc

%Method 2 (My double loop with improved indexing)
tic
for z = 1:Z
wm = w - 1;
Soln2 = NaN(w, w);
for m = 1:w:size(A, 2)
    for n = 1:w:size(A, 1)
        Soln2((m+1)/2, (n+1)/2) = max(max(A(n:n+wm, m:m+wm)));
    end
end
Soln2 = Soln2';
end
toc


%Method 3 (My one line method)
tic
for z = 1:Z
Soln = cell2mat(cellfun(@max, cellfun(@max, mat2cell(A, [w w], [w w]), 'UniformOutput', false), 'UniformOutput', false));
end
toc

%Method 4 (Rody's method)
tic
for z = 1:Z
b = [A(1:2,:) A(3:4,:)];
reshape(max(reshape(b, 4,[])), 2,2);
end
toc

速度测试的结果(z上的循环)是:

Elapsed time is 0.042246 seconds.
Elapsed time is 0.019071 seconds.
Elapsed time is 0.165239 seconds.
Elapsed time is 0.011743 seconds.

讨厌鬼!似乎Rody(+1)是胜利者。 : - )

更新:新参赛者angainor(+1)领先!

答案 1 :(得分:2)

另一种选择:比cell2mat(cellfun ...)代码慢,但给出了中间步骤:

fun = @(block_struct) reshape((block_struct.data), [],1);
B = reshape(blockproc(A,[2 2],fun),2,2,[])
r=reshape(max(max(B)) ,2,[])

B(:,:,1) =

 1     1
 1     1


B(:,:,2) =

 3     3
 3     3


B(:,:,3) =

 2     2
 2     2


B(:,:,4) =

 4     4
 4     4

r =

 1     2
 3     4

答案 2 :(得分:2)

不是很一般,但适用于a

b = [a(1:2,:) a(3:4,:)];
reshape(max(reshape(b, 4,[])), 2,2).'

这个的一般版本有点* ahum * fuglier:

% window size
W = [2 2];

% number of blocks (rows, cols)
nW = size(a)./W;


% indices to first block
ids = bsxfun(@plus, (1:W(1)).', (0:W(2)-1)*size(a,1));

% indices to all blocks in first block-column
ids = bsxfun(@plus, ids(:), (0:nW(1)-1)*W(1));

% indices to all blocks
ids = reshape(bsxfun(@plus, ids(:), 0:nW(1)*prod(W):numel(a)-1), size(ids,1),[]);

% maxima
M = reshape(max(a(ids)), nW)

它可以更优雅地完成:

b = kron(reshape(1:prod(nW), nW), ones(W));    
C = arrayfun(@(x) find(b==x), 1:prod(nW), 'uni', false);    
M = reshape(max(a([C{:}])), nW)

但我怀疑那会更快......

答案 3 :(得分:2)

我将根据线性指数加入另一种非一般(但是)解决方案的赛马

idx = [1 2 5 6; 3 4 7 8]';
splita = [A(idx) A(idx+8)];
reshape(max(splita), 2, 2);

通过Colins代码获得的时间,我的方法最后:

Elapsed time is 0.039565 seconds.
Elapsed time is 0.021723 seconds.
Elapsed time is 0.168946 seconds.
Elapsed time is 0.011688 seconds.
Elapsed time is 0.006255 seconds.

idx数组可以很容易地推广到更大的窗口和系统大小。

答案 4 :(得分:0)

注意:Nate的解决方案使用图像处理工具箱功能| blockproc |。我会改写:

fun = @(x) max(max(x.data));
r = blockproc(A,[2 2],fun)

比较不同计算机之间的时序充满了困难,就像在不到一秒钟内发生的事情一样。 TIMEIT在这里很有用:

http://www.mathworks.com/matlabcentral/fileexchange/18798

但是使用tic / toc在我的电脑上计时这个时间需要0.008秒。

干杯, 布雷特