Я пытаюсь вычислить объектно-ориентированную ограничительную рамку для набора точек. Я использую C++ и собственную библиотеку линейных алгебр.Объект, ориентированный на 3D-объект, с использованием PCA
Я использую две записи в блогах в качестве руководств, но все же мои ограничивающие прямоугольники являются неправильными (см. Изображения).
Я надеюсь, что мой комментарий код понятен моей попытка, но суть алгоритма состоит в том, чтобы использовать PCA, чтобы найти базисные векторы для объектно-ориентированных координат.
Чтобы затем проецировать все точки в новый кадр, найдите минимальные и максимальные точки, которые определяют поле, затем проецируйте эти точки в исходную координатную рамку и визуализируйте их.
Я могу успешно сделать поле, но не является ограничивающей рамкой и, по-видимому, выровнен по отношению к нормальной оси x, y, z. Это ясно видно на первом изображении для каждого из двух указанных объектов.
Любая помощь была бы действительно оценена. Заранее спасибо.
// iglVertices is a X by 3 Eigen::::MatrixXf
// Covariance matrix and eigen decomposition
Eigen::MatrixXf centered = iglVertices.rowwise() - iglVertices.colwise().mean();
Eigen::MatrixXf cov = centered.adjoint() * centered;
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig(cov);
//Setup homogenous tranformation to act as new basis functions for new coordinate frame
auto basis = Eigen::Matrix4f(eig.eigenvectors().colwise().homogeneous().rowwise().homogeneous());
basis.row(3) = Eigen::Vector4f::Zero();
basis.col(3) = Eigen::Vector4f::Zero();
basis(3,3) = 1.0f;
std::cout << "eig.eigenvectors() " << eig.eigenvectors() << std::endl;
std::cout << "Basis " << basis << std::endl;
//invert matrix and and transform points into new coordinate frame
auto invBasis = basis.inverse();
auto newVertices = invBasis * iglVertices.rowwise().homogeneous().transpose();
//Find max and min for all of the new axis
auto maxP = newVertices.rowwise().maxCoeff();
auto minP = newVertices.rowwise().minCoeff();
std::cout << "max " << maxP << std::endl;
std::cout << "min " << minP << std::endl;
//Find center and half extent in new coordinate frame
auto center = Eigen::Vector4f((maxP + minP)/2.0);
auto half_extent = Eigen::Vector4f((maxP - minP)/2.0);
auto t = Eigen::Vector4f((basis * center));
std::cout << "t " << t << std::endl;
//Update basis function with the translation between two coordinate origins
//I don't actually understand why I need this and have tried without it but still my bounding
//box is wrong
basis.col(3) = Eigen::Vector4f(t[0], t[1], t[2], t[3]);
std::cout << "Basis complete " << basis << std::endl;
std::cout << "center " << center << std::endl;
std::cout << "half_extent " << half_extent << std::endl;
//This is the same as the previous minP/maxP but thought i should try this as
// box is paramaterised with center and half-extent
auto max = center + half_extent;
auto min = center - half_extent;
//Transform back into the original coordinates
auto minNormalBasis = (basis * min).hnormalized();
auto maxNormalBasis = (basis * max).hnormalized();
std::cout << "min new coord" << min << std::endl;
std::cout << "max new coord"<< max << std::endl;
std::cout << "min old coord" << minNormalBasis << std::endl;
std::cout << "max old coord"<< maxNormalBasis << std::endl;
//Extract min and max
auto min_x = minNormalBasis[0];
auto min_y = minNormalBasis[1];
auto min_z = minNormalBasis[2];
auto max_x = maxNormalBasis[0];
auto max_y = maxNormalBasis[1];
auto max_z = maxNormalBasis[2];
bBox.clear();
//Build box for rendering
//Ordering specific to the faces I have manually generated
bBox.push_back(trimesh::point(min_x, min_y, min_z));
bBox.push_back(trimesh::point(min_x, max_y, min_z));
bBox.push_back(trimesh::point(min_x, min_y, max_z));
bBox.push_back(trimesh::point(min_x, max_y, max_z));
bBox.push_back(trimesh::point(max_x, min_y, max_z));
bBox.push_back(trimesh::point(max_x, max_y, max_z));
bBox.push_back(trimesh::point(max_x, min_y, min_z));
bBox.push_back(trimesh::point(max_x, max_y, min_z));
Выход печати для примера спрей бутылка
eig.eigenvectors() 0 -0.999992 -0.00411613
-0.707107 -0.00291054 0.707101
0.707107 -0.00291054 0.707101
Basis 0 -0.999992 -0.00411613 0
-0.707107 -0.00291054 0.707101 0
0.707107 -0.00291054 0.707101 0
0 0 0 1
max 2.98023e-08
0.216833
0.582629
1
min -2.98023e-08
-0.215
-0.832446
1
t -0.000402254
-0.0883253
-0.0883253
1
Basis complete 0 -0.999992 -0.00411613 -0.000402254
-0.707107 -0.00291054 0.707101 -0.0883253
0.707107 -0.00291054 0.707101 -0.0883253
0 0 0 1
center 0
0.000916399
-0.124908
1
half_extent 2.98023e-08
0.215916
0.707537
0
min new coord-2.98023e-08
-0.215
-0.832446
1
max new coord2.98023e-08
0.216833
0.582629
1
min old coord 0.218022
-0.676322
-0.676322
max old coord-0.219631
0.323021
0.323021
Спасибо за помощь, очень просто и лаконично в конце :). Для будущих читателей newVertices вычисляется с помощью Matrix newVertices = eig.eigenvectors(). Inverse(). Transpose() * iglVertices.transpose(); –
TrueWheel