Point Cloud Library (PCL)  1.7.0
marching_cubes.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2010, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35 
36 #ifndef PCL_SURFACE_IMPL_MARCHING_CUBES_H_
37 #define PCL_SURFACE_IMPL_MARCHING_CUBES_H_
38 
39 #include <pcl/surface/marching_cubes.h>
40 #include <pcl/common/common.h>
41 #include <pcl/common/vector_average.h>
42 #include <pcl/Vertices.h>
43 #include <pcl/kdtree/kdtree_flann.h>
44 
45 //////////////////////////////////////////////////////////////////////////////////////////////
46 template <typename PointNT>
48 : min_p_ (), max_p_ (), percentage_extend_grid_ (), iso_level_ ()
49 {
50 }
51 
52 //////////////////////////////////////////////////////////////////////////////////////////////
53 template <typename PointNT>
55 {
56 }
57 
58 //////////////////////////////////////////////////////////////////////////////////////////////
59 template <typename PointNT> void
61 {
62  pcl::getMinMax3D (*input_, min_p_, max_p_);
63 
64  min_p_ -= (max_p_ - min_p_) * percentage_extend_grid_/2;
65  max_p_ += (max_p_ - min_p_) * percentage_extend_grid_/2;
66 
67  Eigen::Vector4f bounding_box_size = max_p_ - min_p_;
68 
69  bounding_box_size = max_p_ - min_p_;
70  PCL_DEBUG ("[pcl::MarchingCubesHoppe::getBoundingBox] Size of Bounding Box is [%f, %f, %f]\n",
71  bounding_box_size.x (), bounding_box_size.y (), bounding_box_size.z ());
72  double max_size =
73  (std::max) ((std::max)(bounding_box_size.x (), bounding_box_size.y ()),
74  bounding_box_size.z ());
75  (void)max_size;
76  // ????
77  // data_size_ = static_cast<uint64_t> (max_size / leaf_size_);
78  PCL_DEBUG ("[pcl::MarchingCubesHoppe::getBoundingBox] Lower left point is [%f, %f, %f]\n",
79  min_p_.x (), min_p_.y (), min_p_.z ());
80  PCL_DEBUG ("[pcl::MarchingCubesHoppe::getBoundingBox] Upper left point is [%f, %f, %f]\n",
81  max_p_.x (), max_p_.y (), max_p_.z ());
82 }
83 
84 
85 //////////////////////////////////////////////////////////////////////////////////////////////
86 template <typename PointNT> void
88  Eigen::Vector3f &p2,
89  float val_p1,
90  float val_p2,
91  Eigen::Vector3f &output)
92 {
93  float mu = (iso_level_ - val_p1) / (val_p2-val_p1);
94  output = p1 + mu * (p2 - p1);
95 }
96 
97 
98 //////////////////////////////////////////////////////////////////////////////////////////////
99 template <typename PointNT> void
100 pcl::MarchingCubes<PointNT>::createSurface (std::vector<float> &leaf_node,
101  Eigen::Vector3i &index_3d,
103 {
104  int cubeindex = 0;
105  Eigen::Vector3f vertex_list[12];
106  if (leaf_node[0] < iso_level_) cubeindex |= 1;
107  if (leaf_node[1] < iso_level_) cubeindex |= 2;
108  if (leaf_node[2] < iso_level_) cubeindex |= 4;
109  if (leaf_node[3] < iso_level_) cubeindex |= 8;
110  if (leaf_node[4] < iso_level_) cubeindex |= 16;
111  if (leaf_node[5] < iso_level_) cubeindex |= 32;
112  if (leaf_node[6] < iso_level_) cubeindex |= 64;
113  if (leaf_node[7] < iso_level_) cubeindex |= 128;
114 
115  // Cube is entirely in/out of the surface
116  if (edgeTable[cubeindex] == 0)
117  return;
118 
119  //Eigen::Vector4f index_3df (index_3d[0], index_3d[1], index_3d[2], 0.0f);
120  Eigen::Vector3f center;// TODO coeff wise product = min_p_ + Eigen::Vector4f (1.0f/res_x_, 1.0f/res_y_, 1.0f/res_z_) * index_3df * (max_p_ - min_p_);
121  center[0] = min_p_[0] + (max_p_[0] - min_p_[0]) * float (index_3d[0]) / float (res_x_);
122  center[1] = min_p_[1] + (max_p_[1] - min_p_[1]) * float (index_3d[1]) / float (res_y_);
123  center[2] = min_p_[2] + (max_p_[2] - min_p_[2]) * float (index_3d[2]) / float (res_z_);
124 
125  std::vector<Eigen::Vector3f> p;
126  p.resize (8);
127  for (int i = 0; i < 8; ++i)
128  {
129  Eigen::Vector3f point = center;
130  if(i & 0x4)
131  point[1] = static_cast<float> (center[1] + (max_p_[1] - min_p_[1]) / float (res_y_));
132 
133  if(i & 0x2)
134  point[2] = static_cast<float> (center[2] + (max_p_[2] - min_p_[2]) / float (res_z_));
135 
136  if((i & 0x1) ^ ((i >> 1) & 0x1))
137  point[0] = static_cast<float> (center[0] + (max_p_[0] - min_p_[0]) / float (res_x_));
138 
139  p[i] = point;
140  }
141 
142 
143  // Find the vertices where the surface intersects the cube
144  if (edgeTable[cubeindex] & 1)
145  interpolateEdge (p[0], p[1], leaf_node[0], leaf_node[1], vertex_list[0]);
146  if (edgeTable[cubeindex] & 2)
147  interpolateEdge (p[1], p[2], leaf_node[1], leaf_node[2], vertex_list[1]);
148  if (edgeTable[cubeindex] & 4)
149  interpolateEdge (p[2], p[3], leaf_node[2], leaf_node[3], vertex_list[2]);
150  if (edgeTable[cubeindex] & 8)
151  interpolateEdge (p[3], p[0], leaf_node[3], leaf_node[0], vertex_list[3]);
152  if (edgeTable[cubeindex] & 16)
153  interpolateEdge (p[4], p[5], leaf_node[4], leaf_node[5], vertex_list[4]);
154  if (edgeTable[cubeindex] & 32)
155  interpolateEdge (p[5], p[6], leaf_node[5], leaf_node[6], vertex_list[5]);
156  if (edgeTable[cubeindex] & 64)
157  interpolateEdge (p[6], p[7], leaf_node[6], leaf_node[7], vertex_list[6]);
158  if (edgeTable[cubeindex] & 128)
159  interpolateEdge (p[7], p[4], leaf_node[7], leaf_node[4], vertex_list[7]);
160  if (edgeTable[cubeindex] & 256)
161  interpolateEdge (p[0], p[4], leaf_node[0], leaf_node[4], vertex_list[8]);
162  if (edgeTable[cubeindex] & 512)
163  interpolateEdge (p[1], p[5], leaf_node[1], leaf_node[5], vertex_list[9]);
164  if (edgeTable[cubeindex] & 1024)
165  interpolateEdge (p[2], p[6], leaf_node[2], leaf_node[6], vertex_list[10]);
166  if (edgeTable[cubeindex] & 2048)
167  interpolateEdge (p[3], p[7], leaf_node[3], leaf_node[7], vertex_list[11]);
168 
169  // Create the triangle
170  for (int i = 0; triTable[cubeindex][i] != -1; i+=3)
171  {
172  PointNT p1,p2,p3;
173  p1.x = vertex_list[triTable[cubeindex][i ]][0];
174  p1.y = vertex_list[triTable[cubeindex][i ]][1];
175  p1.z = vertex_list[triTable[cubeindex][i ]][2];
176  cloud.push_back (p1);
177  p2.x = vertex_list[triTable[cubeindex][i+1]][0];
178  p2.y = vertex_list[triTable[cubeindex][i+1]][1];
179  p2.z = vertex_list[triTable[cubeindex][i+1]][2];
180  cloud.push_back (p2);
181  p3.x = vertex_list[triTable[cubeindex][i+2]][0];
182  p3.y = vertex_list[triTable[cubeindex][i+2]][1];
183  p3.z = vertex_list[triTable[cubeindex][i+2]][2];
184  cloud.push_back (p3);
185  }
186 }
187 
188 
189 //////////////////////////////////////////////////////////////////////////////////////////////
190 template <typename PointNT> void
192  Eigen::Vector3i &index3d)
193 {
194  leaf = std::vector<float> (8, 0.0f);
195 
196  leaf[0] = getGridValue (index3d);
197  leaf[1] = getGridValue (index3d + Eigen::Vector3i (1, 0, 0));
198  leaf[2] = getGridValue (index3d + Eigen::Vector3i (1, 0, 1));
199  leaf[3] = getGridValue (index3d + Eigen::Vector3i (0, 0, 1));
200  leaf[4] = getGridValue (index3d + Eigen::Vector3i (0, 1, 0));
201  leaf[5] = getGridValue (index3d + Eigen::Vector3i (1, 1, 0));
202  leaf[6] = getGridValue (index3d + Eigen::Vector3i (1, 1, 1));
203  leaf[7] = getGridValue (index3d + Eigen::Vector3i (0, 1, 1));
204 }
205 
206 
207 //////////////////////////////////////////////////////////////////////////////////////////////
208 template <typename PointNT> float
210 {
211  /// TODO what to return?
212  if (pos[0] < 0 || pos[0] >= res_x_)
213  return -1.0f;
214  if (pos[1] < 0 || pos[1] >= res_y_)
215  return -1.0f;
216  if (pos[2] < 0 || pos[2] >= res_z_)
217  return -1.0f;
218 
219  return grid_[pos[0]*res_y_*res_z_ + pos[1]*res_z_ + pos[2]];
220 }
221 
222 
223 //////////////////////////////////////////////////////////////////////////////////////////////
224 template <typename PointNT> void
226 {
227  if (!(iso_level_ >= 0 && iso_level_ < 1))
228  {
229  PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", getClassName ().c_str (), iso_level_);
230  output.cloud.width = output.cloud.height = 0;
231  output.cloud.data.clear ();
232  output.polygons.clear ();
233  return;
234  }
235 
236  // Create grid
237  grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f);
238 
239  // Populate tree
240  tree_->setInputCloud (input_);
241 
242  getBoundingBox ();
243 
244  // Transform the point cloud into a voxel grid
245  // This needs to be implemented in a child class
246  voxelizeData ();
247 
248 
249 
250  // Run the actual marching cubes algorithm, store it into a point cloud,
251  // and copy the point cloud + connectivity into output
253 
254  for (int x = 1; x < res_x_-1; ++x)
255  for (int y = 1; y < res_y_-1; ++y)
256  for (int z = 1; z < res_z_-1; ++z)
257  {
258  Eigen::Vector3i index_3d (x, y, z);
259  std::vector<float> leaf_node;
260  getNeighborList1D (leaf_node, index_3d);
261  createSurface (leaf_node, index_3d, cloud);
262  }
263  pcl::toPCLPointCloud2 (cloud, output.cloud);
264 
265  output.polygons.resize (cloud.size () / 3);
266  for (size_t i = 0; i < output.polygons.size (); ++i)
267  {
268  pcl::Vertices v;
269  v.vertices.resize (3);
270  for (int j = 0; j < 3; ++j)
271  v.vertices[j] = static_cast<int> (i) * 3 + j;
272  output.polygons[i] = v;
273  }
274 }
275 
276 
277 //////////////////////////////////////////////////////////////////////////////////////////////
278 template <typename PointNT> void
280  std::vector<pcl::Vertices> &polygons)
281 {
282  if (!(iso_level_ >= 0 && iso_level_ < 1))
283  {
284  PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n", getClassName ().c_str (), iso_level_);
285  points.width = points.height = 0;
286  points.points.clear ();
287  polygons.clear ();
288  return;
289  }
290 
291  // Create grid
292  grid_ = std::vector<float> (res_x_*res_y_*res_z_, 0.0f);
293 
294  // Populate tree
295  tree_->setInputCloud (input_);
296 
297  getBoundingBox ();
298 
299  // Transform the point cloud into a voxel grid
300  // This needs to be implemented in a child class
301  voxelizeData ();
302 
303  // Run the actual marching cubes algorithm, store it into a point cloud,
304  // and copy the point cloud + connectivity into output
305  points.clear ();
306  for (int x = 1; x < res_x_-1; ++x)
307  for (int y = 1; y < res_y_-1; ++y)
308  for (int z = 1; z < res_z_-1; ++z)
309  {
310  Eigen::Vector3i index_3d (x, y, z);
311  std::vector<float> leaf_node;
312  getNeighborList1D (leaf_node, index_3d);
313  createSurface (leaf_node, index_3d, points);
314  }
315 
316  polygons.resize (points.size () / 3);
317  for (size_t i = 0; i < polygons.size (); ++i)
318  {
319  pcl::Vertices v;
320  v.vertices.resize (3);
321  for (int j = 0; j < 3; ++j)
322  v.vertices[j] = static_cast<int> (i) * 3 + j;
323  polygons[i] = v;
324  }
325 }
326 
327 
328 
329 #define PCL_INSTANTIATE_MarchingCubes(T) template class PCL_EXPORTS pcl::MarchingCubes<T>;
330 
331 #endif // PCL_SURFACE_IMPL_MARCHING_CUBES_H_
332