-
-
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 2 commits
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 |
||
|
||
|
@@ -90,15 +90,15 @@ pcl::MarchingCubes<PointNT>::interpolateEdge (Eigen::Vector3f &p1, | |
float val_p2, | ||
Eigen::Vector3f &output) | ||
{ | ||
float mu = (iso_level_ - val_p1) / (val_p2-val_p1); | ||
float mu = (iso_level_ - val_p1) / (val_p2 - val_p1); | ||
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 |
||
output = p1 + mu * (p2 - 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; | ||
} | ||
} | ||
} | ||
|
||
|
||
|
@@ -224,53 +233,11 @@ pcl::MarchingCubes<PointNT>::getGridValue (Eigen::Vector3i pos) | |
template <typename PointNT> void | ||
pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PolygonMesh &output) | ||
{ | ||
if (!(iso_level_ >= 0 && iso_level_ < 1)) | ||
{ | ||
PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", getClassName ().c_str (), iso_level_); | ||
output.cloud.width = output.cloud.height = 0; | ||
output.cloud.data.clear (); | ||
output.polygons.clear (); | ||
return; | ||
} | ||
|
||
// Create grid | ||
grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f); | ||
|
||
// Populate tree | ||
tree_->setInputCloud (input_); | ||
|
||
getBoundingBox (); | ||
pcl::PointCloud<PointNT> points; | ||
|
||
// Transform the point cloud into a voxel grid | ||
// This needs to be implemented in a child class | ||
voxelizeData (); | ||
|
||
|
||
|
||
// Run the actual marching cubes algorithm, store it into a point cloud, | ||
// and copy the point cloud + connectivity into output | ||
pcl::PointCloud<PointNT> cloud; | ||
performReconstruction (points, output.polygons); | ||
|
||
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); | ||
for (size_t i = 0; i < output.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; | ||
output.polygons[i] = v; | ||
} | ||
pcl::toPCLPointCloud2(points, output.cloud); | ||
} | ||
|
||
|
||
|
@@ -281,15 +248,19 @@ pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PointCloud<PointNT> &po | |
{ | ||
if (!(iso_level_ >= 0 && iso_level_ < 1)) | ||
{ | ||
PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", getClassName ().c_str (), iso_level_); | ||
PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", | ||
getClassName ().c_str (), iso_level_); | ||
points.width = points.height = 0; | ||
points.points.clear (); | ||
polygons.clear (); | ||
return; | ||
} | ||
|
||
// the point cloud really generated from Marching Cubes, prev intermediate_cloud_ | ||
pcl::PointCloud<PointNT> intermediate_cloud; | ||
|
||
// Create grid | ||
grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f); | ||
grid_ = std::vector<float> (res_x_*res_y_*res_z_, NAN); | ||
|
||
// Populate tree | ||
tree_->setInputCloud (input_); | ||
|
@@ -302,17 +273,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); | ||
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 is potentially a huge number. Do we have a check for overflow somewhere? 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 wanted to avoid massive copy of vector. How to check overflow? Could you show me a file with this function? (in voxel grid I have seen similar output, but for overflow of uint32 or int32) 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 meant that this product may exceed what |
||
|
||
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); | ||
} | ||
|
||
points.swap(intermediate_cloud); | ||
|
||
polygons.resize (points.size () / 3); | ||
for (size_t i = 0; i < polygons.size (); ++i) | ||
{ | ||
|
@@ -324,8 +302,6 @@ pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PointCloud<PointNT> &po | |
} | ||
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,42 @@ pcl::MarchingCubesHoppe<PointNT>::~MarchingCubesHoppe () | |
template <typename PointNT> void | ||
pcl::MarchingCubesHoppe<PointNT>::voxelizeData () | ||
{ | ||
const bool is_far_ignored = dist_ignore_ > 0.0f; | ||
|
||
const Eigen::Vector3f min_p = min_p_.segment(0, 3); | ||
const Eigen::Vector3f delta = ( max_p_ - min_p_ ).segment(0, 3).cwiseQuotient( | ||
Eigen::Vector3f((float)res_x_, (float)res_y_, (float)res_z_) ); | ||
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 explicit cast necessary? |
||
|
||
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_); | ||
|
||
std::vector<int> nn_indices(1, 0); | ||
std::vector<float> nn_sqr_dists(1, 0.0f); | ||
const Eigen::Vector3f point = min_p + delta.cwiseProduct(Eigen::Vector3f(x, y, 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 |
||
{ | ||
const Eigen::Vector3f normal = input_->points[nn_indices[0]].getNormalVector3fMap (); | ||
|
||
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 ()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
|
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!