00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Point Cloud Library (PCL) - www.pointclouds.org 00005 * Copyright (c) 2010-2012, Willow Garage, Inc. 00006 * Copyright (c) 2012, Urban Robotics, Inc. 00007 * 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without 00011 * modification, are permitted provided that the following conditions 00012 * are met: 00013 * 00014 * * Redistributions of source code must retain the above copyright 00015 * notice, this list of conditions and the following disclaimer. 00016 * * Redistributions in binary form must reproduce the above 00017 * copyright notice, this list of conditions and the following 00018 * disclaimer in the documentation and/or other materials provided 00019 * with the distribution. 00020 * * Neither the name of Willow Garage, Inc. nor the names of its 00021 * contributors may be used to endorse or promote products derived 00022 * from this software without specific prior written permission. 00023 * 00024 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00025 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00026 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00027 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00028 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00029 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00030 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00031 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00032 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00033 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00034 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00035 * POSSIBILITY OF SUCH DAMAGE. 00036 * 00037 * $Id$ 00038 */ 00039 00040 #ifndef PCL_OUTOFCORE_OCTREE_BASE_IMPL_H_ 00041 #define PCL_OUTOFCORE_OCTREE_BASE_IMPL_H_ 00042 00043 00044 #include <pcl/outofcore/octree_base.h> 00045 00046 // JSON 00047 #include <pcl/outofcore/cJSON.h> 00048 00049 #include <pcl/filters/random_sample.h> 00050 #include <pcl/filters/extract_indices.h> 00051 00052 // C++ 00053 #include <iostream> 00054 #include <fstream> 00055 #include <sstream> 00056 #include <string> 00057 #include <exception> 00058 00059 namespace pcl 00060 { 00061 namespace outofcore 00062 { 00063 00064 //////////////////////////////////////////////////////////////////////////////// 00065 //Static constants 00066 //////////////////////////////////////////////////////////////////////////////// 00067 00068 template<typename ContainerT, typename PointT> 00069 const std::string OutofcoreOctreeBase<ContainerT, PointT>::TREE_EXTENSION_ = ".octree"; 00070 00071 template<typename ContainerT, typename PointT> 00072 const int OutofcoreOctreeBase<ContainerT, PointT>::OUTOFCORE_VERSION_ = static_cast<int>(3); 00073 00074 //////////////////////////////////////////////////////////////////////////////// 00075 00076 template<typename ContainerT, typename PointT> 00077 OutofcoreOctreeBase<ContainerT, PointT>::OutofcoreOctreeBase (const boost::filesystem::path& root_name, const bool load_all) 00078 : root_node_ () 00079 , read_write_mutex_ () 00080 , metadata_ (new OutofcoreOctreeBaseMetadata ()) 00081 , sample_percent_ (0.125) 00082 , lod_filter_ptr_ (new pcl::RandomSample<pcl::PCLPointCloud2> ()) 00083 { 00084 //validate the root filename 00085 if (!this->checkExtension (root_name)) 00086 { 00087 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBase] Bad extension. Outofcore Octrees must have a root node ending in .oct_idx\n"); 00088 } 00089 00090 // Create root_node_node 00091 root_node_ = new OutofcoreOctreeBaseNode<ContainerT, PointT> (root_name, NULL, load_all); 00092 // Set root_node_nodes tree to the newly created tree 00093 root_node_->m_tree_ = this; 00094 00095 // Set the path to the outofcore octree metadata (unique to the root folder) ending in .octree 00096 boost::filesystem::path treepath = root_name.parent_path () / (boost::filesystem::basename (root_name) + TREE_EXTENSION_); 00097 00098 //Load the JSON metadata 00099 metadata_->loadMetadataFromDisk (treepath); 00100 } 00101 00102 //////////////////////////////////////////////////////////////////////////////// 00103 00104 template<typename ContainerT, typename PointT> 00105 OutofcoreOctreeBase<ContainerT, PointT>::OutofcoreOctreeBase (const Eigen::Vector3d& min, const Eigen::Vector3d& max, const double resolution_arg, const boost::filesystem::path& root_node_name, const std::string& coord_sys) 00106 : root_node_() 00107 , read_write_mutex_ () 00108 , metadata_ (new OutofcoreOctreeBaseMetadata ()) 00109 , sample_percent_ (0.125) 00110 , lod_filter_ptr_ (new pcl::RandomSample<pcl::PCLPointCloud2> ()) 00111 { 00112 //Enlarge the bounding box to a cube so our voxels will be cubes 00113 Eigen::Vector3d tmp_min = min; 00114 Eigen::Vector3d tmp_max = max; 00115 this->enlargeToCube (tmp_min, tmp_max); 00116 00117 //Compute the depth of the tree given the resolution 00118 boost::uint64_t depth = this->calculateDepth (tmp_min, tmp_max, resolution_arg); 00119 00120 //Create a new outofcore tree 00121 this->init (depth, tmp_min, tmp_max, root_node_name, coord_sys); 00122 } 00123 00124 //////////////////////////////////////////////////////////////////////////////// 00125 00126 template<typename ContainerT, typename PointT> 00127 OutofcoreOctreeBase<ContainerT, PointT>::OutofcoreOctreeBase (const boost::uint64_t max_depth, const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::filesystem::path& root_node_name, const std::string& coord_sys) 00128 : root_node_() 00129 , read_write_mutex_ () 00130 , metadata_ (new OutofcoreOctreeBaseMetadata ()) 00131 , sample_percent_ (0.125) 00132 , lod_filter_ptr_ (new pcl::RandomSample<pcl::PCLPointCloud2> ()) 00133 { 00134 //Create a new outofcore tree 00135 this->init (max_depth, min, max, root_node_name, coord_sys); 00136 } 00137 00138 //////////////////////////////////////////////////////////////////////////////// 00139 template<typename ContainerT, typename PointT> void 00140 OutofcoreOctreeBase<ContainerT, PointT>::init (const uint64_t& depth, const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::filesystem::path& root_name, const std::string& coord_sys) 00141 { 00142 //Validate the extension of the pathname 00143 if (!this->checkExtension (root_name)) 00144 { 00145 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBase] Bad extension. Outofcore Octrees must have a root node ending in .oct_idx\n"); 00146 } 00147 00148 //Check to make sure that we are not overwriting existing data 00149 if (boost::filesystem::exists (root_name.parent_path ())) 00150 { 00151 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBase] A dir named %s already exists. Overwriting an existing tree is not supported.\n", 00152 #if ! defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION < 3 00153 root_name.parent_path ().filename().c_str () ); 00154 #else 00155 root_name.parent_path ().c_str () ); 00156 #endif 00157 PCL_THROW_EXCEPTION ( PCLException, "[pcl::outofcore::OutofcoreOctreeBase] Directory exists; Overwriting an existing tree is not supported\n"); 00158 } 00159 00160 // Get fullpath and recreate directories 00161 boost::filesystem::path dir = root_name.parent_path (); 00162 00163 if (!boost::filesystem::exists (dir)) 00164 { 00165 boost::filesystem::create_directory (dir); 00166 } 00167 00168 Eigen::Vector3d tmp_min = min; 00169 Eigen::Vector3d tmp_max = max; 00170 this->enlargeToCube (tmp_min, tmp_max); 00171 00172 // Create root node 00173 root_node_= new OutofcoreOctreeBaseNode<ContainerT, PointT> (tmp_min, tmp_max, this, root_name); 00174 root_node_->m_tree_ = this; 00175 00176 // Set root nodes file path 00177 boost::filesystem::path treepath = dir / (boost::filesystem::basename (root_name) + TREE_EXTENSION_); 00178 00179 //fill the fields of the metadata 00180 metadata_->setCoordinateSystem (coord_sys); 00181 metadata_->setDepth (depth); 00182 metadata_->setLODPoints (depth+1); 00183 metadata_->setMetadataFilename (treepath); 00184 metadata_->setOutofcoreVersion (OUTOFCORE_VERSION_); 00185 //metadata_->setPointType ( <point type string here> ); 00186 00187 //save to disk 00188 metadata_->serializeMetadataToDisk (); 00189 } 00190 00191 00192 //////////////////////////////////////////////////////////////////////////////// 00193 template<typename ContainerT, typename PointT> 00194 OutofcoreOctreeBase<ContainerT, PointT>::~OutofcoreOctreeBase () 00195 { 00196 root_node_->flushToDiskRecursive (); 00197 00198 saveToFile (); 00199 delete (root_node_); 00200 } 00201 00202 //////////////////////////////////////////////////////////////////////////////// 00203 00204 template<typename ContainerT, typename PointT> void 00205 OutofcoreOctreeBase<ContainerT, PointT>::saveToFile () 00206 { 00207 this->metadata_->serializeMetadataToDisk (); 00208 } 00209 00210 //////////////////////////////////////////////////////////////////////////////// 00211 00212 template<typename ContainerT, typename PointT> boost::uint64_t 00213 OutofcoreOctreeBase<ContainerT, PointT>::addDataToLeaf (const AlignedPointTVector& p) 00214 { 00215 boost::unique_lock < boost::shared_mutex > lock (read_write_mutex_); 00216 00217 const bool _FORCE_BB_CHECK = true; 00218 00219 uint64_t pt_added = root_node_->addDataToLeaf (p, _FORCE_BB_CHECK); 00220 00221 assert (p.size () == pt_added); 00222 00223 return (pt_added); 00224 } 00225 00226 //////////////////////////////////////////////////////////////////////////////// 00227 00228 template<typename ContainerT, typename PointT> boost::uint64_t 00229 OutofcoreOctreeBase<ContainerT, PointT>::addPointCloud (PointCloudConstPtr point_cloud) 00230 { 00231 return (addDataToLeaf (point_cloud->points)); 00232 } 00233 00234 //////////////////////////////////////////////////////////////////////////////// 00235 00236 template<typename ContainerT, typename PointT> boost::uint64_t 00237 OutofcoreOctreeBase<ContainerT, PointT>::addPointCloud (pcl::PCLPointCloud2::Ptr &input_cloud, const bool skip_bb_check) 00238 { 00239 uint64_t pt_added = this->root_node_->addPointCloud (input_cloud, skip_bb_check) ; 00240 // assert (input_cloud->width*input_cloud->height == pt_added); 00241 return (pt_added); 00242 } 00243 00244 00245 //////////////////////////////////////////////////////////////////////////////// 00246 00247 template<typename ContainerT, typename PointT> boost::uint64_t 00248 OutofcoreOctreeBase<ContainerT, PointT>::addPointCloud_and_genLOD (PointCloudConstPtr point_cloud) 00249 { 00250 // Lock the tree while writing 00251 boost::unique_lock < boost::shared_mutex > lock (read_write_mutex_); 00252 boost::uint64_t pt_added = root_node_->addDataToLeaf_and_genLOD (point_cloud->points, false); 00253 return (pt_added); 00254 } 00255 00256 //////////////////////////////////////////////////////////////////////////////// 00257 00258 template<typename ContainerT, typename PointT> boost::uint64_t 00259 OutofcoreOctreeBase<ContainerT, PointT>::addPointCloud_and_genLOD (pcl::PCLPointCloud2::Ptr &input_cloud) 00260 { 00261 // Lock the tree while writing 00262 boost::unique_lock < boost::shared_mutex > lock (read_write_mutex_); 00263 boost::uint64_t pt_added = root_node_->addPointCloud_and_genLOD (input_cloud); 00264 00265 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBase::%s] Points added %lu, points in input cloud, %lu\n",__FUNCTION__, pt_added, input_cloud->width*input_cloud->height ); 00266 00267 assert ( input_cloud->width*input_cloud->height == pt_added ); 00268 00269 return (pt_added); 00270 } 00271 00272 //////////////////////////////////////////////////////////////////////////////// 00273 00274 template<typename ContainerT, typename PointT> boost::uint64_t 00275 OutofcoreOctreeBase<ContainerT, PointT>::addDataToLeaf_and_genLOD (AlignedPointTVector& src) 00276 { 00277 // Lock the tree while writing 00278 boost::unique_lock < boost::shared_mutex > lock (read_write_mutex_); 00279 boost::uint64_t pt_added = root_node_->addDataToLeaf_and_genLOD (src, false); 00280 return (pt_added); 00281 } 00282 00283 //////////////////////////////////////////////////////////////////////////////// 00284 00285 template<typename Container, typename PointT> void 00286 OutofcoreOctreeBase<Container, PointT>::queryFrustum (const double planes[24], std::list<std::string>& file_names) const 00287 { 00288 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00289 root_node_->queryFrustum (planes, file_names, this->getTreeDepth()); 00290 } 00291 00292 //////////////////////////////////////////////////////////////////////////////// 00293 00294 template<typename Container, typename PointT> void 00295 OutofcoreOctreeBase<Container, PointT>::queryFrustum(const double *planes, std::list<std::string>& file_names, const boost::uint32_t query_depth) const 00296 { 00297 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00298 root_node_->queryFrustum (planes, file_names, query_depth); 00299 } 00300 00301 //////////////////////////////////////////////////////////////////////////////// 00302 00303 template<typename Container, typename PointT> void 00304 OutofcoreOctreeBase<Container, PointT>::queryFrustum ( 00305 const double *planes, 00306 const Eigen::Vector3d &eye, 00307 const Eigen::Matrix4d &view_projection_matrix, 00308 std::list<std::string>& file_names, 00309 const boost::uint32_t query_depth) const 00310 { 00311 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00312 root_node_->queryFrustum (planes, eye, view_projection_matrix, file_names, query_depth); 00313 } 00314 00315 //////////////////////////////////////////////////////////////////////////////// 00316 00317 template<typename ContainerT, typename PointT> void 00318 OutofcoreOctreeBase<ContainerT, PointT>::queryBBIncludes (const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::uint64_t query_depth, AlignedPointTVector& dst) const 00319 { 00320 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00321 dst.clear (); 00322 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode] Querying Bounding Box %.2lf %.2lf %.2lf, %.2lf %.2lf %.2lf", min[0], min[1], min[2], max[0], max[1], max[2]); 00323 root_node_->queryBBIncludes (min, max, query_depth, dst); 00324 } 00325 00326 //////////////////////////////////////////////////////////////////////////////// 00327 00328 template<typename ContainerT, typename PointT> void 00329 OutofcoreOctreeBase<ContainerT, PointT>::queryBBIncludes (const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::uint64_t query_depth, const pcl::PCLPointCloud2::Ptr& dst_blob) const 00330 { 00331 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00332 00333 dst_blob->data.clear (); 00334 dst_blob->width = 0; 00335 dst_blob->height =1; 00336 00337 root_node_->queryBBIncludes ( min, max, query_depth, dst_blob ); 00338 } 00339 00340 //////////////////////////////////////////////////////////////////////////////// 00341 00342 template<typename ContainerT, typename PointT> void 00343 OutofcoreOctreeBase<ContainerT, PointT>::queryBBIncludes_subsample (const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::uint64_t query_depth, const double percent, AlignedPointTVector& dst) const 00344 { 00345 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00346 dst.clear (); 00347 root_node_->queryBBIncludes_subsample (min, max, query_depth, percent, dst); 00348 } 00349 00350 //////////////////////////////////////////////////////////////////////////////// 00351 template<typename ContainerT, typename PointT> void 00352 OutofcoreOctreeBase<ContainerT, PointT>::queryBoundingBox (const Eigen::Vector3d &min, const Eigen::Vector3d &max, const int query_depth, const pcl::PCLPointCloud2::Ptr &dst_blob, double percent) 00353 { 00354 if (percent==1.0) 00355 { 00356 root_node_->queryBBIncludes (min, max, query_depth, dst_blob); 00357 } 00358 else 00359 { 00360 root_node_->queryBBIncludes_subsample (min, max, query_depth, dst_blob, percent); 00361 } 00362 } 00363 00364 //////////////////////////////////////////////////////////////////////////////// 00365 00366 template<typename ContainerT, typename PointT> bool 00367 OutofcoreOctreeBase<ContainerT, PointT>::getBoundingBox (Eigen::Vector3d &min, Eigen::Vector3d &max) const 00368 { 00369 if (root_node_!= NULL) 00370 { 00371 root_node_->getBoundingBox (min, max); 00372 return true; 00373 } 00374 return false; 00375 } 00376 00377 //////////////////////////////////////////////////////////////////////////////// 00378 00379 template<typename ContainerT, typename PointT> void 00380 OutofcoreOctreeBase<ContainerT, PointT>::printBoundingBox(const size_t query_depth) const 00381 { 00382 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00383 root_node_->printBoundingBox (query_depth); 00384 } 00385 00386 //////////////////////////////////////////////////////////////////////////////// 00387 00388 template<typename ContainerT, typename PointT> void 00389 OutofcoreOctreeBase<ContainerT, PointT>::getOccupiedVoxelCenters(AlignedPointTVector &voxel_centers, const size_t query_depth) const 00390 { 00391 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00392 if (query_depth > metadata_->getDepth ()) 00393 { 00394 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, metadata_->getDepth ()); 00395 } 00396 else 00397 { 00398 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, query_depth); 00399 } 00400 } 00401 00402 //////////////////////////////////////////////////////////////////////////////// 00403 00404 template<typename ContainerT, typename PointT> void 00405 OutofcoreOctreeBase<ContainerT, PointT>::getOccupiedVoxelCenters(std::vector<Eigen::Vector3d, Eigen::aligned_allocator<Eigen::Vector3d> > &voxel_centers, const size_t query_depth) const 00406 { 00407 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00408 if (query_depth > metadata_->getDepth ()) 00409 { 00410 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, metadata_->getDepth ()); 00411 } 00412 else 00413 { 00414 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, query_depth); 00415 } 00416 } 00417 00418 //////////////////////////////////////////////////////////////////////////////// 00419 00420 template<typename ContainerT, typename PointT> void 00421 OutofcoreOctreeBase<ContainerT, PointT>::queryBBIntersects (const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::uint32_t query_depth, std::list<std::string>& bin_name) const 00422 { 00423 boost::shared_lock < boost::shared_mutex > lock (read_write_mutex_); 00424 bin_name.clear (); 00425 #if defined _MSC_VER 00426 #pragma warning(push) 00427 #pragma warning(disable : 4267) 00428 #endif 00429 root_node_->queryBBIntersects (min, max, query_depth, bin_name); 00430 #if defined _MSC_VER 00431 #pragma warning(pop) 00432 #endif 00433 } 00434 00435 //////////////////////////////////////////////////////////////////////////////// 00436 00437 template<typename ContainerT, typename PointT> void 00438 OutofcoreOctreeBase<ContainerT, PointT>::writeVPythonVisual (const boost::filesystem::path filename) 00439 { 00440 #if ! defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION < 3 00441 std::ofstream f (filename.filename().c_str ()); 00442 #else 00443 std::ofstream f (filename.c_str ()); 00444 #endif 00445 00446 f << "from visual import *\n\n"; 00447 00448 root_node_->writeVPythonVisual (f); 00449 } 00450 00451 //////////////////////////////////////////////////////////////////////////////// 00452 00453 template<typename ContainerT, typename PointT> void 00454 OutofcoreOctreeBase<ContainerT, PointT>::flushToDisk () 00455 { 00456 root_node_->flushToDisk (); 00457 } 00458 00459 //////////////////////////////////////////////////////////////////////////////// 00460 00461 template<typename ContainerT, typename PointT> void 00462 OutofcoreOctreeBase<ContainerT, PointT>::flushToDiskLazy () 00463 { 00464 root_node_->flushToDiskLazy (); 00465 } 00466 00467 //////////////////////////////////////////////////////////////////////////////// 00468 00469 template<typename ContainerT, typename PointT> void 00470 OutofcoreOctreeBase<ContainerT, PointT>::convertToXYZ () 00471 { 00472 saveToFile (); 00473 root_node_->convertToXYZ (); 00474 } 00475 00476 //////////////////////////////////////////////////////////////////////////////// 00477 00478 template<typename ContainerT, typename PointT> void 00479 OutofcoreOctreeBase<ContainerT, PointT>::DeAllocEmptyNodeCache () 00480 { 00481 DeAllocEmptyNodeCache (root_node_); 00482 } 00483 00484 //////////////////////////////////////////////////////////////////////////////// 00485 00486 template<typename ContainerT, typename PointT> void 00487 OutofcoreOctreeBase<ContainerT, PointT>::DeAllocEmptyNodeCache (OutofcoreOctreeBaseNode<ContainerT, PointT>* current) 00488 { 00489 if (current->size () == 0) 00490 { 00491 current->flush_DeAlloc_this_only (); 00492 } 00493 00494 for (int i = 0; i < current->numchildren (); i++) 00495 { 00496 DeAllocEmptyNodeCache (current->children[i]); 00497 } 00498 00499 } 00500 00501 //////////////////////////////////////////////////////////////////////////////// 00502 template<typename ContainerT, typename PointT> OutofcoreOctreeBaseNode<ContainerT, PointT>* 00503 OutofcoreOctreeBase<ContainerT, PointT>::getBranchChildPtr (const BranchNode& branch_arg, unsigned char childIdx_arg) const 00504 { 00505 return (branch_arg.getChildPtr (childIdx_arg)); 00506 } 00507 00508 //////////////////////////////////////////////////////////////////////////////// 00509 template<typename ContainerT, typename PointT> pcl::Filter<pcl::PCLPointCloud2>::Ptr 00510 OutofcoreOctreeBase<ContainerT, PointT>::getLODFilter () 00511 { 00512 return (lod_filter_ptr_); 00513 } 00514 00515 //////////////////////////////////////////////////////////////////////////////// 00516 00517 template<typename ContainerT, typename PointT> const pcl::Filter<pcl::PCLPointCloud2>::ConstPtr 00518 OutofcoreOctreeBase<ContainerT, PointT>::getLODFilter () const 00519 { 00520 return (lod_filter_ptr_); 00521 } 00522 00523 //////////////////////////////////////////////////////////////////////////////// 00524 00525 template<typename ContainerT, typename PointT> void 00526 OutofcoreOctreeBase<ContainerT, PointT>::setLODFilter (const pcl::Filter<pcl::PCLPointCloud2>::Ptr& filter_arg) 00527 { 00528 lod_filter_ptr_ = filter_arg; 00529 } 00530 00531 //////////////////////////////////////////////////////////////////////////////// 00532 00533 template<typename ContainerT, typename PointT> bool 00534 OutofcoreOctreeBase<ContainerT, PointT>::getBinDimension (double& x, double& y) const 00535 { 00536 if (root_node_== NULL) 00537 { 00538 x = 0; 00539 y = 0; 00540 return (false); 00541 } 00542 00543 Eigen::Vector3d min, max; 00544 this->getBoundingBox (min, max); 00545 00546 double depth = static_cast<double> (metadata_->getDepth ()); 00547 Eigen::Vector3d diff = max-min; 00548 00549 y = diff[1] * pow (.5, depth); 00550 x = diff[0] * pow (.5, depth); 00551 00552 return (true); 00553 } 00554 00555 //////////////////////////////////////////////////////////////////////////////// 00556 00557 template<typename ContainerT, typename PointT> double 00558 OutofcoreOctreeBase<ContainerT, PointT>::getVoxelSideLength (const boost::uint64_t& depth) const 00559 { 00560 Eigen::Vector3d min, max; 00561 this->getBoundingBox (min, max); 00562 double result = (max[0] - min[0]) * pow (.5, static_cast<double> (metadata_->getDepth ())) * static_cast<double> (1 << (metadata_->getDepth () - depth)); 00563 return (result); 00564 } 00565 00566 //////////////////////////////////////////////////////////////////////////////// 00567 00568 template<typename ContainerT, typename PointT> void 00569 OutofcoreOctreeBase<ContainerT, PointT>::buildLOD () 00570 { 00571 if (root_node_== NULL) 00572 { 00573 PCL_ERROR ("Root node is null; aborting buildLOD.\n"); 00574 return; 00575 } 00576 00577 boost::unique_lock < boost::shared_mutex > lock (read_write_mutex_); 00578 00579 const int number_of_nodes = 1; 00580 00581 std::vector<BranchNode*> current_branch (number_of_nodes, static_cast<BranchNode*>(0)); 00582 current_branch[0] = root_node_; 00583 assert (current_branch.back () != 0); 00584 this->buildLODRecursive (current_branch); 00585 } 00586 00587 //////////////////////////////////////////////////////////////////////////////// 00588 00589 template<typename ContainerT, typename PointT> void 00590 OutofcoreOctreeBase<ContainerT, PointT>::printBoundingBox (OutofcoreOctreeBaseNode<ContainerT, PointT>& node) const 00591 { 00592 Eigen::Vector3d min, max; 00593 node.getBoundingBox (min,max); 00594 PCL_INFO ("[pcl::outofcore::OutofcoreOctreeBase::%s] min(%lf,%lf,%lf), max(%lf,%lf,%lf)\n", __FUNCTION__, min[0], min[1], min[2], max[0], max[1], max[2]); 00595 } 00596 00597 00598 //////////////////////////////////////////////////////////////////////////////// 00599 00600 template<typename ContainerT, typename PointT> void 00601 OutofcoreOctreeBase<ContainerT, PointT>::buildLODRecursive (const std::vector<BranchNode*>& current_branch) 00602 { 00603 PCL_DEBUG ("%s Building LOD at depth %d",__PRETTY_FUNCTION__, current_branch.size ()); 00604 00605 if (!current_branch.back ()) 00606 { 00607 return; 00608 } 00609 00610 if (current_branch.back ()->getNodeType () == pcl::octree::LEAF_NODE) 00611 { 00612 assert (current_branch.back ()->getDepth () == this->getDepth ()); 00613 00614 BranchNode* leaf = current_branch.back (); 00615 00616 pcl::PCLPointCloud2::Ptr leaf_input_cloud (new pcl::PCLPointCloud2 ()); 00617 //read the data from the PCD file associated with the leaf; it is full resolution 00618 leaf->read (leaf_input_cloud); 00619 assert (leaf_input_cloud->width*leaf_input_cloud->height > 0); 00620 00621 //go up the tree, re-downsampling the full resolution leaf cloud at lower and lower resolution 00622 for (int64_t level = static_cast<int64_t>(current_branch.size ()-1); level >= 1; level--) 00623 { 00624 BranchNode* target_parent = current_branch[level-1]; 00625 assert (target_parent != 0); 00626 double exponent = static_cast<double>(current_branch.size () - target_parent->getDepth ()); 00627 double current_depth_sample_percent = pow (sample_percent_, exponent); 00628 00629 assert (current_depth_sample_percent > 0.0); 00630 //------------------------------------------------------------ 00631 //subsample data: 00632 // 1. Get indices from a random sample 00633 // 2. Extract those indices with the extract indices class (in order to also get the complement) 00634 //------------------------------------------------------------ 00635 00636 lod_filter_ptr_->setInputCloud (leaf_input_cloud); 00637 00638 //set sample size to 1/8 of total points (12.5%) 00639 uint64_t sample_size = static_cast<uint64_t> (static_cast<double> (leaf_input_cloud->width*leaf_input_cloud->height) * current_depth_sample_percent); 00640 00641 if (sample_size == 0) 00642 sample_size = 1; 00643 00644 lod_filter_ptr_->setSample (static_cast<unsigned int>(sample_size)); 00645 00646 //create our destination 00647 pcl::PCLPointCloud2::Ptr downsampled_cloud (new pcl::PCLPointCloud2 ()); 00648 00649 //create destination for indices 00650 pcl::IndicesPtr downsampled_cloud_indices (new std::vector< int > ()); 00651 lod_filter_ptr_->filter (*downsampled_cloud_indices); 00652 00653 //extract the "random subset", size by setSampleSize 00654 pcl::ExtractIndices<pcl::PCLPointCloud2> extractor; 00655 extractor.setInputCloud (leaf_input_cloud); 00656 extractor.setIndices (downsampled_cloud_indices); 00657 extractor.filter (*downsampled_cloud); 00658 00659 //write to the target 00660 if (downsampled_cloud->width*downsampled_cloud->height > 0) 00661 { 00662 target_parent->payload_->insertRange (downsampled_cloud); 00663 this->incrementPointsInLOD (target_parent->getDepth (), downsampled_cloud->width*downsampled_cloud->height); 00664 } 00665 } 00666 } 00667 else//not at leaf, keep going down 00668 { 00669 //clear this node while walking down the tree in case we are updating the LOD 00670 current_branch.back ()->clearData (); 00671 00672 std::vector<BranchNode*> next_branch (current_branch); 00673 00674 if (current_branch.back ()->hasUnloadedChildren ()) 00675 { 00676 current_branch.back ()->loadChildren (false); 00677 } 00678 00679 for (size_t i = 0; i < 8; i++) 00680 { 00681 next_branch.push_back (current_branch.back ()->getChildPtr (i)); 00682 //skip that child if it doesn't exist 00683 if (next_branch.back () != 0) 00684 buildLODRecursive (next_branch); 00685 00686 next_branch.pop_back (); 00687 } 00688 } 00689 } 00690 //////////////////////////////////////////////////////////////////////////////// 00691 00692 template<typename ContainerT, typename PointT> void 00693 OutofcoreOctreeBase<ContainerT, PointT>::incrementPointsInLOD (boost::uint64_t depth, boost::uint64_t new_point_count) 00694 { 00695 if (std::numeric_limits<uint64_t>::max () - metadata_->getLODPoints (depth) < new_point_count) 00696 { 00697 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBase::incrementPointsInLOD] Overflow error. Too many points in depth %d of outofcore octree with root at %s\n", depth, 00698 #if ! defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION < 3 00699 metadata_->getMetadataFilename().filename().c_str()); 00700 #else 00701 metadata_->getMetadataFilename().c_str()); 00702 #endif 00703 PCL_THROW_EXCEPTION (PCLException, "Overflow error"); 00704 } 00705 00706 metadata_->setLODPoints (depth, new_point_count, true /*true->increment*/); 00707 } 00708 00709 //////////////////////////////////////////////////////////////////////////////// 00710 00711 template<typename ContainerT, typename PointT> bool 00712 OutofcoreOctreeBase<ContainerT, PointT>::checkExtension (const boost::filesystem::path& path_name) 00713 { 00714 if (boost::filesystem::extension (path_name) != OutofcoreOctreeBaseNode<ContainerT, PointT>::node_index_extension) 00715 { 00716 PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBase] Wrong root node file extension: %s. The tree must have a root node ending in %s\n", boost::filesystem::extension (path_name).c_str (), OutofcoreOctreeBaseNode<ContainerT, PointT>::node_index_extension.c_str () ); 00717 return (0); 00718 } 00719 00720 return (1); 00721 } 00722 00723 //////////////////////////////////////////////////////////////////////////////// 00724 00725 template<typename ContainerT, typename PointT> void 00726 OutofcoreOctreeBase<ContainerT, PointT>::enlargeToCube (Eigen::Vector3d& bb_min, Eigen::Vector3d& bb_max) 00727 { 00728 Eigen::Vector3d diff = bb_max - bb_min; 00729 assert (diff[0] > 0); 00730 assert (diff[1] > 0); 00731 assert (diff[2] > 0); 00732 Eigen::Vector3d center = (bb_max + bb_min)/2.0; 00733 00734 double max_sidelength = std::max (std::max (fabs (diff[0]), fabs (diff[1])), fabs (diff[2])); 00735 assert (max_sidelength > 0); 00736 bb_min = center - Eigen::Vector3d (1.0, 1.0, 1.0)*(max_sidelength/2.0); 00737 bb_max = center + Eigen::Vector3d (1.0, 1.0, 1.0)*(max_sidelength/2.0); 00738 } 00739 00740 //////////////////////////////////////////////////////////////////////////////// 00741 00742 template<typename ContainerT, typename PointT> boost::uint64_t 00743 OutofcoreOctreeBase<ContainerT, PointT>::calculateDepth (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, const double leaf_resolution) 00744 { 00745 //Assume cube 00746 double side_length = max_bb[0] - min_bb[0]; 00747 00748 if (side_length < leaf_resolution) 00749 return (0); 00750 00751 boost::uint64_t res = static_cast<boost::uint64_t> (std::ceil (log2f (static_cast<float> (side_length / leaf_resolution)))); 00752 00753 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBase::calculateDepth] Setting depth to %d\n",res); 00754 return (res); 00755 } 00756 }//namespace outofcore 00757 }//namespace pcl 00758 00759 #endif //PCL_OUTOFCORE_OCTREE_BASE_IMPL_H_
Except where otherwise noted, the PointClouds.org web pages are licensed under Creative Commons Attribution 3.0.
Pages generated on Wed Mar 25 00:24:34 2015