1

画像 (3744x5616) から追跡された複数のオブジェクトの x、y ピクセル座標があります。座標は、オブジェクトと呼ばれる構造体に格納されます。

objects(1).centre = [1868 1236]

オブジェクトはそれぞれ数値コードによって一意に識別されます。

objects(i).code = 33

2 つのオブジェクトが互いに半径 300 ピクセル以内に入るたびに記録できるようにしたいと考えています。オブジェクトが接触しているかどうかを確認し、オブジェクト 33 がオブジェクト 34 と相互作用するように、相互作用に関与する両方のオブジェクトの ID を記録する最良の方法は何でしょうか。

ありがとう!

4

1 に答える 1

3

私が今考えることができる最善のことは、力ずくのアプローチです。1 つのオブジェクトの中心から他のオブジェクトの残りの距離を確認し、距離が 300 ピクセル未満かどうかを手動で確認するだけです。

これを速くしたい場合は、おそらくツールボックスなしでこれを行う必要があります。を使用して、vanilla MATLAB でこれをインテリジェントに行うことができますbsxfun。まず、各オブジェクトのXおよび座標用に個別の配列を作成します。Y

points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);

[ ] は、構造内の各フィールドobjects.centreの個々の座標にアクセスし、それらをコンマ区切りリストにアンパックします。centre最初の行がX座標で、2 番目の行が座標である 2 行になるように、この配列を再形成しYます。行を抽出して、別々の配列に配置します。

次に、それぞれに対して 2 つの差分行列を作成しますXYここで、行は 1 つの一意の座標を表し、列は別の一意の座標を表します。iこの行列内の値は、行のポイントと列ijポイントの差jです。

