00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef OCTREE_H_
00037 #define OCTREE_H_
00038
00039 #include <boost/shared_ptr.hpp>
00040 #include <octreelib/spatialaggregate/octree.h>
00041 #include <octreelib/algorithm/downsample.h>
00042 #include "NormalEstimationValueClass.h"
00043 #include <list>
00044 #include <vector>
00045
00046 class OcTree {
00047 public:
00048 typedef NormalEstimationValueClass ValueClass;
00049 typedef spatialaggregate::OcTree<float, ValueClass> Octree;
00050 typedef Octree* OctreePtr;
00051 typedef spatialaggregate::OcTreeNodeFixedCountAllocator<float, ValueClass> Allocator;
00052 typedef boost::shared_ptr<Allocator> AllocatorPtr;
00053 typedef algorithm::OcTreeSamplingMap<float, ValueClass> SamplingMap;
00054 typedef spatialaggregate::OcTreeNode<float, ValueClass>* NodePtr;
00055 typedef spatialaggregate::OcTreeKey<float, ValueClass> OctreeKey;
00056 typedef std::vector<NodePtr> NodePointers;
00057 typedef std::list<NodePtr> NodePointerList;
00058 typedef std::vector<int> PointIndices;
00059 typedef std::vector<PointIndices> NodeIdToPointIdxVector;
00060 typedef Eigen::Vector3f Vec3;
00061
00062 OcTree(float minOctreeResolution, float rho_max, float principalVarFactor, float minPointsForNormal,
00063 float curvThreshold, float curv2Threshold, float sqDistFactor, size_t numPoints) :
00064 mOctreePtr(NULL), mOctreeDepth(0), mMinOctreeResolution(minOctreeResolution), mRho_max(rho_max),
00065 mPrincipalVarFactor(principalVarFactor), mMinPointsForNormal(minPointsForNormal), mCurvThreshold(
00066 curvThreshold), mCurv2Threshold(curv2Threshold) , mSqDistFactor(sqDistFactor){
00067 preAllocate(numPoints);
00068 }
00069
00070 ~OcTree() {
00071 if (mOctreePtr != NULL)
00072 delete mOctreePtr;
00073 }
00074
00075 void preAllocate(const size_t& numPoints);
00076
00077 template<typename PointCloudType>
00078 void buildOctree(const PointCloudType& pointCloud);
00079
00080 bool checkSamplingMap() const
00081 {
00082 for(unsigned int depth = 0; depth <= mOctreeDepth; ++depth)
00083 {
00084 NodePointers octreeNodes(getNodesOnDepth(depth));
00085 if(!checkOctreeNodes(octreeNodes))
00086 {
00087 std::cout << "checkSamplingMap test failed on depth " << depth << " of " << mOctreeDepth << std::endl;
00088 return false;
00089 }
00090 }
00091 return true;
00092 }
00093
00094 bool checkGetAllLeafs() const
00095 {
00096 NodePointers octreeNodes;
00097 getAllLeafs(octreeNodes, mOctreePtr->root_);
00098 return checkOctreeNodes(octreeNodes);
00099 }
00100
00101 bool checkOctreeNodes(const NodePointers& nodePointers) const
00102 {
00103 for(NodePointers::const_iterator np_it = nodePointers.begin(); np_it != nodePointers.end(); ++np_it)
00104 {
00105 if((*np_it)->value_.id >= mNodeIdToPointIdxVector.size())
00106 {
00107 return false;
00108 }
00109 }
00110 return true;
00111 }
00112
00113 const unsigned int& getMaxDepth() const {
00114 return mOctreeDepth;
00115 }
00116
00117 const SamplingMap& getSamplingMap() const {
00118 return mSamplingMap;
00119 }
00120
00121 const NodePointerList& getNodeListOnDepth(const unsigned int& depth) const {
00122 assert(depth <= mOctreeDepth);
00123 return mSamplingMap.find(depth)->second;
00124 }
00125
00126 NodePointers getNodesOnDepth(const unsigned int& depth) const {
00127 assert(depth <= mOctreeDepth);
00128 NodePointerList nodePointerList = mSamplingMap.find(depth)->second;
00129 NodePointers nodePointers;
00130 for(NodePointerList::const_iterator list_it = nodePointerList.begin(); list_it != nodePointerList.end(); ++list_it)
00131 {
00132 nodePointers.push_back(*list_it);
00133 }
00134 return nodePointers;
00135 }
00136
00137 const OctreePtr& getOctreePtr() const
00138 {
00139 return mOctreePtr;
00140 }
00141
00142 const PointIndices& getPointsFromNodeId(const unsigned int& nodeId) const {
00143 assert(nodeId < mNodeIdToPointIdxVector.size());
00144 return mNodeIdToPointIdxVector[nodeId];
00145 }
00146
00147 const PointIndices& getPointsFromNodePtr(const NodePtr& nodePtr) const {
00148 const unsigned int& nodeId = nodePtr->value_.id;
00149 return getPointsFromNodeId(nodeId);
00150 }
00151
00152 float getCellSizeFromDepth(const unsigned int& depth) const {
00153 return mOctreePtr->volumeSizeForDepth((int) depth);
00154 }
00155
00156 void findFinestNormal(Vec3& normal, const Vec3& point) const{
00157 NodePtr nodePtr = mOctreePtr->root_->findRepresentative(Eigen::Vector4f(point(0), point(1), point(2), 1.f), mMinOctreeResolution);
00158 while(!nodePtr->value_.stable){
00159 nodePtr = nodePtr->parent_;
00160 }
00161 normal = nodePtr->value_.normal;
00162 }
00163
00164 void getNeighboringNodes(NodePointers& neighborNodes, const NodePtr& node, const unsigned int& maxSearchDepth,
00165 const float& neighborhoodSize = 1.f) const;
00166
00167 void getNeighboringNodes(NodePointers& neighborNodes, const NodePtr& currNode, const unsigned int& maxSearchDepth,
00168 const unsigned int& currDepth, const OctreeKey& minPos, const OctreeKey& maxPos) const;
00169
00170 void getAllLeafs(NodePointers& leafNodes, const NodePtr& topNode) const;
00171 private:
00172 AllocatorPtr mAllocatorPtr;
00173 OctreePtr mOctreePtr;
00174 unsigned int mOctreeDepth;
00175 SamplingMap mSamplingMap;
00176 NodeIdToPointIdxVector mNodeIdToPointIdxVector;
00177
00178
00179 float mMinOctreeResolution;
00180 float mRho_max;
00181 float mPrincipalVarFactor;
00182 float mMinPointsForNormal;
00183 float mCurvThreshold;
00184 float mCurv2Threshold;
00185 float mSqDistFactor;
00186 };
00187
00188 inline void OcTree::preAllocate(const size_t& numPoints) {
00189 mAllocatorPtr.reset(new Allocator(numPoints));
00190 }
00191
00192 template<typename PointCloudType>
00193 void OcTree::buildOctree(const PointCloudType& pointCloud) {
00194 mNodeIdToPointIdxVector.clear();
00195 mNodeIdToPointIdxVector.reserve(pointCloud.points.size());
00196 mAllocatorPtr->reset();
00197
00198 if (mOctreePtr)
00199 delete mOctreePtr;
00200 Vec3 rootPos(0.f, 0.f, 0.f);
00201 mOctreePtr = new Octree(Eigen::Vector4f(rootPos(0), rootPos(1), rootPos(2), 1.f), mMinOctreeResolution, mRho_max, mAllocatorPtr);
00202 mOctreeDepth = 0;
00203 unsigned int idx = 0;
00204 for (unsigned int i = 0; i < pointCloud.points.size(); i++) {
00205 if (isnan(pointCloud.points[i].x) || isinf(pointCloud.points[i].x))
00206 continue;
00207
00208 if (isnan(pointCloud.points[i].y) || isinf(pointCloud.points[i].y))
00209 continue;
00210
00211 if (isnan(pointCloud.points[i].z) || isinf(pointCloud.points[i].z))
00212 continue;
00213 Vec3 pos(pointCloud.points[i].getVector3fMap());
00214 ValueClass val;
00215 val.id = idx;
00216 val.numPoints = 1;
00217 val.summedSquares(0, 0) = pos(0) * pos(0);
00218 val.summedSquares(0, 1) = val.summedSquares(1, 0) = pos(0) * pos(1);
00219 val.summedSquares(0, 2) = val.summedSquares(2, 0) = pos(0) * pos(2);
00220 val.summedSquares(1, 1) = pos(1) * pos(1);
00221 val.summedSquares(1, 2) = val.summedSquares(2, 1) = pos(1) * pos(2);
00222 val.summedSquares(2, 2) = pos(2) * pos(2);
00223 val.summedPos(0) = pos(0);
00224 val.summedPos(1) = pos(1);
00225 val.summedPos(2) = pos(2);
00226 NodePtr n;
00227 if (mSqDistFactor > 0.f){
00228 float sqdist = val.summedSquares(0, 0) + val.summedSquares(1, 1) + val.summedSquares(2, 2);
00229 float minResolution = std::max(mMinOctreeResolution, mSqDistFactor * sqdist);
00230 n = mOctreePtr->addPoint(pos(0), pos(1), pos(2), val, mOctreePtr->depthForVolumeSize(minResolution));
00231 }
00232 else
00233 n = mOctreePtr->addPoint(pos(0), pos(1), pos(2), val, mOctreePtr->depthForVolumeSize(mMinOctreeResolution));
00234 if (n->value_.id == idx) {
00235 mNodeIdToPointIdxVector.push_back(std::vector<int>(1, i));
00236 idx++;
00237 } else {
00238 assert(n->value_.id <= pointCloud.points.size());
00239 mNodeIdToPointIdxVector[n->value_.id].push_back(i);
00240 }
00241 if ((unsigned int)n->depth_ > mOctreeDepth)
00242 mOctreeDepth = (unsigned int)n->depth_;
00243 }
00244
00245 assert(checkGetAllLeafs());
00246
00247 mSamplingMap.clear();
00248 mSamplingMap = algorithm::downsampleOcTree(*mOctreePtr, true, mOctreeDepth);
00249 for (unsigned int d = 0; d <= mOctreeDepth; d++) {
00250 const NodePointerList& octreeLayer = mSamplingMap[d];
00251 float principalVariance = mPrincipalVarFactor * getCellSizeFromDepth(d);
00252 principalVariance *= principalVariance;
00253 for(NodePointerList::const_iterator np_it = octreeLayer.begin(); np_it != octreeLayer.end(); ++np_it)
00254 {
00255 if (!(*np_it)->value_.stable)
00256 {
00257 calculateNormal((*np_it), Vec3(0.f, 0.f, 0.f), mMinPointsForNormal, mCurvThreshold, mCurv2Threshold, principalVariance);
00258 }
00259 }
00260 }
00261
00262 assert(checkSamplingMap());
00263 }
00264
00265 inline void OcTree::getNeighboringNodes(NodePointers& neighborNodes, const NodePtr& node, const unsigned int& maxSearchDepth,
00266 const float& neighborhoodSize) const {
00267 Vec3 size;
00268 size(0) = node->max_key_.getPosition(node->tree_)(0) - node->min_key_.getPosition(node->tree_)(0);
00269 size(1) = node->max_key_.getPosition(node->tree_)(1) - node->min_key_.getPosition(node->tree_)(1);
00270 size(2) = node->max_key_.getPosition(node->tree_)(2) - node->min_key_.getPosition(node->tree_)(2);
00271 float minPosX = node->pos_key_.getPosition(node->tree_)(0) - size(0) * neighborhoodSize;
00272 float minPosY = node->pos_key_.getPosition(node->tree_)(1) - size(1) * neighborhoodSize;
00273 float minPosZ = node->pos_key_.getPosition(node->tree_)(2) - size(2) * neighborhoodSize;
00274 OctreeKey minPos(minPosX, minPosY, minPosZ, node->tree_);
00275 float maxPosX = node->pos_key_.getPosition(node->tree_)(0) + size(0) * neighborhoodSize;
00276 float maxPosY = node->pos_key_.getPosition(node->tree_)(1) + size(1) * neighborhoodSize;
00277 float maxPosZ = node->pos_key_.getPosition(node->tree_)(2) + size(2) * neighborhoodSize;
00278 OctreeKey maxPos(maxPosX, maxPosY, maxPosZ, node->tree_);
00279 getNeighboringNodes(neighborNodes, mOctreePtr->root_, maxSearchDepth, 0, minPos, maxPos);
00280 }
00281
00282 inline void OcTree::getNeighboringNodes(NodePointers& neighborNodes, const NodePtr& currNode, const unsigned int& maxSearchDepth,
00283 const unsigned int& currDepth, const OctreeKey& minPos, const OctreeKey& maxPos) const {
00284 if (currNode->type_ == spatialaggregate::OCTREE_LEAF_NODE || currDepth == maxSearchDepth) {
00285 if (currNode->overlap(minPos, maxPos) && !currNode->value_.nodeQuerried) {
00286 neighborNodes.push_back(currNode);
00287 }
00288 } else {
00289 for (unsigned int i=0; i<8; ++i){
00290 if (!currNode->children_[i]){
00291 continue;
00292 }
00293 if(currNode->children_[i]->overlap(minPos, maxPos))
00294 getNeighboringNodes(neighborNodes, currNode->children_[i], maxSearchDepth, currDepth+1, minPos, maxPos);
00295 }
00296 }
00297 }
00298
00299 inline void OcTree::getAllLeafs(NodePointers& leafNodes, const NodePtr& topNode) const{
00300 if(topNode->type_ == spatialaggregate::OCTREE_LEAF_NODE){
00301 leafNodes.push_back(topNode);
00302 }
00303 else {
00304
00305
00306 for(unsigned int i = 0; i < 8; i++){
00307 if(!topNode->children_[i])
00308 continue;
00309 getAllLeafs(leafNodes, topNode->children_[i]);
00310 }
00311 }
00312 }
00313 #endif