2012-10-25 37 views
5

鑑於矩陣:以連續的矩陣塊的最大值在MATLAB

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

我想獲得以下四個2×2矩陣:

a1 = 
    1 1 
    1 1 

a2 = 
    2 2 
    2 2 

a3 = 
    3 3 
    3 3 

a4 = 
    4 4 
    4 4 

從那裏,我想取每個矩陣的最大,然後重塑結果成2×2矩陣的結果,如下所示:

r = 
    1 2 
    3 4 

結果最大值Va的位置相對於它們在初始矩陣中的原始位置的提示是重要的。

目前,我使用下面的代碼來實現:

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(max(max(reshape(A, w, w, []))), w, w, []) ,是以錯誤的價值觀和收益的最大值:

ans = 
    3 4 
    3 4 

有沒有辦法做到這一點不重複或以其他方式提高自己的迭代方法?

+0

這裏是一個一行法比你的循環要慢4倍:'SOLN = cell2mat(cellfun(@Max,cellfun(@Max,mat2cell(A,[2 2], [2 2]),'UniformOutput',false),'UniformOutput',false));'。你確實問過沒有迭代的方法:-)但是我已經把它作爲一個評論,而不是一個答案,因爲從速度的角度來看,迭代確實是更可取的。 –

+1

您是否需要中間2x2矩陣作爲別的東西,或者您只是對最後一個矩陣「r」感興趣? –

+0

是的,那也是我的想法...... – bla

回答

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) 

它可以做一點點mor Ë優雅:

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) 

,但我懷疑這會是更快...

+0

您必須調換結果--OP表示順序非常重要。 – angainor

+0

@angainor:謝謝,編輯。你能否看看我的第二個解決方案,看能否更有效地完成索引的生成? –

+0

看看我打算做什麼;)雖然我敢肯定,它可以做得更短.. – angainor

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 
3

更新:我不知道我是如何已經結束了得票最多(截至2012-10- 28)。對於閱讀此內容的任何人,請參閱angainor或Rody的答案,以獲得更好的解決方案,而不需要任何額外的工具箱。

這裏是每一個答案的賽馬迄今(不含納茨 - 對不起,沒有必要的工具箱):

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. 

Drat!看來Rody(+1)是勝利者。 :-)

更新:新進入者比賽angainor(+1)率先!

+1

Soln2 - > Soln2' – bla

+0

@nate是的,發現,雖然我通過切換循環的順序來解決它。對不起,沒有在賽馬中包括你的方法,但我沒有'blockproc'工具箱 –

+0

不用擔心!好玩。 – bla

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

+0

非常整齊!我只是在研究一個類似於線性指數的想法,但並沒有設法讓時間低於Rody的時間。 +1!我想回到工作的時間我認爲... –

+0

會有一種方法來推廣創建idx矩陣來支持任何給定的原始矩陣和窗口大小嗎? –

+0

@NickEwing Rody在他的擴展答案中展示了一種方法。帶有'bsxfun'的版本就是你要找的。 – angainor

0

注意:Nate的解決方案使用圖像處理工具箱功能| blockproc |。我想重寫:

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

在不同的電腦相比時機是困難重重,如定時的東西一旦被在幾分之一秒內發生。 TIMEIT在這裏很有用:

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

但這個時機我的電腦抽動/ TOC就拿0.008秒。

乾杯, 佈雷特

+0

嗨佈雷特。同意,如果想要正確地計算功能性能,timeit是一個很好的工具。但是,請注意,上面我們實際上循環每個例程1000次,而不是一次,因此結果可以被認爲是一個(非標度)算術平均值,它應該使事情平滑一些。它肯定不會像'timeit'那樣強壯,而且在計算機之間切換肯定會增加噪音,但有時當你在爲某個SO問題竊聽時,更容易不必擔心函數句柄等問題:-) –