5

より大きなマトリックス(任意の次元数)でマトリックス(パターン)を見つける「良い」方法を探しています。

例:

total = rand(3,4,5);
sub = total(2:3,1:3,3:4);

今、私はこれが起こることを望みます:

loc = matrixFind(total, sub)

この場合loc、 になるはず[2 1 3]です。

今のところ、1 つの点 (存在する場合) を見つけることに関心があり、丸めの問題については心配していません。subに「適合」していると推測できますtotal


これは私が3次元でそれを行う方法ですが、もっと良い方法があるように感じます:

total = rand(3,4,5);
sub = total(2:3,1:3,3:4);
loc = [];
for x = 1:size(total,1)-size(sub,1)+1
    for y = 1:size(total,2)-size(sub,2)+1
        for z = 1:size(total,3)-size(sub,3)+1
            block = total(x:x+size(sub,1)-1,y:y+size(sub,2)-1,z:z+size(sub,3)-1);
            if isequal(sub,block)
                loc = [x y z]
            end
        end
    end
end

任意の数の次元に対して実行可能な解決策を見つけたいと思っています。

4

3 に答える 3

2

これは、元の行列のすべての可能なシフトを実行し、シフトされたtotalものの左上端などのサブ行列をtotal求められたパターンと比較することに基づいていますsubs。シフトは文字列を使用して生成され、 を使用して適用されcircshiftます。

ほとんどの作業はベクトル化されています。1 レベルのループのみが使用されます。

この関数は、最初の一致だけでなく、すべての一致を検出します。例えば:

>> total = ones(3,4,5,6);
>> sub = ones(3,3,5,6);
>> matrixFind(total, sub)
ans =

     1     1     1     1
     1     2     1     1

関数は次のとおりです。

function sol = matrixFind(total, sub)

nd = ndims(total);
sizt = size(total).';
max_sizt = max(sizt);
sizs = [ size(sub) ones(1,nd-ndims(sub)) ].'; % in case there are
% trailing singletons

if any(sizs>sizt)
    error('Incorrect dimensions')
end

allowed_shift = (sizt-sizs);
max_allowed_shift = max(allowed_shift);
if max_allowed_shift>0
    shifts = dec2base(0:(max_allowed_shift+1)^nd-1,max_allowed_shift+1).'-'0';
    filter = all(bsxfun(@le,shifts,allowed_shift));
    shifts = shifts(:,filter); % possible shifts of matrix "total", along 
    % all dimensions
else
    shifts = zeros(nd,1);
end

for dim = 1:nd
    d{dim} = 1:sizt(dim); % vectors with subindices per dimension
end
g = cell(1,nd);
[g{:}] = ndgrid(d{:}); % grid of subindices per dimension
gc = cat(nd+1,g{:}); % concatenated grid
accept = repmat(permute(sizs,[2:nd+1 1]), [sizt; 1]); % acceptable values
% of subindices in order to compare with matrix "sub"
ind_filter = find(all(gc<=accept,nd+1));

sol = [];
for shift = shifts
    total_shifted = circshift(total,-shift);
    if all(total_shifted(ind_filter)==sub(:))
        sol = [ sol; shift.'+1 ];
    end
end
于 2013-09-16T17:04:04.420 に答える
1

任意の数の次元については、 を試すことができますconvn

C = convn(total,reshape(sub(end:-1:1),size(sub)),'valid'); % flip dimensions of sub to be correlation
[~,indmax] = max(C(:));
% thanks to Eitan T for the next line
cc = cell(1,ndims(total)); [cc{:}] = ind2sub(size(C),indmax); subs = [cc{:}]

一般化された ind2sub にカンマ区切りのリストを使用するよう提案してくれた Eitan T に感謝します。

最後に、isequalこれは正規化された相互相関ではないため、結果を でテストする必要があります。つまり、ローカル サブリージョンの数値が大きくなると、相関値が膨らみ、偽陽性が発生する可能性があります。行列が大きな値の領域で非常に不均一な場合total、 で他の最大値を検索する必要がある場合がありますC

于 2013-09-16T16:08:27.217 に答える