Point Cloud Library (PCL) 1.12.1
Loading...
Searching...
No Matches
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
44//////////////////////////////////////////////////////////////////////////////////////////////
45template <typename PointNT>
49
50//////////////////////////////////////////////////////////////////////////////////////////////
51template <typename PointNT> void
53{
54 PointNT max_pt, min_pt;
55 pcl::getMinMax3D (*input_, min_pt, max_pt);
56
57 lower_boundary_ = min_pt.getArray3fMap ();
58 upper_boundary_ = max_pt.getArray3fMap ();
59
60 const Eigen::Array3f size3_extend = 0.5f * percentage_extend_grid_
62
63 lower_boundary_ -= size3_extend;
64 upper_boundary_ += size3_extend;
65}
66
67
68//////////////////////////////////////////////////////////////////////////////////////////////
69template <typename PointNT> void
71 Eigen::Vector3f &p2,
72 float val_p1,
73 float val_p2,
74 Eigen::Vector3f &output)
75{
76 const float mu = (iso_level_ - val_p1) / (val_p2 - val_p1);
77 output = p1 + mu * (p2 - p1);
78}
79
80
81//////////////////////////////////////////////////////////////////////////////////////////////
82template <typename PointNT> void
83pcl::MarchingCubes<PointNT>::createSurface (const std::vector<float> &leaf_node,
84 const Eigen::Vector3i &index_3d,
86{
87 int cubeindex = 0;
88 if (leaf_node[0] < iso_level_) cubeindex |= 1;
89 if (leaf_node[1] < iso_level_) cubeindex |= 2;
90 if (leaf_node[2] < iso_level_) cubeindex |= 4;
91 if (leaf_node[3] < iso_level_) cubeindex |= 8;
92 if (leaf_node[4] < iso_level_) cubeindex |= 16;
93 if (leaf_node[5] < iso_level_) cubeindex |= 32;
94 if (leaf_node[6] < iso_level_) cubeindex |= 64;
95 if (leaf_node[7] < iso_level_) cubeindex |= 128;
96
97 // Cube is entirely in/out of the surface
98 if (edgeTable[cubeindex] == 0)
99 return;
100
101 const Eigen::Vector3f center = lower_boundary_
102 + size_voxel_ * index_3d.cast<float> ().array ();
103
104 std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > p;
105 p.resize (8);
106 for (int i = 0; i < 8; ++i)
107 {
108 Eigen::Vector3f point = center;
109 if (i & 0x4)
110 point[1] = static_cast<float> (center[1] + size_voxel_[1]);
111
112 if (i & 0x2)
113 point[2] = static_cast<float> (center[2] + size_voxel_[2]);
114
115 if ((i & 0x1) ^ ((i >> 1) & 0x1))
116 point[0] = static_cast<float> (center[0] + size_voxel_[0]);
117
118 p[i] = point;
119 }
120
121 // Find the vertices where the surface intersects the cube
122 std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > vertex_list;
123 vertex_list.resize (12);
124 if (edgeTable[cubeindex] & 1)
125 interpolateEdge (p[0], p[1], leaf_node[0], leaf_node[1], vertex_list[0]);
126 if (edgeTable[cubeindex] & 2)
127 interpolateEdge (p[1], p[2], leaf_node[1], leaf_node[2], vertex_list[1]);
128 if (edgeTable[cubeindex] & 4)
129 interpolateEdge (p[2], p[3], leaf_node[2], leaf_node[3], vertex_list[2]);
130 if (edgeTable[cubeindex] & 8)
131 interpolateEdge (p[3], p[0], leaf_node[3], leaf_node[0], vertex_list[3]);
132 if (edgeTable[cubeindex] & 16)
133 interpolateEdge (p[4], p[5], leaf_node[4], leaf_node[5], vertex_list[4]);
134 if (edgeTable[cubeindex] & 32)
135 interpolateEdge (p[5], p[6], leaf_node[5], leaf_node[6], vertex_list[5]);
136 if (edgeTable[cubeindex] & 64)
137 interpolateEdge (p[6], p[7], leaf_node[6], leaf_node[7], vertex_list[6]);
138 if (edgeTable[cubeindex] & 128)
139 interpolateEdge (p[7], p[4], leaf_node[7], leaf_node[4], vertex_list[7]);
140 if (edgeTable[cubeindex] & 256)
141 interpolateEdge (p[0], p[4], leaf_node[0], leaf_node[4], vertex_list[8]);
142 if (edgeTable[cubeindex] & 512)
143 interpolateEdge (p[1], p[5], leaf_node[1], leaf_node[5], vertex_list[9]);
144 if (edgeTable[cubeindex] & 1024)
145 interpolateEdge (p[2], p[6], leaf_node[2], leaf_node[6], vertex_list[10]);
146 if (edgeTable[cubeindex] & 2048)
147 interpolateEdge (p[3], p[7], leaf_node[3], leaf_node[7], vertex_list[11]);
148
149 // Create the triangle
150 for (int i = 0; triTable[cubeindex][i] != -1; i += 3)
151 {
152 PointNT p1, p2, p3;
153 p1.getVector3fMap () = vertex_list[triTable[cubeindex][i]];
154 cloud.push_back (p1);
155 p2.getVector3fMap () = vertex_list[triTable[cubeindex][i+1]];
156 cloud.push_back (p2);
157 p3.getVector3fMap () = vertex_list[triTable[cubeindex][i+2]];
158 cloud.push_back (p3);
159 }
160}
161
162
163//////////////////////////////////////////////////////////////////////////////////////////////
164template <typename PointNT> void
166 Eigen::Vector3i &index3d)
167{
168 leaf.resize (8);
169
170 leaf[0] = getGridValue (index3d);
171 leaf[1] = getGridValue (index3d + Eigen::Vector3i (1, 0, 0));
172 leaf[2] = getGridValue (index3d + Eigen::Vector3i (1, 0, 1));
173 leaf[3] = getGridValue (index3d + Eigen::Vector3i (0, 0, 1));
174 leaf[4] = getGridValue (index3d + Eigen::Vector3i (0, 1, 0));
175 leaf[5] = getGridValue (index3d + Eigen::Vector3i (1, 1, 0));
176 leaf[6] = getGridValue (index3d + Eigen::Vector3i (1, 1, 1));
177 leaf[7] = getGridValue (index3d + Eigen::Vector3i (0, 1, 1));
178
179 for (int i = 0; i < 8; ++i)
180 {
181 if (std::isnan (leaf[i]))
182 {
183 leaf.clear ();
184 break;
185 }
186 }
187}
188
189
190//////////////////////////////////////////////////////////////////////////////////////////////
191template <typename PointNT> float
193{
194 /// TODO what to return?
195 if (pos[0] < 0 || pos[0] >= res_x_)
196 return -1.0f;
197 if (pos[1] < 0 || pos[1] >= res_y_)
198 return -1.0f;
199 if (pos[2] < 0 || pos[2] >= res_z_)
200 return -1.0f;
201
202 return grid_[pos[0]*res_y_*res_z_ + pos[1]*res_z_ + pos[2]];
203}
204
205
206//////////////////////////////////////////////////////////////////////////////////////////////
207template <typename PointNT> void
216
217
218//////////////////////////////////////////////////////////////////////////////////////////////
219template <typename PointNT> void
221 std::vector<pcl::Vertices> &polygons)
222{
223 if (!(iso_level_ >= 0 && iso_level_ < 1))
224 {
225 PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n",
226 getClassName ().c_str (), iso_level_);
227 points.clear ();
228 polygons.clear ();
229 return;
230 }
231
232 // the point cloud really generated from Marching Cubes, prev intermediate_cloud_
233 pcl::PointCloud<PointNT> intermediate_cloud;
234
235 // Create grid
236 grid_ = std::vector<float> (res_x_*res_y_*res_z_, NAN);
237
238 // Compute bounding box and voxel size
241 * Eigen::Array3f (res_x_, res_y_, res_z_).inverse ();
242
243 // Transform the point cloud into a voxel grid
244 // This needs to be implemented in a child class
245 voxelizeData ();
246
247 // preallocate memory assuming a hull. suppose 6 point per voxel
248 double size_reserve = std::min((double) intermediate_cloud.points.max_size (),
249 2.0 * 6.0 * (double) (res_y_*res_z_ + res_x_*res_z_ + res_x_*res_y_));
250 intermediate_cloud.reserve ((std::size_t) size_reserve);
251
252 for (int x = 1; x < res_x_-1; ++x)
253 for (int y = 1; y < res_y_-1; ++y)
254 for (int z = 1; z < res_z_-1; ++z)
255 {
256 Eigen::Vector3i index_3d (x, y, z);
257 std::vector<float> leaf_node;
258 getNeighborList1D (leaf_node, index_3d);
259 if (!leaf_node.empty ())
260 createSurface (leaf_node, index_3d, intermediate_cloud);
261 }
262
263 points.swap (intermediate_cloud);
264
265 polygons.resize (points.size () / 3);
266 for (std::size_t i = 0; i < polygons.size (); ++i)
267 {
269 v.vertices.resize (3);
270 for (int j = 0; j < 3; ++j)
271 v.vertices[j] = static_cast<int> (i) * 3 + j;
272 polygons[i] = v;
273 }
274}
275
276#define PCL_INSTANTIATE_MarchingCubes(T) template class PCL_EXPORTS pcl::MarchingCubes<T>;
277
278#endif // PCL_SURFACE_IMPL_MARCHING_CUBES_H_
279
std::vector< float > grid_
The data structure storing the 3D grid.
int res_x_
The grid resolution.
Eigen::Array3f upper_boundary_
bounding box
virtual void voxelizeData()=0
Convert the point cloud into voxel data.
std::string getClassName() const override
Class get name method.
float iso_level_
The iso level to be extracted.
void performReconstruction(pcl::PolygonMesh &output) override
Extract the surface.
virtual float getGridValue(Eigen::Vector3i pos)
Method that returns the scalar value at the given grid position.
Eigen::Array3f size_voxel_
size of voxels
float percentage_extend_grid_
Parameter that defines how much free space should be left inside the grid between the bounding box of...
void getBoundingBox()
Get the bounding box for the input data points.
void interpolateEdge(Eigen::Vector3f &p1, Eigen::Vector3f &p2, float val_p1, float val_p2, Eigen::Vector3f &output)
Interpolate along the voxel edge.
void createSurface(const std::vector< float > &leaf_node, const Eigen::Vector3i &index_3d, pcl::PointCloud< PointNT > &cloud)
Calculate out the corresponding polygons in the leaf node.
Eigen::Array3f lower_boundary_
void getNeighborList1D(std::vector< float > &leaf, Eigen::Vector3i &index3d)
Method that returns the scalar values of the neighbors of a given 3D position in the grid.
~MarchingCubes()
Destructor.
PointCloudConstPtr input_
Definition pcl_base.h:147
PointCloud represents the base class in PCL for storing collections of 3D points.
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
void clear()
Removes all points in a cloud and sets the width and height to 0.
std::size_t size() const
void reserve(std::size_t n)
void swap(PointCloud< PointT > &rhs)
Swap a point cloud with another cloud.
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Define standard C methods and C++ classes that are common to all methods.
void getMinMax3D(const pcl::PointCloud< PointT > &cloud, PointT &min_pt, PointT &max_pt)
Get the minimum and maximum values on each of the 3 (x-y-z) dimensions in a given pointcloud.
Definition common.hpp:295
void toPCLPointCloud2(const pcl::PointCloud< PointT > &cloud, pcl::PCLPointCloud2 &msg)
Convert a pcl::PointCloud<T> object to a PCLPointCloud2 binary data blob.
const unsigned int edgeTable[256]
const int triTable[256][16]
std::vector< ::pcl::Vertices > polygons
Definition PolygonMesh.h:23
::pcl::PCLPointCloud2 cloud
Definition PolygonMesh.h:21
Describes a set of vertices in a polygon mesh, by basically storing an array of indices.
Definition Vertices.h:15
Indices vertices
Definition Vertices.h:19