2

3Dオブジェクトの表面にランダムにサンプリングされたポイントのセットがあります。2つの異なるオブジェクト間の類似性を計算できるようにしたいと思います。これを機能させるには、まず、比較する両方のオブジェクトのサンプルポイントが同じ回転とスケールであることを確認する必要があります。これは、主成分軸をx / y / z軸に沿って配置し、最長の主成分が単位長になるようにスケーリングすることで実現できると思いました。

最初にポイントセットの図心を計算し、原点が新しい図心になるようにすべての点を変換します。

CGAL linear_least_squares_fitting_3関数を使用して主成分分析を行います。これにより、ポイントを通る最適な平面が得られます。両方の基本ベクトルの外積をとることにより、この平面の法線を計算します。

Plane plane;
linear_least_squares_fitting_3(points.begin(), points.end(), 
    plane, CGAL::Dimension_tag<0>());

auto dir1 = dir2vec(plane.base1().direction());
auto dir2 = dir2vec(plane.base2().direction());
auto normal = dir1 ^ dir2; // cross product
normal.normalize(); dir1.normalize(); dir2.normalize();

この関数は、オブジェクトを同等dir2vecのオブジェクトに変換します(私はOpenSceneGraphグラフィックエンジンを使用しています)。最後に、次のコードを使用して、すべてを単位軸に回転させます。CGAL::Direction_3osg::Vec3d

Matrixd r1, r2, r3;
r1.makeRotate(normal, Vec3d(1,0,0));
r2.makeRotate(dir1 * r1, Vec3d(0,1,0));
r3.makeRotate(dir2 * r1 * r2, Vec3d(0,0,1));
auto rotate = [&](Vec3d const &p) {
    return p * r1 * r2 * r3;
};
transform(osgPoints.begin(), osgPoints.end(), osgPoints.begin(), rotate);

ここに、osgPointsがありvector<osg::Vec3d>ます。テストの目的で、回転したポイントの図心を元の位置に変換して、両方のポイントクラウドが重ならないようにします。

Vec3d center = point2vec(centroid);
auto tocentroid = [&](Vec3d const &v) {
    return v + center;
};
transform(osgPoints.begin(), osgPoints.end(), osgPoints.begin(), tocentroid);

それをテストするために、同じポイントセットの2つのコピーを使用しますが、1つは変換(回転および変換)されます。上記のコードは回転を元に戻す必要がありますが、結果は私が期待したものではありません。この画像を参照してください。赤い線は、最適な平面のベースベクトルとその法線を示しています。linear_least_squares_fitting_3平面の一方が他方に対して少し回転しているため、への両方の呼び出しの結果はわずかに異なる答えを与えるように見えます。

これは、両方のオブジェクトが重心を原点として配置されている別の画像です。これで、法線と基本ベクトルが一緒になっていることがはっきりとわかりますが、点はそうではありません。

なぜこれが起こるのか、そしてどうすればそれを防ぐことができるのか誰かが知っていますか?

4

2 に答える 2

3

平面を一連の点に合わせると、1つの自由度に制約がなくなります。平面はその法線の周りを自由に回転し、フィットは等しくなります。CGALについては何も知りませんが、フィットを見つけるときに便利な平面(おそらく空間の元の軸から最も近い投影)を見つけるだけであることに気付くのは驚くことではありません。

点群で実際のPCAを実行した場合、その問題は発生しないと思います。あるいは、フィッティングアルゴリズムによって検出された法線に沿ってデータを再スケーリング(ストレッチ)してから、別のフィッティングを見つけることもできます。データを十分に伸ばすと、最初に見つかった平面は、直交する平面ほどうまく適合しないはずです。

于 2011-03-30T16:03:01.230 に答える
0

JCooperが示唆したように、実際、CGALはすべての主成分を計算するわけではないように見えました。PCAを実行するためにALGLIBライブラリに切り替えましたが、動作するようになりました。

于 2011-03-30T21:49:38.450 に答える