У меня есть наборы случайно выбранных точек на поверхности трехмерных объектов. Я хочу быть в состоянии вычислить сходство между двумя различными объектами. Чтобы это работало, я сначала должен убедиться, что точки выборки обоих объектов, которые я хочу сравнить, имеют одинаковое вращение и масштаб. Я думал, что смогу сделать это, ориентируя оси главных компонентов вдоль осей 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
преобразует объект CGAL::Direction_3
в эквивалентный объект osg::Vec3d
(я использую графический движок OpenSceneGraph). Наконец, я поворачиваю все по осям юнитов, используя следующий код:
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);
Чтобы проверить это, я использую две копии одного и того же набора точек, однако одна трансформируется (поворачивается и переводится). Приведенный выше код должен отменить повороты, однако результаты не соответствуют ожиданиям: см. это изображение . Красные линии обозначают базовые векторы наиболее подходящих плоскостей и их нормаль. Похоже, что результаты обоих вызовов linear_least_squares_fitting_3
дают немного разные ответы, так как одна из плоскостей немного повернута относительно другой.
Вот еще одно изображение, где оба объекта расположены с центром в центре. Теперь ясно видно, что нормали и базовые векторы падают вместе, а точки - нет.
Кто-нибудь знает, почему это происходит, и как я могу это предотвратить?