5

与えられたマトリックス:

a =
   1   1   2   2
   1   1   2   2
   3   3   4   4
   3   3   4   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現在)。これを読んでいる人は、追加のツールボックスを必要としないより良いソリューションについて、againorまたは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.

ドラ!Rody(+1)が勝者のようです。:-)

更新:レース獲得者(+1)への新規参入者が主導権を握ります!

于 2012-10-25T07:56:41.860 に答える
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

別のオプション: 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

線形インデックスに基づいて、別の非一般的な (まだ;) ソリューションで競馬に参加します

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のソリューションは、ImageProcessingToolbox関数|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 に答える