Xdiff = bsxfun(@minus, X.', X);
Ydiff = bsxfun(@minus, Y.', Y);

bsxfunB inary Singleton EX pansion FUN ctionの略です。この関数に精通している場合は、基本的に内部で行列とベクトルを複製するため、操作している両方の入力が同じサイズになります。この場合、私が行っているのは、 orを両方の入力として指定することです。一方は他方の転置バージョンです。これにより、入力の次元が一致するように各入力が自動的にブロードキャストされます。具体的には、最初の入力は and の列ベクトルであるため、これは の値の数だけ繰り返され、水平方向に積み上げられます。 repmatXYbsxfunXX

同様に、これはY値に対しても行われます。これを行った後、両方の出力に対して要素ごとの減算を実行し、あるポイントと別のポイントの間の成分ごとの減算を取得しますXYここで、行は最初のポイントを示し、列は 2 番目のポイントを示します。おもちゃの例として、 があったと想像してくださいX = [1 2 3]bsxfun上記のコードを使用して呼び出しを行うと、次のようになります。

>> Xdiff = bsxfun(@minus, [1 2 3].', [1 2 3])

Xdiff =

##  |  1     2     3  
----------------------
 1  |  0    -1    -2
 2  |  1     0    -1
 3  |  2     1     0

出力にいくつか追加の文字を配置しましたが、これらは説明と参考のためにのみ使用されています。列から行の値を取得し、行から##列の値を減算##すると、目的の減算が得られます。たとえば、1 行目の 2 列目は 1 - 2 = -1 を示しています。2 行目の 3 列目は、2 - 3 = -1 を示しています。Xとポイントの両方に対してこれを行うYと、対称行列内の他のすべてのポイントに対する 1 つのポイントの成分ごとの距離が得られます。


これは、対角線がすべて 0 である反対称行列であることに気付くでしょう。それ自体に対する 1 つの点の 1 つの次元の距離は 0 でなければならないので、意味があります。行列の左下の三角形の部分は、右の反対の符号... 減算の順序のため。ポイント 1 をポイント 2 で減算した場合、逆の減算を行うと逆の符号が得られます。ただし、行が最初のオブジェクトを表し、列が 2 番目のオブジェクトを表すと仮定して、半分に集中する必要があります。

NaNここで、距離を計算します。距離を計算するときに符号が無視されるため、上半分または下半分の三角形を に設定してください。これを無視しないと、相互作用する重複したオブジェクトが見つかるため、オブジェクト 3 とオブジェクト 1 は、オブジェクト 1 とオブジェクト 3 とは異なる相互作用になります。または下三角半分をNaN次のステップに進みます。ユークリッド距離を仮定すると:

dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;

最初の行は、点のすべてのペアのユークリッド距離を計算し、trilすべての論理で構成される行列の下三角部分を抽出するために使用します1。この行列を抽出し、これを使用して行列の下半分を に設定しNaNます。これにより、関心のないエントリをスキップできます。1 つのオブジェクトからそれ自体までの距離には関心がないため、対角線も 0 に設定していることに注意してください。

ようやくここまで来たので、300 ピクセル未満のオブジェクトを検索します。

[I,J] = find(dists < 300);

IおよびJは、マトリックス内のどの行と列の値が 300 未満かを決定する行/列のペアです。したがって、この場合、配列内のIとの各ペアは、互いにJ近いオブジェクトの位置を示します。

最終的に正しいオブジェクト コードを把握するには、次のようにします。

codes = [[objects(I).code].' [objects(J).code].'];

これはI、 とを使用Jして、コンマ区切りのリストで類似したオブジェクトの対応するコードにアクセスし、それらを横に並べてN x 2マトリックスに配置します。そのため、 の各行はcodes、距離要件を満たすオブジェクトの一意のペアを提供します。


コピーと貼り付けの場合:

points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
Xdiff = bsxfun(@minus, X.', X);
Ydiff = bsxfun(@minus, Y.', Y);
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
[I,J] = find(dists < 300);    
codes = [[objects(I).code].' [objects(J).code].'];

おもちゃの例

これが正しいかどうかを確認するために使用できる例を次に示します。

objects(1).centre = [1868 1236];
objects(2).centre = [2000 1000];
objects(3).centre = [1900 1300];
objects(4).centre = [3000 2000];
objects(1).code = 33;
objects(2).code = 34;
objects(3).code = 35;
objects(4).code = 99;

異なる重心と異なるコードで 4 つのオブジェクトを初期化しました。dists配列を計算した後、配列から何が得られるか見てみましょう。

>> format long g
>> dists

dists =

                       NaN          270.407100498489          71.5541752799933          1365.69396278961
                       NaN                       NaN          316.227766016838           1414.2135623731
                       NaN                       NaN                       NaN          1303.84048104053
                       NaN                       NaN                       NaN                       NaN

他の 3 つのポイントの近くにないポイントがある場合を示すことができるように、意図的に最後のポイントを他の 3 つのポイントのいずれよりも遠くにしました。

ご覧のとおり、点 (1,2) と (1,3) はすべて互いに近くにあり、残りのコードを完成させるとこのようになります。これは、(33,34) と (33,35) のペアリングを持つオブジェクト 33、34、および 35 に対応します。コード 34 と 35 のポイントを少し小さくしましたが、それでも 300 ピクセルのしきい値を超えているため、どちらもカウントされません。

>> codes

codes =

    33    34
    33    35

これをきれいな形式で表示したい場合は、おそらくforループを使用します。

for vec = codes.'
    fprintf('Object with code %d interacted with object with code %d\n', vec(1), vec(2));
end

このforループは少しトリッキーです。forループは行列も受け入れることができ、index 変数は一度に各行列の 1 つの列を左から右に与えることはあまり知られていません。codesしたがって、一意のコードの各ペアが列になるように、配列を転置しました。各列の最初と 2 番目の要素にアクセスして出力するだけです。

我々が得る:

Object with code 33 interacted with object with code 34
Object with code 33 interacted with object with code 35
于 2015-09-11T15:41:02.693 に答える