-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add computeCentroidAndOBB function #5690
Add computeCentroidAndOBB function #5690
Conversation
@mvieth please let me know what you think about the two points left from the previous pull request (enforcing right hand rule and Eigen::Affine ) that I proposed to postpone. please see the comments there |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mvieth please let me know what you think about the two points left from the previous pull request (enforcing right hand rule and Eigen::Affine ) that I proposed to postpone. please see the comments there
If the cross product is used to enforce the right hand rule, I am fine with it, but I would prefer using Eigen's vec1.cross(vec2)
function to not "reinvent the wheel" and add a comment why this is done.
Regarding Eigen::Affine
: yes I think it would be a good idea to try that since it would lead to shorter and potentially faster code (Eigen may use SIMD instructions).
could you please suggest a link to read about this SIMD (to possibly study also how to trigger it)? i conceived this as the projection of the vector v=[xd,yd,zd] on the 3 axes major...minor to give the 3 Cartesian components which is defined below but can be defined before as that seems to me conceptually more simple and straight forward then an affine transform of coordinates, which I am not sure how to implement in this case with an Eigen call probably it might get convenient make a global affine transformed copy of all the cloud before the for cycle, instead of on the single point inside the for, probably that is what you meant that would allow also to reduce the executed < and > inside the for() which I saw cost time because you can if ( < min ) with ) I know for instance soemthing like this Eigen::Affine3f transform_2 = Eigen::Affine3f::Identity(); or also something like this (defining the Homogenous matrix 4x4) Eigen::Matrix4f transform_1 = Eigen::Matrix4f::Identity(); what's the best way you think to use Eigen instead of pcl in the last step ( pcl::transformPointCloud ) ? |
no problem |
If you have never heard of SIMD before, the Wikipedia page could be a good starting point. This page discusses some Eigen internals. This FAQ page is also very informative. The basic idea is that an operation is done on multiple values (usually 4, 8, or 16) at the same time, which can be much faster. Eigen will use SIMD operations if possible, for example when multiplying with a 4x4 matrix (or equivalently when using an affine transform).
That would also be possible, but not quite what I meant. We don't need to store all the transformed points, we can just transform each point, compare, and "forget" the point.
If the function works but is not fully optimized performance-wise, that is also fine by me. Just say what you are willing to do/how much time you have. |
of course I have heard of it I just wanted to know how and when it is applied by eigen in this case.
of course the change of reference is also considerable as an homogeneous transform I have implemented it. I had to solve a stupid bug I had done float: 6 -> 7 msec How to assess if eigen is optimizing? i pushed the code, please let me know what you think about it and please let's close this point soon ;)) |
@mvieth centroid = centroid4.head<3>(); compiles on my PC but does not compile on azure pipeline so I had to restore it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to assess if eigen is optimizing?
Eigen says: https://eigen.tuxfamily.org/index.php?title=FAQ#How_can_I_check_that_vectorization_is_actually_being_used.3F
Please also add a note to https://github.com/PointCloudLibrary/pcl/blob/master/doc/tutorials/content/moment_of_inertia.rst specifying that users who only need the obb or aabb, but not the descriptors, should use computeCentroidAndOBB or getMinMax3D (faster)
…ion + ref in moment of inertia tutorial
@mvieth it's all set up |
|
||
for (; i<cloud.points.size();++i) | ||
{ | ||
auto point = cloud.points[i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, an isFinite
check is missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i will check it later but yes sorry!! seems a silly bug
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh, and don't use .points - use the operators on the pointcloud directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sorry I don't think I understand in detail what you mean, can you exemplify in more detail please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if it is mvieth - I could imagine something like:
If(!pcl::isInfinite(point))
continue;
|
||
for (; i<indices.size();++i) | ||
{ | ||
auto point = cloud.points[indices[i]]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isFinite
check also missing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as above
common/include/pcl/common/centroid.h
Outdated
* \param[out] centroid the centroid of the set of points in the cloud | ||
* \param[out] obb_center position of the centroid of the OBB (Oriented Bounding Box) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please describe better what the difference between centroid and obb_center is.
For the description of obb_center, I would strictly use the word "center" instead of "centroid" to avoid confusion.
For centroid, I would mention that this is the mean of all points, and perhaps that obb_center and centroid are very different if the cloud is highly skewed or has outliers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, the two are the same if the cloud is centrally symmetric.
the obb centre is the centroid of the 8 OBB vertices= centre of symmetry of the OBB (so I called it centroid, but I agree it might be misleading and needs better clarification as you wrote)
|
||
for (; i<cloud.points.size();++i) | ||
{ | ||
auto point = cloud.points[i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto point = cloud.points[i]; | |
auto point = cloud[i]; |
i pushed the corrections |
|
||
if (cloud.is_dense) | ||
{ | ||
auto point = cloud[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you process this first point outside the for loop?
Else you could have a for-range loop, ie:
for(const auto& point : cloud)
{
...
}
couldn't you?
anyways, you missed a few .points in the for loops 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for the non-dense branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the sane reason I have split the non dense for loop in two parts: to set min max finite so to have
if (P(0) < obb_min_pointx)
obb_min_pointx = P(0);
else if (P(0) > obb_max_pointx)
obb_max_pointx = P(0);
instead of
if (P(0) < obb_min_pointx)
obb_min_pointx = P(0);
if (P(0) > obb_max_pointx)
obb_max_pointx = P(0);
one might avoid also
obb_min_pointx = obb_min_pointy = obb_min_pointz = std::numeric_limits::max();
obb_max_pointx = obb_max_pointy = obb_max_pointz = std::numeric_limits::min();
but then the compiler doesn't like it cause it sees a possible non initialization (if the cloud is non dense and all non finite or if it is of size 0)
do you mean cloud.points.size() ??
that is a different thing
I checked there is an inline efficient operator[]
but for this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh. Make sense.
Yes, I pretty sure you can and should use cloud.size(). The .points should have been a private member, as it exposes the internal container type. Which makes it unchangeable atm, but eventually one could.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you save lots of compares if the first point is in the right "side" and then the next just grows or shrink. Worst case you would have equally as many compares btween the two solutions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one could make difficult statistical analysis on this based on the statistical cloud distribution. for a uniform density the probability would inolv some sort of geometric progression. the best case you save more is when the cloud is a surface with indexes decreasing progressively in x,y,z, the worst the opposite. one could think of a dynamical object that changes the code of comparison based on the cloud progression but let's leave it. I just measured with a counter with one of my main samples and it gives this on 11 segments
saved 0.000258977
saved 0.00359994
saved 0.00205254
saved 0.00217213
saved 0.0025008
saved 0.0554903
saved 0.00217482
saved 0.00121175
saved 0.0190972
saved 0.00453767
saved 0.00445811
Loaded cloud width*height = 2205157 w,h= 2205157 , 1
cloud is_dense= 1
cloud isOrganized= 0
so you can see from 0.02% to 5.5% comparisons avoided, 0.9% in average on this cloud, it can change a lot from cloud to cloud
major_axis(0), middle_axis(0), minor_axis(0), | ||
major_axis(1), middle_axis(1), minor_axis(1), | ||
major_axis(2), middle_axis(2), minor_axis(2); | ||
//obb_rotational_matrix.col(0)==major_axis |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I consider this comment necessary
major_axis(0), middle_axis(0), minor_axis(0), | ||
major_axis(1), middle_axis(1), minor_axis(1), | ||
major_axis(2), middle_axis(2), minor_axis(2); | ||
//obb_rotational_matrix.col(0)==major_axis |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove?
the tests have failed due to kfpcs_ia, has the master erros now? |
No, its somehow a flaky test. |
{ | ||
Eigen::Matrix<Scalar, 3, 3> covariance_matrix; | ||
Eigen::Matrix<Scalar, 4, 1> centroid4; | ||
unsigned int point_count= computeMeanAndCovarianceMatrix(cloud, covariance_matrix, centroid4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unsigned int point_count= computeMeanAndCovarianceMatrix(cloud, covariance_matrix, centroid4); | |
const auto point_count = computeMeanAndCovarianceMatrix(cloud, covariance_matrix, centroid4); |
Eigen::SelfAdjointEigenSolver<Eigen::Matrix<Scalar, 3, 3>> evd(covariance_matrix); | ||
|
||
Eigen::Matrix<Scalar, 3, 3> eigenvectors_ = evd.eigenvectors(); | ||
Eigen::Matrix<Scalar, 3, 1> major_axis; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const Eigen::Matrix<Scalar, 3, 1> minor_axis = eigenvectors_.col(0); //the eigenvectors do not need to be normalized (they are already)
const Eigen::Matrix<Scalar, 3, 1> middle_axis = eigenvectors_.col(1);
// Enforce right hand rule
const Eigen::Matrix<Scalar, 3, 1> major_axis = middle_axis.cross(minor_axis);
|
||
if (cloud.is_dense) | ||
{ | ||
auto point = cloud[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto point = cloud[0]; | |
const auto& point = cloud[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get a reference instead of making a copy? Can be applied several places.
|
||
obb_center = centroid+ obb_rotational_matrix * shift;//position of the OBB center in the same reference Oxyz of the point cloud | ||
|
||
return ( point_count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return ( point_count); | |
return (point_count); |
obb_dimensions(1) = obb_max_pointy - obb_min_pointy; | ||
obb_dimensions(2) = obb_max_pointz - obb_min_pointz; | ||
|
||
obb_center = centroid+ obb_rotational_matrix * shift;//position of the OBB center in the same reference Oxyz of the point cloud |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
obb_center = centroid+ obb_rotational_matrix * shift;//position of the OBB center in the same reference Oxyz of the point cloud | |
obb_center = centroid + obb_rotational_matrix * shift;//position of the OBB center in the same reference Oxyz of the point cloud |
@@ -52,6 +53,7 @@ | |||
namespace pcl | |||
{ | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
|
||
} | ||
|
||
Eigen::Matrix<Scalar, 3, 1> //shift between point cloud centroid and OBB center (position of the OBB center relative to (p.c.centroid, major_axis, middle_axis, minor_axis)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const infront - can be applied to several of the Eigen::Matrix's.
{ | ||
Eigen::Matrix<Scalar, 3, 3> covariance_matrix; | ||
Eigen::Matrix<Scalar, 4, 1> centroid4; | ||
const auto point_count= computeMeanAndCovarianceMatrix(cloud, covariance_matrix, centroid4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const auto point_count= computeMeanAndCovarianceMatrix(cloud, covariance_matrix, centroid4); | |
const auto point_count = computeMeanAndCovarianceMatrix(cloud, covariance_matrix, centroid4); |
|
||
if (cloud.is_dense) | ||
{ | ||
const auto & point = cloud[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const auto & point = cloud[0]; | |
const auto& point = cloud[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are multiple places for this
Minor formatting errors, but else it looks good! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
/** \brief Compute centroid, OBB, PCA axes of a given set of points.
*/
light connection with issue #5659 which can be closed after this merge