Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
marching_cubes.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  */
00035 
00036 #ifndef PCL_SURFACE_IMPL_MARCHING_CUBES_H_
00037 #define PCL_SURFACE_IMPL_MARCHING_CUBES_H_
00038 
00039 #include "pcl/surface/marching_cubes.h"
00040 #include <pcl/common/common.h>
00041 #include <pcl/common/vector_average.h>
00042 #include <pcl/Vertices.h>
00043 #include <pcl/kdtree/kdtree_flann.h>
00044 
00046 template <typename PointNT>
00047 pcl::MarchingCubes<PointNT>::MarchingCubes ()
00048 {
00049 }
00050 
00052 template <typename PointNT>
00053 pcl::MarchingCubes<PointNT>::~MarchingCubes ()
00054 {
00055 }
00056 
00058 template <typename PointNT> void
00059 pcl::MarchingCubes<PointNT>::getBoundingBox ()
00060 {
00061   pcl::getMinMax3D (*input_, min_p_, max_p_);
00062 
00063   Eigen::Vector4f bounding_box_size = max_p_ - min_p_;
00064 
00065   bounding_box_size = max_p_ - min_p_;
00066   PCL_DEBUG ("[pcl::MarchingCubes::getBoundingBox] Size of Bounding Box is [%f, %f, %f]\n",
00067       bounding_box_size.x (), bounding_box_size.y (), bounding_box_size.z ());
00068   double max_size =
00069     (std::max) ((std::max)(bounding_box_size.x (), bounding_box_size.y ()),
00070                 bounding_box_size.z ());
00071 
00072   data_size_ = max_size / leaf_size_;
00073   PCL_DEBUG ("[pcl::MarchingCubes::getBoundingBox] Lower left point is [%f, %f, %f]\n",
00074       min_p_.x (), min_p_.y (), min_p_.z ());
00075   PCL_DEBUG ("[pcl::MarchingCubes::getBoundingBox] Upper left point is [%f, %f, %f]\n",
00076       max_p_.x (), max_p_.y (), max_p_.z ());
00077   PCL_DEBUG ("[pcl::MarchingCubes::getBoundingBox] Padding size: %d\n", padding_size_);
00078   PCL_DEBUG ("[pcl::MarchingCubes::getBoundingBox] Leaf size: %f\n", leaf_size_);
00079 
00080   gaussian_scale_ = pow ((padding_size_+1) * leaf_size_ / 2.0, 2.0);
00081 }
00082 
00084 template <typename PointNT> void
00085 pcl::MarchingCubes<PointNT>::interpolateEdge (float iso_level,
00086                                               Eigen::Vector3f &p1,
00087                                               Eigen::Vector3f &p2,
00088                                               float val_p1,
00089                                               float val_p2,
00090                                               Eigen::Vector3f &output)
00091 {
00092   if (iso_level - val_p1 < 0.00001)
00093     output = p1;
00094   if (iso_level - val_p2 < 0.00001)
00095     output = p2;
00096   if (val_p1 - val_p2 < 0.00001)
00097     output = p1;
00098 
00099   float mu = (iso_level - val_p1) / (val_p2-val_p1);
00100   output[0] = p1[0] + mu * (p2[0] - p1[0]);
00101   output[1] = p1[1] + mu * (p2[1] - p1[1]);
00102   output[2] = p1[2] + mu * (p2[2] - p1[2]);
00103 }
00104 
00106 template <typename PointNT> void
00107 pcl::MarchingCubes<PointNT>::createSurface (Leaf leaf_node,
00108                                             Eigen::Vector3i &index_3d,
00109                                             pcl::PointCloud<PointNT> &cloud,
00110                                             float iso_level)
00111 {
00112   int cubeindex = 0;
00113   Eigen::Vector3f vertex_list[12];
00114   if (leaf_node.vertex[0] < iso_level) cubeindex |= 1;
00115   if (leaf_node.vertex[1] < iso_level) cubeindex |= 2;
00116   if (leaf_node.vertex[2] < iso_level) cubeindex |= 4;
00117   if (leaf_node.vertex[3] < iso_level) cubeindex |= 8;
00118   if (leaf_node.vertex[4] < iso_level) cubeindex |= 16;
00119   if (leaf_node.vertex[5] < iso_level) cubeindex |= 32;
00120   if (leaf_node.vertex[6] < iso_level) cubeindex |= 64;
00121   if (leaf_node.vertex[7] < iso_level) cubeindex |= 128;
00122 
00123   // Cube is entirely in/out of the surface
00124   if (edgeTable[cubeindex] == 0)
00125      return;
00126 
00127   std::vector<Eigen::Vector3f> p;
00128   p.resize (8);
00129   Eigen::Vector4f center;
00130   getCellCenterFromIndex (index_3d, center);
00131   for (int i = 0; i < 8; ++i)
00132   {
00133     Eigen::Vector3f point;
00134     if(i & 0x4)
00135       point[1] = center[1] + leaf_size_/2;
00136     else
00137       point[1] = center[1] - leaf_size_/2;
00138 
00139     if(i & 0x2)
00140       point[2] = center[2] + leaf_size_/2;
00141     else
00142       point[2] = center[2] - leaf_size_/2;
00143 
00144     if((i & 0x1) ^ ((i >> 1) & 0x1))
00145       point[0] = center[0] + leaf_size_/2;
00146     else
00147       point[0] = center[0] - leaf_size_/2;
00148 
00149     p[i] = point;
00150   }
00151 
00152   // Find the vertices where the surface intersects the cube
00153   if (edgeTable[cubeindex] & 1)
00154     interpolateEdge (iso_level,p[0],p[1],leaf_node.vertex[0],leaf_node.vertex[1], vertex_list[0]);
00155   if (edgeTable[cubeindex] & 2)
00156     interpolateEdge (iso_level,p[1],p[2],leaf_node.vertex[1],leaf_node.vertex[2], vertex_list[1]);
00157   if (edgeTable[cubeindex] & 4)
00158     interpolateEdge (iso_level,p[2],p[3],leaf_node.vertex[2],leaf_node.vertex[3], vertex_list[2]);
00159   if (edgeTable[cubeindex] & 8)
00160     interpolateEdge (iso_level,p[3],p[0],leaf_node.vertex[3],leaf_node.vertex[0], vertex_list[3]);
00161   if (edgeTable[cubeindex] & 16)
00162     interpolateEdge (iso_level,p[4],p[5],leaf_node.vertex[4],leaf_node.vertex[5], vertex_list[4]);
00163   if (edgeTable[cubeindex] & 32)
00164     interpolateEdge (iso_level,p[5],p[6],leaf_node.vertex[5],leaf_node.vertex[6], vertex_list[5]);
00165   if (edgeTable[cubeindex] & 64)
00166     interpolateEdge (iso_level,p[6],p[7],leaf_node.vertex[6],leaf_node.vertex[7], vertex_list[6]);
00167   if (edgeTable[cubeindex] & 128)
00168     interpolateEdge (iso_level,p[7],p[4],leaf_node.vertex[7],leaf_node.vertex[4], vertex_list[7]);
00169   if (edgeTable[cubeindex] & 256)
00170     interpolateEdge (iso_level,p[0],p[4],leaf_node.vertex[0],leaf_node.vertex[4], vertex_list[8]);
00171   if (edgeTable[cubeindex] & 512)
00172     interpolateEdge (iso_level,p[1],p[5],leaf_node.vertex[1],leaf_node.vertex[5], vertex_list[9]);
00173   if (edgeTable[cubeindex] & 1024)
00174     interpolateEdge (iso_level,p[2],p[6],leaf_node.vertex[2],leaf_node.vertex[6], vertex_list[10]);
00175   if (edgeTable[cubeindex] & 2048)
00176     interpolateEdge (iso_level,p[3],p[7],leaf_node.vertex[3],leaf_node.vertex[7], vertex_list[11]);
00177 
00178   // Create the triangle
00179   for (int i = 0; triTable[cubeindex][i] != -1; i+=3)
00180   {
00181     PointNT p1,p2,p3;
00182     p1.x = vertex_list[triTable[cubeindex][i  ]][0];
00183     p1.y = vertex_list[triTable[cubeindex][i  ]][1];
00184     p1.z = vertex_list[triTable[cubeindex][i  ]][2];
00185     cloud.push_back (p1);
00186     p2.x = vertex_list[triTable[cubeindex][i+1]][0];
00187     p2.y = vertex_list[triTable[cubeindex][i+1]][1];
00188     p2.z = vertex_list[triTable[cubeindex][i+1]][2];
00189     cloud.push_back (p2);
00190     p3.x = vertex_list[triTable[cubeindex][i+2]][0];
00191     p3.y = vertex_list[triTable[cubeindex][i+2]][1];
00192     p3.z = vertex_list[triTable[cubeindex][i+2]][2];
00193     cloud.push_back (p3);
00194   }
00195 }
00196 
00198 template <typename PointNT> void
00199 pcl::MarchingCubes<PointNT>::getNeighborList1D (Leaf leaf,
00200                                                 Eigen::Vector3i &index3d,
00201                                                 HashMap &neighbor_list)
00202 {
00203   for (int x = -1; x < 2; ++x)
00204   {
00205     for (int y = -1; y < 2; ++y)
00206     {
00207       for (int z = -1; z < 2; ++z)
00208       {
00209         if (x == 0 && y == 0 && z == 0)
00210           continue;
00211 
00212         if (index3d[0] == 0 && x == -1)
00213           continue;
00214         if (index3d[1] == 0 && y == -1)
00215           continue;
00216         if (index3d[2] == 0 && z == -1)
00217           continue;
00218 
00219         Eigen::Vector3i neighbor_index;
00220         neighbor_index[0] = index3d[0] + x;
00221         neighbor_index[1] = index3d[1] + y;
00222         neighbor_index[2] = index3d[2] + z;
00223         Leaf neighbor_leaf;
00224 
00225         if ((x == 0 || x == 1) &&
00226             (y == 0 || y == 1) &&
00227             (z == 0 || z == 1))
00228           neighbor_leaf.vertex[0] = leaf.vertex[0];
00229 
00230         if ((x == 0 || x == -1) &&
00231             (y == 0 || y == 1) &&
00232             (z == 0 || z == 1))
00233           neighbor_leaf.vertex[1] = leaf.vertex[1];
00234 
00235         if ((x == 0 || x == -1) &&
00236             (y == 0 || y == 1) &&
00237             (z == 0 || z == -1))
00238           neighbor_leaf.vertex[2] = leaf.vertex[2];
00239 
00240         if ((x == 0 || x == 1) &&
00241             (y == 0 || y == 1) &&
00242             (z == 0 || z == -1))
00243           neighbor_leaf.vertex[3] = leaf.vertex[3];
00244 
00245         if ((x == 0 || x == 1) &&
00246             (y == 0 || y == -1) &&
00247             (z == 0 || z == 1))
00248           neighbor_leaf.vertex[4] = leaf.vertex[4];
00249 
00250         if ((x == 0 || x == -1) &&
00251             (y == 0 || y == -1) &&
00252             (z == 0 || z == 1))
00253           neighbor_leaf.vertex[5] = leaf.vertex[5];
00254 
00255         if ((x == 0 || x == -1) &&
00256             (y == 0 || y == -1) &&
00257             (z == 0 || z == -1))
00258           neighbor_leaf.vertex[6] = leaf.vertex[6];
00259 
00260         if ((x == 0 || x == 1) &&
00261             (y == 0 || y == -1) &&
00262             (z == 0 || z == -1))
00263           neighbor_leaf.vertex[7] = leaf.vertex[7];
00264 
00265         neighbor_list[getIndexIn1D (neighbor_index)] = neighbor_leaf;
00266       }
00267     }
00268   }
00269 }
00270 
00272 template <typename PointNT> void
00273 pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PolygonMesh &output)
00274 {
00275   if (!(iso_level_ > 0 && iso_level_ < 1))
00276   {
00277     PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", getClassName ().c_str (), iso_level_);
00278     output.cloud.width = output.cloud.height = 0;
00279     output.cloud.data.clear ();
00280     output.polygons.clear ();
00281     return;
00282   }
00283   if (leaf_size_ <=0)
00284   {
00285     PCL_ERROR ("[pcl::%s::performReconstruction] Invalid leaf size %f! Please use a number greater than 0.\n", getClassName ().c_str (), leaf_size_);
00286     output.cloud.width = output.cloud.height = 0;
00287     output.cloud.data.clear ();
00288     output.polygons.clear ();
00289     return;
00290     
00291   }
00292 
00293   getBoundingBox ();
00294 
00295   // transform the point cloud into a voxel grid
00296   // this needs to be implemented in a child class
00297   voxelizeData ();
00298 
00299   // run the actual marching cubes algorithm, store it into a point cloud,
00300   // and copy the point cloud + connectivity into output
00301   pcl::PointCloud<PointNT> cloud;
00302   BOOST_FOREACH (typename HashMap::value_type entry, cell_hash_map_)
00303   {
00304     Eigen::Vector3i leaf_index;
00305     getIndexIn3D (entry.first, leaf_index);
00306     createSurface (entry.second, leaf_index, cloud, iso_level_);
00307   }
00308   pcl::toROSMsg (cloud, output.cloud);
00309   output.polygons.resize (cloud.size () / 3);
00310 
00311   for (size_t i = 0; i < output.polygons.size (); ++i)
00312   {
00313     pcl::Vertices v;
00314     v.vertices.resize (3);
00315     for (int j = 0; j < 3; ++j)
00316       v.vertices[j] = i*3+j;
00317      output.polygons[i] = v;
00318   }
00319 }
00320 
00322 template <typename PointNT> void
00323 pcl::MarchingCubes<PointNT>::performReconstruction (pcl::PointCloud<PointNT> &points,
00324                                                     std::vector<pcl::Vertices> &polygons)
00325 {
00327   if (!(iso_level_ > 0 && iso_level_ < 1))
00328   {
00329     PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", getClassName ().c_str (), iso_level_);
00330     points.width = points.height = 0;
00331     points.clear ();
00332     polygons.clear ();
00333     return;
00334   }
00335   if (leaf_size_ <=0)
00336   {
00337     PCL_ERROR ("[pcl::%s::performReconstruction] Invalid leaf size %f! Please use a number greater than 0.\n", getClassName ().c_str (), leaf_size_);
00338     points.width = points.height = 0;
00339     points.clear ();
00340     polygons.clear ();
00341     return;
00342 
00343   }
00344 
00345   getBoundingBox ();
00346 
00347   // transform the point cloud into a voxel grid
00348   // this needs to be implemented in a child class
00349   voxelizeData ();
00350 
00351   // run the actual marching cubes algorithm, store it into a point cloud,
00352   // and copy the point cloud + connectivity into output
00353   BOOST_FOREACH (typename HashMap::value_type entry, cell_hash_map_)
00354   {
00355     Eigen::Vector3i leaf_index;
00356     getIndexIn3D (entry.first, leaf_index);
00357     createSurface (entry.second, leaf_index, points, iso_level_);
00358   }
00359   polygons.resize (points.size () / 3);
00360 
00361   for (size_t i = 0; i < polygons.size (); ++i)
00362   {
00363     pcl::Vertices v;
00364     v.vertices.resize (3);
00365     for (int j = 0; j < 3; ++j)
00366       v.vertices[j] = i*3+j;
00367      polygons[i] = v;
00368   }
00369 }
00370 
00371 
00372 
00373 #define PCL_INSTANTIATE_MarchingCubes(T) template class PCL_EXPORTS pcl::MarchingCubes<T>;
00374 
00375 #endif    // PCL_SURFACE_IMPL_MARCHING_CUBES_H_
00376