簡體   English   中英

在MATLAB中考慮連續矩陣塊的最大值

[英]Taking the max of contiguous matrix chunks in MATLAB

鑒於矩陣:

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

有沒有辦法在沒有迭代的情況下完成此任務或以其他方式改進我的迭代方法?

更新:我不確定我是如何得到最多的選票(截至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)領先!

另一種選擇:比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

不是很一般,但是它適用於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)

但我懷疑那會更快......

我將根據線性指數加入另一種非一般(但是)解決方案

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數組可以很容易地推廣到更大的窗口和系統大小。

注意: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秒。

干杯,布雷特

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM