5

给定矩阵:

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

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

4

5 回答 5

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.

讨厌!看来罗迪(+1)是赢家。:-)

更新:新加入的比赛 angainor (+1) 领先!

于 2012-10-25T07:56:41.860 回答
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
于 2012-10-25T07:54:15.370 回答
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)

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

于 2012-10-25T07:56:39.097 回答
2

我将加入另一个基于线性索引的非通用(尚未)解决方案的赛马

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

柯林斯代码得到的次数,我的方法最后:

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数组可以很容易地推广到更大的窗口和系统大小。

于 2012-10-25T08:35:43.213 回答
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 秒。

干杯,布雷特

于 2012-10-25T20:49:16.410 回答