3

1が現在のサブセットである行列が与えられます

test =

     0     0     0     0     0     0
     0     0     0     0     0     0
     0     0     1     1     0     0
     0     0     1     1     0     0
     0     0     0     0     0     0
     0     0     0     0     0     0

サブセットを現在のサブセットの境界に変更するための関数または迅速な方法はありますか?

例えば。上記の「テスト」からこのサブセットを取得します

test =

     0     0     0     0     0     0
     0     1     1     1     1     0
     0     1     0     0     1     0
     0     1     0     0     1     0
     0     1     1     1     1     0
     0     0     0     0     0     0

結局、行列のサブセットを囲むセルの最小値を取得したいだけです。確かに、ループして境界の最小値(セルごと)を取得することはできますが、上記の方法でそれを行う方法が必要です。

サブセットは接続されますが、長方形ではない可能性があることに注意してください。これは大きな問題かもしれません。

これは可能なサブセットです....(これをNaNボーダーで埋めます)

test =

     0     0     0     0     0     0
     0     0     0     0     0     0
     0     0     1     1     0     0
     0     0     1     1     0     0
     0     0     1     1     1     1
     0     0     1     1     1     1

アイデア?

4

3 に答える 3

3

私が使用する基本的な手順は次のとおりです。

  1. 形状に拡張を実行して、形状とその境界である新しい領域を取得します
  2. 拡張された形状から元の形状を差し引いて、境界だけを残します
  3. 境界を使用してデータマトリックスにインデックスを付け、最小値を取ります。

膨張

ここでやりたいのは、各セルに3x3ウィンドウを渡し、そのウィンドウで最大値を取得することです。

[m, n] = size(A); % assuming A is your original shape matrix
APadded = zeros(m + 2, n + 2);
APadded(2:end-1, 2:end-1) = A; % pad A with zeroes on each side
ADilated = zeros(m + 2, n + 2); % this will hold the dilated shape.

for i = 1:m
    for j = 1:n
        mask = zeros(size(APadded));
        mask(i:i+2, j:j+2) = 1; % this places a 3x3 square of 1's around (i, j)
        ADilated(i + 1, j + 1) = max(APadded(mask));
    end
end

形状減算

これは基本的に論理積であり、交差を削除する論理否定です。

ABoundary = ADilated & (~APadded);

この段階では、拡張を行うために追加した境界線を削除することをお勧めします。これは、もう必要ないためです。

ABoundary = ABoundary(2:end-1, 2:end-1);

境界に沿って最小のデータポイントを見つける

論理境界を使用して元のデータをベクトルにインデックス付けし、そのベクトルの最小値を取得できます。

dataMinimum = min(data(ABoundary));
于 2012-11-29T01:40:36.920 に答える
2

これは、集合論ではなく、形態の問題と見なす必要があります。imdilate()これは、(イメージパッケージが必要です)を使用して非常に簡単に解決できます。基本的には、1の3x3マトリックスを使用して、画像をその膨張まで減算するだけで済みます。

octave> test = logical ([0  0  0  0  0  0
                         0  0  0  0  0  0
                         0  0  1  1  0  0
                         0  0  1  1  0  0
                         0  0  1  1  1  1
                         0  0  1  1  1  1]);
octave> imdilate (test, true (3)) - test
ans =

   0   0   0   0   0   0
   0   1   1   1   1   0
   0   1   0   0   1   0
   0   1   0   0   1   1
   0   1   0   0   0   0
   0   1   0   0   0   0

ただし、NaNでパッドすることはありません。本当に必要な場合は、元の行列にfalseを埋め込み、操作を実行してから、境界にtrueの値があるかどうかを確認できます。

を使用する必要はないことに注意してください。その場合は、の代わりにlogical()を使用する必要があります。しかし、それはより多くのメモリを必要とし、パフォーマンスが低下します。ones()true()

編集: matlabツールボックスを使用せずにそれを実行しようとしているので、Octaveのソースをimdilate()見てください。論理行列の場合(これはあなたの場合です)、それfilter2()はmatlabコアに属する単純な使用法です。そうは言っても、次の1行は正常に機能し、はるかに高速になるはずです。

octave> (filter2 (true (3), test) > 0) - test
ans =

   0   0   0   0   0   0
   0   1   1   1   1   0
   0   1   0   0   1   0
   0   1   0   0   1   1
   0   1   0   0   0   0
   0   1   0   0   0   0
于 2012-11-29T01:39:35.547 に答える
1

考えられる解決策の1つは、サブセットを取得して元のマトリックスに追加することですが、サブセットを追加するたびに、その位置を+1行-1行および+1列-1列オフセットするようにしてください。結果は、元のサブセット全体で1つの行と列に展開されます。次に、元の行列を使用して、元のsubetをゼロにマスクします。

このような:

test_new = test + ...
[[test(2:end,2:end);zeros(1,size(test,1)-1)],zeros(size(test,1),1)] + ... %move subset up-left
[[zeros(1,size(test,1)-1);test(1:end-1,2:end)],zeros(size(test,1),1)] + ... %move down-left
[zeros(size(test,1),1),[test(2:end,1:end-1);zeros(1,size(test,1)-1)]] + ... %move subset up-right
[zeros(size(test,1),1),[zeros(1,size(test,1)-1);test(1:end-1,1:end-1)]];  %move subset down-right

test_masked = test_new.*~test; %mask with original matrix
result = test_masked;
result(result>1)=1; % ensure that there is only 1's, not 2, 3, etc.

testマトリックスでのこの結果は次のとおりです。

result =

 0     0     0     0     0     0
 0     1     1     1     1     0
 0     1     0     0     1     0
 0     1     0     0     1     1
 0     1     0     0     0     0
 0     1     0     0     0     0

編集済み-サブセットを上下左右、上下左右、上下左右に移動することで、コーナーも取得するようになりました。

これは、これを実現するための非常に迅速な方法であると思います。ループも関数もありません。行列演算だけです。

于 2012-11-29T01:40:09.677 に答える