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
implementation of ball pivoting for surface reconstruction #1950
base: master
Are you sure you want to change the base?
Conversation
Thanks for contributing this. It looks pretty neat 👍 Some preliminary comments:
|
I'll do unit test soon. But where should I write the example and tutorial? |
All our tutorials are contained in this same repository under the "doc" directory. You can take any of the existing tutorials as an example. But I would say let's first concentrate on adding unit tests, reviewing and merging this. The tutorial can be added in a separate PR later on. Unfortunately I don't have any time today/tomorrow, but I will go through the code and leave comments later this week. |
The unit test I wrote failed. But it is successful locally. Can you help me? |
Unfortunately there's not much I can do on my side other than run it on a Darwin platform. You need to think about a synthetic small test case, in which you can theoretically predict the outcome, without having to run the algorithm. You should be able to fully understand what are the algorithm's capabilities and limitations, and come up with test scenarios which exploit success and failure conditions. Loading the bun.pcd and then performing reconstruction, gives me the impression you're doing the exactly reverse process which is better than not having a unit test, but it's not a good unit test. My advice is to rewrite the unit test following the guidelines I just gave you. |
Do you mean composing a hand-made simple cloud and doing unit test with it? But aren't many other unit tests done with the reverse way? |
Exactly
In our repo? Definitely. But it doesn't necessarily make them good unit tests. :) |
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.
Thanks for contributing. I think we will need several rounds of reviews to get this merged.
My first request will be on the structural side of things. The Edge
and Front
classes are currently members of the BPA class and, as such, are implicitly templated on the point type. However, their implementation is virtually independent of the point type. Only exception is the Edge::center_
member field of type PointNT
. However, only the XYZ coordinates of it are used, so it can be replaced with Eigen::Vector3f.
With this is mind, I'd propose to strip these classes off from BPA. They can remain in the same header file, maybe renamed to BallPivotingEdge
and BallPivotingFront
to make their scope clear. The implementation can be moved to the "cpp" file because it is template-free.
This change will decrease compilation time and the binary size, because useless instantiations of virtually the same classes will be avoided.
#define PCL_BALL_PIVOTING_H_ | ||
|
||
/** | ||
* This class is an implementation of ball pivoting algorithm with some different details |
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.
This Doxygen comment should be moved to be directly above the class declaration.
We typically have just authors/title/journal instead of a full BiBTeX entry, i.e. in this case
Bernardini F., Mittleman J., Rushmeier H., Silva C., Taubin G., "The ball-pivoting algorithm for surface reconstruction", TVCG'99
Also, please add \ingroup surface
tag.
Finally, it would be great to have a sentence or two with high-level usage guideline. For example (just copied from the paper, assume these claims are actually true):
BPA exhibits linear time complexity and robustness to noise in real scanned data. The output mesh is a manifold of an alpha-shape of the point set.
BPA requires that the points are distributed over the entire surface with a spatial frequency greater than or equal to a certain minimum value. An estimate of surface normal should be available for every point.
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 think that Edge
should be a plain data struct
. In its current form it has no "business logic", i.e. methods besides from member field accessors. And the accessors are trivial, there are no invariants to be maintained (besides from the size of id_vertices_ vector, which as I commented, should be just an array).
surface/CMakeLists.txt
Outdated
@@ -121,6 +122,7 @@ if(build) | |||
"include/pcl/${SUBSYS_NAME}/marching_cubes.h" | |||
"include/pcl/${SUBSYS_NAME}/marching_cubes_hoppe.h" | |||
"include/pcl/${SUBSYS_NAME}/marching_cubes_rbf.h" | |||
"include/pcl/${SUBSYS_NAME}/ball_pivoting.h" |
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.
Don't forget that the header with helper structures should also be installed.
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.
Is this issue still open?
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.
No, it's not an issue, I see you added "ball_pivoting_front.h", thanks.
* Software License Agreement (BSD License) | ||
* | ||
* Point Cloud Library (PCL) - www.pointclouds.org | ||
* Copyright (c) 2014-, Open Perception, Inc. |
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.
2017
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.
is it necessary? not the starting time of the license?
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.
This is a brand new file, created in 2017. You can not claim copyright for the time before it existed!
#ifndef PCL_BALL_PIVOTING_H_ | ||
#define PCL_BALL_PIVOTING_H_ | ||
|
||
#include <memory> |
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.
Isn't this a c++11 header? Why do we need 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.
for pair, not right?
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.
No, std::pair
comes from <utility>
header. But you don't need to include it explicitly, for example map
already has it.
|
||
#include <memory> | ||
#include <vector> | ||
#include <map> |
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.
map
and set
includes should be in the "ball_pivoting_front.h", that's where they are needed.
* Software License Agreement (BSD License) | ||
* | ||
* Point Cloud Library (PCL) - www.pointclouds.org | ||
* Copyright (c) 2014-, Open Perception, Inc. |
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.
2017
* returns the center of ball | ||
* @return | ||
*/ | ||
Eigen::Vector3f |
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.
Better return by const reference to avoid copies.
class Edge | ||
{ | ||
protected: | ||
/** list of vertice index, should have length 2 */ |
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.
If this list should have a fixed length, why not using good ol' array? I.e. uint32_t id_vertices_[2];
Edge (); | ||
|
||
/** | ||
* a fake constructor with only vertice index on edge |
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'm not sure if "fake" is a good terminology, it's not clear what is implied. What is the state of the other variables? Is an edge constructed this way valid?
* @return | ||
*/ | ||
uint32_t | ||
getIdVertice (const size_t id) const |
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.
Should be getIdVertex
Speaking of the |
Buenas mis amigos. Is the code and unit test better now? |
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.
Thanks for the effort so far, I think we are getting close.
A general comment: we should not have free functions inside the "hpp" file. They are an implementation detail of BPA, but by keeping them free you "leak" them into the rest of PCL. Please turn them into private class methods, maybe static if you want. Also, please follow the PCL style guide regarding the function naming, not snake_case()
, but camelCase()
.
surface/src/ball_pivoting.cpp
Outdated
/* | ||
* Software License Agreement (BSD License) | ||
* | ||
* Copyright (c) 2017, Willow Garage, Inc. |
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.
This should be Open Perception
surface/src/ball_pivoting.cpp
Outdated
* copyright notice, this list of conditions and the following | ||
* disclaimer in the documentation and/or other materials provided | ||
* with the distribution. | ||
* * Neither the name of Willow Garage, Inc. nor the names of its |
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 also, no Willow Garage. Please just copy the license from your other files.
} // namespace pcl | ||
|
||
// Instantiations of specific point types | ||
PCL_INSTANTIATE(BallPivoting, (pcl::PointNormal)(pcl::PointXYZRGBNormal)(pcl::PointXYZINormal)) |
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.
This should be conditionally compiled depending on the PCL_NO_PRECOMPILE
macro. Please take this as an example.
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.
Both XYZ and Normal are necessary, which macro should I use? I didn't find "PCL_XYZ_NORMAL_POINT_TYPES" or "PCL_XYZNORMAL_POINT_TYPES"
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 did not mean to change the point types, my comment was about conditional compilation. I.e. something like:
#ifndef PCL_NO_PRECOMPILE
#include <pcl/point_types.h>
#include <pcl/impl/instantiate.hpp>
PCL_INSTANTIATE(BallPivoting, (pcl::PointNormal)(pcl::PointXYZRGBNormal)(pcl::PointXYZINormal))
#endif
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.
now there is no problem, i though you meant compilation with different range of types
surface/src/ball_pivoting.cpp
Outdated
|
||
#include <boost/make_shared.hpp> | ||
|
||
#include <pcl/impl/instantiate.hpp> |
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.
This include should be inside the conditional compilation branch, see my comment in the end of this file.
* @param num_point_in_radius | ||
* @param ratio_success | ||
*/ | ||
virtual void |
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 is this virtual? Do we expect other algorithms deriving from BPA that will want to modify this behavior?
* @param ratio_success | ||
*/ | ||
virtual void | ||
setEstimatedRadius (const int num_sample_point, const int num_point_in_radius, const float ratio_success); |
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 think this is not a clear name. What about setSearchRadiusAutomatic()
? This will make connection with the setSearchRadius()
function, thus making clear for the user that these two functions have the same purpose of setting the search radius. Further, I think we should provide some reasonable default values for the arguments.
*/ | ||
template<typename PointNT> | ||
double | ||
guess_radius (const typename PCLSurfaceBase<PointNT>::KdTreePtr &kdtree, |
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 do not see a reason to have this as a free function. This simply provides an implementation for setEstimatedRadius()
and is only used there.
BTW, these are the default parameters I asked for.
* @param point0 | ||
* @param point1 | ||
* @param center | ||
* @param plane the rotation is along the normal vector of plane |
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 we need to explicitly pass the plane? Isn't it implicitly determined by the three points?
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.
The direction can be inferred in normal vector of the plane, either alpha in one direction or 360-alpha in the other
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.
Hm, I still not sure if I get this. The angle between these two vectors is simply
alpha = acos(vc0.dot(vc1));
And then, based on direction of the plane normal, you want to change it to 2pi - alpha
?
virtual void | ||
setEstimatedRadius (const int num_sample_point, const int num_point_in_radius, const float ratio_success); | ||
void | ||
setSearchRadiusAutomatically (const int num_sample_point = 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.
Can this be a typo? Before when the function was called guess_radius
the default was 500.
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.
should not be, now non-positive parameter would be changed to one ratio of point cloud size, 10% or 20% i remember
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.
This definitely needs to be documented. What if instead of number of sample points this function take the fraction of sample points, between 0 and 1? And the default value will be explicitly 0.2?
* @param point0 | ||
* @param point1 | ||
* @param center | ||
* @param plane the rotation is along the normal vector of plane |
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.
Hm, I still not sure if I get this. The angle between these two vectors is simply
alpha = acos(vc0.dot(vc1));
And then, based on direction of the plane normal, you want to change it to 2pi - alpha
?
…archRadiusAutomatically's parameters, rectification for rate_success
Hi, sorry for the miss-operations. After some reading, I think geometry.h is better as a container for the first two function: plane in between and circle centre, how do you think? I can also correct this odd thing, that the functions are defined in .h file. Maybe also the case that angle.hpp should be a cpp file, as there is no template. How do you like? |
Hello, the CI seems to fail because time went out, what could I do about it? Thx :) |
Rebase with master. The tests were split in two jobs IIRC and you should no longer have timeouts. |
Hello, thank you for your suggestion, it looks like the VTK cannot be found.. What should I do? |
This pull request has been automatically marked as stale because it hasn't had Come back whenever you have time. We look forward to your contribution. |
algorithm from
general structure from https://github.com/rodschulz/BPA
fitted from https://github.com/t-lou/bpa_remake
example
input point cloud
output surface