私が今考えることができる最善のことは、力ずくのアプローチです。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 つの差分行列を作成しますX
。Y
ここで、行は 1 つの一意の座標を表し、列は別の一意の座標を表します。i
この行列内の値は、行のポイントと列i
のj
ポイントの差j
です。
Xdiff = bsxfun(@minus, X.', X);
Ydiff = bsxfun(@minus, Y.', Y);
bsxfun
B inary Singleton EX pansion FUN ctionの略です。この関数に精通している場合は、基本的に内部で行列とベクトルを複製するため、操作している両方の入力が同じサイズになります。この場合、私が行っているのは、 orを両方の入力として指定することです。一方は他方の転置バージョンです。これにより、入力の次元が一致するように各入力が自動的にブロードキャストされます。具体的には、最初の入力は and の列ベクトルであるため、これは の値の数だけ繰り返され、水平方向に積み上げられます。 repmat
X
Y
bsxfun
X
X
同様に、これはY
値に対しても行われます。これを行った後、両方の出力に対して要素ごとの減算を実行し、あるポイントと別のポイントの間の成分ごとの減算を取得しますX
。Y
ここで、行は最初のポイントを示し、列は 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