我在3D對象的表面上有隨機採樣點的集合。我想能夠計算兩個不同對象之間的相似度。爲了做到這一點,我首先必須確保我要比較的兩個對象的採樣點具有相同的旋轉和縮放比例。我認爲我可以通過沿x/y/z軸定位主分量軸並縮放,使得最長的主分量具有單位長度。使用CGAL進行主成分分析的點雲對齊
我首先計算點集的質心,並翻譯所有點,使得原點變成新的質心。
我使用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
功能的CGAL::Direction_3
對象轉換爲等效的osg::Vec3d
對象(我使用OSG的圖形引擎)。最後,我旋轉一切使用下面的代碼的單位軸:
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);
爲了測試它,我使用了相同點集的兩個副本,但是一個被轉換(旋轉和翻譯)。上面的代碼應該取消旋轉,但結果並不是我所期望的:請參閱this image。紅線表示最佳擬合平面的基向量及其正常值。看起來這兩個調用linear_least_squares_fitting_3
的結果給出了稍微不同的答案,因爲其中一個飛機相對於另一個飛機旋轉了一點點。
Here is another圖像中兩個對象的位置均以原點爲中心。現在可以清楚地看到法線和基本矢量集中在一起,但這些點卻沒有。
是否有人知道爲什麼會發生這種情況,以及如何防止它發生?
謝謝你的回答,但不幸的是你的建議不起作用,也許是因爲我理解錯了。你知道一個真正的PCA的C++庫嗎? – muksie 2011-03-30 20:42:21