-
-
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
Avoid phantom surfces in marching cubes hoppe #1874
Changes from 1 commit
22a4977
778adec
97969d6
10fe1eb
0334173
e918642
6cc5a6d
13b2a8f
a5cea53
f08107a
96d1eb4
3a7390f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,7 @@ | |
////////////////////////////////////////////////////////////////////////////////////////////// | ||
template <typename PointNT> | ||
pcl::MarchingCubes<PointNT>::MarchingCubes () | ||
: min_p_ (), max_p_ (), percentage_extend_grid_ (), iso_level_ () | ||
: min_p_ (), max_p_ (), percentage_extend_grid_ (), iso_level_ (), dist_ignore_ (-1.0f) | ||
{ | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wasn't this supposed to be moved to the .h file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this entire constructor to the .h |
||
|
||
|
@@ -97,8 +97,8 @@ pcl::MarchingCubes<PointNT>::interpolateEdge (Eigen::Vector3f &p1, | |
|
||
////////////////////////////////////////////////////////////////////////////////////////////// | ||
template <typename PointNT> void | ||
pcl::MarchingCubes<PointNT>::createSurface (std::vector<float> &leaf_node, | ||
Eigen::Vector3i &index_3d, | ||
pcl::MarchingCubes<PointNT>::createSurface (const std::vector<float> &leaf_node, | ||
const Eigen::Vector3i &index_3d, | ||
pcl::PointCloud<PointNT> &cloud) | ||
{ | ||
int cubeindex = 0; | ||
|
@@ -191,7 +191,7 @@ template <typename PointNT> void | |
pcl::MarchingCubes<PointNT>::getNeighborList1D (std::vector<float> &leaf, | ||
Eigen::Vector3i &index3d) | ||
{ | ||
leaf = std::vector<float> (8, 0.0f); | ||
leaf.resize(8); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space between |
||
|
||
leaf[0] = getGridValue (index3d); | ||
leaf[1] = getGridValue (index3d + Eigen::Vector3i (1, 0, 0)); | ||
|
@@ -201,6 +201,15 @@ pcl::MarchingCubes<PointNT>::getNeighborList1D (std::vector<float> &leaf, | |
leaf[5] = getGridValue (index3d + Eigen::Vector3i (1, 1, 0)); | ||
leaf[6] = getGridValue (index3d + Eigen::Vector3i (1, 1, 1)); | ||
leaf[7] = getGridValue (index3d + Eigen::Vector3i (0, 1, 1)); | ||
|
||
for(int i = 0; i < 8; ++i) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space after |
||
{ | ||
if(std::isnan(leaf[i])) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space after |
||
{ | ||
leaf.clear(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space after |
||
break; | ||
} | ||
} | ||
} | ||
|
||
|
||
|
@@ -233,36 +242,12 @@ pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PolygonMesh &output) | |
return; | ||
} | ||
|
||
// Create grid | ||
grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f); | ||
|
||
// Populate tree | ||
tree_->setInputCloud (input_); | ||
|
||
getBoundingBox (); | ||
|
||
// Transform the point cloud into a voxel grid | ||
// This needs to be implemented in a child class | ||
voxelizeData (); | ||
|
||
// real part of marching cube | ||
performReconstructionProc(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my comment below regarding the signature change for this block and the code that can also be included inside. |
||
|
||
pcl::toPCLPointCloud2 (intermediate_cloud_, output.cloud); | ||
|
||
// Run the actual marching cubes algorithm, store it into a point cloud, | ||
// and copy the point cloud + connectivity into output | ||
pcl::PointCloud<PointNT> cloud; | ||
|
||
for (int x = 1; x < res_x_-1; ++x) | ||
for (int y = 1; y < res_y_-1; ++y) | ||
for (int z = 1; z < res_z_-1; ++z) | ||
{ | ||
Eigen::Vector3i index_3d (x, y, z); | ||
std::vector<float> leaf_node; | ||
getNeighborList1D (leaf_node, index_3d); | ||
createSurface (leaf_node, index_3d, cloud); | ||
} | ||
pcl::toPCLPointCloud2 (cloud, output.cloud); | ||
|
||
output.polygons.resize (cloud.size () / 3); | ||
output.polygons.resize (intermediate_cloud_.size () / 3); | ||
for (size_t i = 0; i < output.polygons.size (); ++i) | ||
{ | ||
pcl::Vertices v; | ||
|
@@ -288,8 +273,28 @@ pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PointCloud<PointNT> &po | |
return; | ||
} | ||
|
||
// real part of marching cube | ||
performReconstructionProc(); | ||
|
||
points.swap(intermediate_cloud_); | ||
|
||
polygons.resize (points.size () / 3); | ||
for (size_t i = 0; i < polygons.size (); ++i) | ||
{ | ||
pcl::Vertices v; | ||
v.vertices.resize (3); | ||
for (int j = 0; j < 3; ++j) | ||
v.vertices[j] = static_cast<int> (i) * 3 + j; | ||
polygons[i] = v; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section can also be refactored into |
||
|
||
template <typename PointNT> void | ||
pcl::MarchingCubes<PointNT>::performReconstructionProc () | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment above regarding the signature for this one. |
||
{ | ||
// Create grid | ||
grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f); | ||
// grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't submit commented lines |
||
grid_ = std::vector<float> (res_x_*res_y_*res_z_, NAN); | ||
|
||
// Populate tree | ||
tree_->setInputCloud (input_); | ||
|
@@ -302,30 +307,24 @@ pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PointCloud<PointNT> &po | |
|
||
// Run the actual marching cubes algorithm, store it into a point cloud, | ||
// and copy the point cloud + connectivity into output | ||
points.clear (); | ||
intermediate_cloud_.clear(); | ||
|
||
// preallocate memory assuming a hull. suppose 6 point per voxel | ||
intermediate_cloud_.reserve((size_t)(res_y_*res_z_ + res_x_*res_z_ + res_x_*res_y_) * 2 * 6); | ||
|
||
for (int x = 1; x < res_x_-1; ++x) | ||
for (int y = 1; y < res_y_-1; ++y) | ||
for (int z = 1; z < res_z_-1; ++z) | ||
{ | ||
Eigen::Vector3i index_3d (x, y, z); | ||
std::vector<float> leaf_node; | ||
getNeighborList1D (leaf_node, index_3d); | ||
createSurface (leaf_node, index_3d, points); | ||
if(!leaf_node.empty()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space after |
||
createSurface (leaf_node, index_3d, intermediate_cloud_); | ||
} | ||
|
||
polygons.resize (points.size () / 3); | ||
for (size_t i = 0; i < polygons.size (); ++i) | ||
{ | ||
pcl::Vertices v; | ||
v.vertices.resize (3); | ||
for (int j = 0; j < 3; ++j) | ||
v.vertices[j] = static_cast<int> (i) * 3 + j; | ||
polygons[i] = v; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In conjunction with my other comments, leave this here. |
||
} | ||
|
||
|
||
|
||
#define PCL_INSTANTIATE_MarchingCubes(T) template class PCL_EXPORTS pcl::MarchingCubes<T>; | ||
|
||
#endif // PCL_SURFACE_IMPL_MARCHING_CUBES_H_ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,26 +60,46 @@ pcl::MarchingCubesHoppe<PointNT>::~MarchingCubesHoppe () | |
template <typename PointNT> void | ||
pcl::MarchingCubesHoppe<PointNT>::voxelizeData () | ||
{ | ||
const bool is_far_ignored = dist_ignore_ > 0.0f; | ||
|
||
std::vector<int> nn_indices(1, 0); | ||
std::vector<float> nn_sqr_dists(1, 0.0f); | ||
Eigen::Vector3f point; | ||
PointNT p; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment regarding the two lines above: I'm an apologist of RAII. Does this grant you a super duper performance increase to justify declaring it here? |
||
const Eigen::Vector4f delta = ( max_p_ - min_p_ ).cwiseQuotient( Eigen::Vector4f( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really understand the reason behind declaring this as Vector4f. Was it to make it aligned or something? Note that if you declare it Vector3f (use actually Array3f to use element wise operations later on) you can reduce the expression below, inside the nested for blocks. Edit: Now I'm definitely sure use you want to perform element wise operations. Read on Eigen about Arrays and block. Create delta as an Array3f for the three top element block of max_p_ min_p_. |
||
float (res_x_), float (res_y_), float (res_z_), 1.0f ) ); | ||
|
||
Eigen::Vector3f normal; | ||
|
||
for (int x = 0; x < res_x_; ++x) | ||
{ | ||
const int y_start = x * res_y_ * res_z_; | ||
|
||
for (int y = 0; y < res_y_; ++y) | ||
{ | ||
const int z_start = y_start + y * res_z_; | ||
|
||
for (int z = 0; z < res_z_; ++z) | ||
{ | ||
std::vector<int> nn_indices; | ||
std::vector<float> nn_sqr_dists; | ||
|
||
Eigen::Vector3f point; | ||
point[0] = min_p_[0] + (max_p_[0] - min_p_[0]) * float (x) / float (res_x_); | ||
point[1] = min_p_[1] + (max_p_[1] - min_p_[1]) * float (y) / float (res_y_); | ||
point[2] = min_p_[2] + (max_p_[2] - min_p_[2]) * float (z) / float (res_z_); | ||
point[0] = min_p_[0] + delta[0] * float (x); | ||
point[1] = min_p_[1] + delta[1] * float (y); | ||
point[2] = min_p_[2] + delta[2] * float (z); | ||
|
||
PointNT p; | ||
p.getVector3fMap () = point; | ||
|
||
tree_->nearestKSearch (p, 1, nn_indices, nn_sqr_dists); | ||
|
||
grid_[x * res_y_*res_z_ + y * res_z_ + z] = input_->points[nn_indices[0]].getNormalVector3fMap ().dot ( | ||
point - input_->points[nn_indices[0]].getVector3fMap ()); | ||
if( !is_far_ignored || nn_sqr_dists[0] < dist_ignore_ ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space after |
||
{ | ||
normal = input_->points[nn_indices[0]].getNormalVector3fMap (); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const |
||
|
||
if(normal.norm() > 0.5f) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this necessary? I thought PCL maintains the invariant There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In some point clouds I used (maybe not generated with pcl, but with quite fine normal), some points have normal vector with length 0. Would the normal be [0] if the neighborhood is not consistent? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, at least in |
||
grid_[z_start + z] = normal.dot ( | ||
point - input_->points[nn_indices[0]].getVector3fMap ()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -430,6 +430,15 @@ namespace pcl | |
getPercentageExtendGrid () | ||
{ return percentage_extend_grid_; } | ||
|
||
/** \brief Method that sets the parameter that defines the distance to ignore the distance to ignore | ||
* a grid | ||
* \param[in] threshold of distance. if it is negative, then calculate in all grids; otherwise | ||
* ignore grids with distance to point cloud(to nearest point) larger than distIgnore | ||
*/ | ||
inline void | ||
setDistanceIgnore (float distIgnore) | ||
{ dist_ignore_ = distIgnore; } | ||
|
||
protected: | ||
/** \brief The data structure storing the 3D grid */ | ||
std::vector<float> grid_; | ||
|
@@ -447,6 +456,15 @@ namespace pcl | |
/** \brief The iso level to be extracted. */ | ||
float iso_level_; | ||
|
||
/** \brief ignore the distance function | ||
* if it is negative | ||
* or distance between voxel centroid and point are larger that it. */ | ||
float dist_ignore_; | ||
|
||
/** \brief the point cloud really generated from Marching Cubes | ||
*/ | ||
pcl::PointCloud<PointNT> intermediate_cloud_; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the changes requested I think this member can be removed and just exist in a temporary scope inside the methods. |
||
|
||
/** \brief Convert the point cloud into voxel data. */ | ||
virtual void | ||
voxelizeData () = 0; | ||
|
@@ -468,8 +486,8 @@ namespace pcl | |
* \param cloud point cloud to store the vertices of the polygon | ||
*/ | ||
void | ||
createSurface (std::vector<float> &leaf_node, | ||
Eigen::Vector3i &index_3d, | ||
createSurface (const std::vector<float> &leaf_node, | ||
const Eigen::Vector3i &index_3d, | ||
pcl::PointCloud<PointNT> &cloud); | ||
|
||
/** \brief Get the bounding box for the input data points. */ | ||
|
@@ -508,6 +526,11 @@ namespace pcl | |
performReconstruction (pcl::PointCloud<PointNT> &points, | ||
std::vector<pcl::Vertices> &polygons); | ||
|
||
/** \brief real marching cube part. called in two performReconstruction-s | ||
*/ | ||
virtual void | ||
performReconstructionProc (); | ||
|
||
public: | ||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
}; | ||
|
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.
Actually, in PCL we often have such simple constructor definitions right in the header file, motivation being that it's easier to see the default values. While we are at it, would you mind to transfer this to the header and also fill in the values of
min_p_
,max_p_
, etc for clarity?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.
Move the whole constructor into header file? Maybe I could move min_p_ and max_p_ to local variable and change to vector3f, it looks a bit stateful to have them as class members. How do you say?
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 had a brief look and they are used in different functions both in parent and deriving class. If you have an idea how to make them local without need to recompute several times, please go ahead!