You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

obb.cpp 4.2 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #include <cmath>
  2. #include "Eigen/Dense"
  3. #include "Eigen/Eigen"
  4. #include "geo/private/math/obb.h"
  5. #include "geo/private/coord/gauss.h"
  6. #include "geo/private/coord/ct_convert.h"
  7. namespace ns
  8. {
  9. namespace geo
  10. {
  11. // 根据物体的型点坐标计算出obb包围盒,这里只计算2D的
  12. ObbData getObb(const std::vector<PointD>& points)
  13. {
  14. ObbData obb;
  15. if (points.size() < 3)
  16. {
  17. return obb;
  18. }
  19. // 将原来的数据转换到Eigen中的vector
  20. Eigen::MatrixX2d eigPoints = Eigen::MatrixX2d::Zero(points.size(), 2);
  21. for (size_t i = 0; i < points.size(); i++)
  22. {
  23. eigPoints.row(i) = Eigen::Vector2d(points[i].x, points[i].y);
  24. }
  25. // 求协方差矩阵
  26. // Eigen::Vector2d centerV = eigPoints.colwise().mean();
  27. // Eigen::Matrix2d covariance;
  28. // covariance.setZero();
  29. // for (size_t i = 0; i < points.size(); i++)
  30. // {
  31. // Eigen::Vector2d pAdg = Eigen::Vector2d(points[i].x, points[i].y) - centerV;
  32. // covariance += pAdg * pAdg.transpose();
  33. // }
  34. // covariance /= (double)points.size();
  35. Eigen::Vector2d meanVec = eigPoints.colwise().mean();
  36. Eigen::RowVector2d meanVecRow(Eigen::RowVector2d::Map(meanVec.data(), 2));
  37. Eigen::MatrixX2d zeroMeanMat = eigPoints;
  38. zeroMeanMat.rowwise() -= meanVecRow;
  39. Eigen::Matrix2d covariance = (zeroMeanMat.adjoint() * zeroMeanMat) / double(eigPoints.rows());
  40. // LOG_DEBUG("covariance row: {}, col: {}", covariance.rows(), covariance.cols());
  41. // 计算矩阵的特征值和特征向量
  42. Eigen::EigenSolver<Eigen::Matrix2d> solver(covariance);
  43. Eigen::Matrix2d eigenVectors = solver.eigenvectors().real();
  44. Eigen::Matrix2d eigenVectorsT = eigenVectors.transpose();
  45. // 应该是旋转到特征向量坐标系下面求出来长宽/四个角点,然后再将角点转回原来坐标系
  46. Eigen::MatrixXd ar = eigPoints * eigenVectors;
  47. // 求出的应该是一个矩阵,然后求出这组矩阵中的每一行的最大值和最小值
  48. // 形成一个最大矩阵组和一个最小矩阵组
  49. Eigen::RowVector2d mina = Eigen::RowVector2d(ar.colwise().minCoeff()); // Eigen的部分归约
  50. Eigen::RowVector2d maxa = Eigen::RowVector2d(ar.colwise().maxCoeff());
  51. // 最后再求出中心点、四个角点、heading、宽和高等
  52. Eigen::RowVector2d diff = (maxa - mina) * 0.5;
  53. Eigen::RowVector2d center = mina + diff;
  54. Eigen::MatrixXd corners = Eigen::MatrixXd::Zero(4, 2);
  55. corners.row(0) = center + Eigen::RowVector2d(-diff.x(), -diff.y());
  56. corners.row(1) = center + Eigen::RowVector2d(diff.x(), -diff.y());
  57. corners.row(2) = center + Eigen::RowVector2d(diff.x(), diff.y());
  58. corners.row(3) = center + Eigen::RowVector2d(-diff.x(), diff.y());
  59. // 中心点
  60. center = center * eigenVectorsT;
  61. // 四个角点
  62. corners = corners * eigenVectorsT;
  63. // heading
  64. Eigen::RowVector2d d1 = corners.row(0);
  65. Eigen::RowVector2d d2 = corners.row(1);
  66. // LOG_DEBUG("d2: {:.8f}, {:.8f}", d2.x(), d2.y());
  67. // LOG_DEBUG("d1: {:.8f}, {:.8f}", d1.x(), d1.y());
  68. double heading = atan2((d2.y() - d1.y()), (d2.x() - d1.x())) * 180 / c_pi();
  69. if (heading < 0)
  70. {
  71. heading += 360;
  72. }
  73. else if (heading >= 360)
  74. {
  75. heading -= 360;
  76. }
  77. // 宽和高
  78. double h = diff.maxCoeff() * 2.0;
  79. double w = diff.minCoeff() * 2.0;
  80. // 求z值,暂时根据所有z的平均值
  81. double sumZ = 0.0;
  82. for (size_t i = 0; i < points.size(); i++)
  83. {
  84. sumZ += points[i].z;
  85. }
  86. double avgZ = sumZ / points.size();
  87. // 保存需要的center点、heading、宽和高
  88. obb.centerPoint = PointD{center.x(), center.y(), avgZ};
  89. obb.width = w;
  90. obb.height = h;
  91. obb.heading = heading;
  92. // 从右上角顺时针方向存储角点
  93. obb.cornerPoints.emplace_back(corners.row(2).x(), corners.row(2).y(), avgZ);
  94. obb.cornerPoints.emplace_back(corners.row(1).x(), corners.row(1).y(), avgZ);
  95. obb.cornerPoints.emplace_back(corners.row(0).x(), corners.row(0).y(), avgZ);
  96. obb.cornerPoints.emplace_back(corners.row(3).x(), corners.row(3).y(), avgZ);
  97. return obb;
  98. }
  99. } // namespace geo
  100. } // namespace ns