3D 개체의 표면에 무작위로 샘플링 된 점 집합이 있습니다. 저는 두 개의 다른 객체들 사이의 유사성을 계산할 수 있기를 원합니다. 이 작업을 수행하기 위해 먼저 비교할 두 오브젝트의 샘플 포인트가 동일한 회전 및 크기를 유지하는지 확인해야합니다. 나는 x/y/z 축을 따라 주요 구성 요소 축을 배향시키고, 가장 긴 주 구성 요소가 단위 길이를 갖도록 배율을 조정하여이 작업을 수행 할 수 있다고 생각했습니다.CGAL을 사용한 주성분 분석을 사용한 점 구름 정렬
내가 먼저 지점 세트의 중심을 계산하고, 기원은 새로운 중심이되도록 모든 지점을 번역합니다.
나는 점을 통해 최적의 피팅 평면을 제공하는 CGAL의 linear_least_squares_fitting_3 기능을 사용하여 주성분 분석을한다. I는 모두 기본 벡터의 외적을 고려하여이 평면의 법선을 계산 :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
함수 등가 osg::Vec3d
객체 (I는 OpenSceneGraph 그래픽 엔진을 사용하고있다)에 CGAL::Direction_3
오브젝트로 변환한다. 마지막으로, 나는 다음과 같은 코드를 사용하여 장치의 축에 모든 회전 : 여기
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);
이를 테스트하기 위해, I는 동일한 지점 세트의 두 복사본을 사용하지만 하나의 변형 (회전) 번역된다. 위의 코드는 회전을 취소해야하지만 결과는 예상 한 것과 다릅니다. this image을 참조하십시오. 빨간색 선은 최상의 피팅 평면과 그 법선의 기본 벡터를 나타냅니다. linear_least_squares_fitting_3
에 대한 두 호출의 결과는 비행기 중 하나가 다른 비행기와 관련하여 조금씩 회전하므로 약간 다른 답변을 제공합니다. 두 개체가 원점에 그 중심에 위치하는
Here is another 이미지. 이제는 법선과 기본 벡터가 함께 떨어지는 것을 명확하게 볼 수 있지만 포인트는 그렇지 않습니다.
왜 이런 일이 발생하는지 알 수 있습니까? 어떻게 방지 할 수 있습니까? 점의 집합에 비행기를 피팅
는
답변 해 주셔서 감사합니다.하지만 불행히도 귀하의 제안이 작동하지 않습니다. 아마도 내가 잘못 이해했기 때문일 수 있습니다. 실제 PCA를 수행하는 C++ 라이브러리에 대해 알고 있습니까? – muksie