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 #include "nabo_private.h"
00033 #include "index_heap.h"
00034 #include <iostream>
00035 #include <stdexcept>
00036 #include <limits>
00037 #include <queue>
00038 #include <algorithm>
00039 #include <utility>
00040 #include <boost/numeric/conversion/bounds.hpp>
00041 #include <boost/limits.hpp>
00042 #include <boost/format.hpp>
00043 #ifdef HAVE_OPENMP
00044 #include <omp.h>
00045 #endif
00046
00052 namespace Nabo
00053 {
00055
00056
00057 using namespace std;
00058
00060
00063 template<typename T>
00064 T getStorageBitCount(T v)
00065 {
00066 for (T i = 0; i < 64; ++i)
00067 {
00068 if (v == 0)
00069 return i;
00070 v >>= 1;
00071 }
00072 return 64;
00073 }
00074
00076
00079 template<typename T, typename CloudType>
00080 size_t argMax(const typename NearestNeighbourSearch<T, CloudType>::Vector& v)
00081 {
00082 T maxVal(0);
00083 size_t maxIdx(0);
00084 for (int i = 0; i < v.size(); ++i)
00085 {
00086 if (v[i] > maxVal)
00087 {
00088 maxVal = v[i];
00089 maxIdx = i;
00090 }
00091 }
00092 return maxIdx;
00093 }
00094
00095
00096 template<typename T, typename Heap, typename CloudType>
00097 pair<T,T> KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::getBounds(const BuildPointsIt first, const BuildPointsIt last, const unsigned dim)
00098 {
00099 T minVal(boost::numeric::bounds<T>::highest());
00100 T maxVal(boost::numeric::bounds<T>::lowest());
00101
00102 for (BuildPointsCstIt it(first); it != last; ++it)
00103 {
00104 const T val(cloud.coeff(dim, *it));
00105 minVal = min(val, minVal);
00106 maxVal = max(val, maxVal);
00107 }
00108
00109 return make_pair(minVal, maxVal);
00110 }
00111
00112 template<typename T, typename Heap, typename CloudType>
00113 unsigned KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::buildNodes(const BuildPointsIt first, const BuildPointsIt last, const Vector minValues, const Vector maxValues)
00114 {
00115 const int count(last - first);
00116 assert(count >= 1);
00117 const unsigned pos(nodes.size());
00118
00119
00120 if (count <= int(bucketSize))
00121 {
00122 const uint32_t initBucketsSize(buckets.size());
00123
00124 for (int i = 0; i < count; ++i)
00125 {
00126 const Index index(*(first+i));
00127 assert(index < cloud.cols());
00128 buckets.push_back(BucketEntry(&cloud.coeff(0, index), index));
00129
00130 }
00131
00132 nodes.push_back(Node(createDimChildBucketSize(dim, count),initBucketsSize));
00133 return pos;
00134 }
00135
00136
00137 const unsigned cutDim = argMax<T, CloudType>(maxValues - minValues);
00138 const T idealCutVal((maxValues(cutDim) + minValues(cutDim))/2);
00139
00140
00141 const pair<T,T> minMaxVals(getBounds(first, last, cutDim));
00142
00143
00144 T cutVal;
00145 if (idealCutVal < minMaxVals.first)
00146 cutVal = minMaxVals.first;
00147 else if (idealCutVal > minMaxVals.second)
00148 cutVal = minMaxVals.second;
00149 else
00150 cutVal = idealCutVal;
00151
00152 int l(0);
00153 int r(count-1);
00154
00155 while (1)
00156 {
00157 while (l < count && cloud.coeff(cutDim, *(first+l)) < cutVal)
00158 ++l;
00159 while (r >= 0 && cloud.coeff(cutDim, *(first+r)) >= cutVal)
00160 --r;
00161 if (l > r)
00162 break;
00163 swap(*(first+l), *(first+r));
00164 ++l; --r;
00165 }
00166 const int br1 = l;
00167 r = count-1;
00168
00169 while (1)
00170 {
00171 while (l < count && cloud.coeff(cutDim, *(first+l)) <= cutVal)
00172 ++l;
00173 while (r >= br1 && cloud.coeff(cutDim, *(first+r)) > cutVal)
00174 --r;
00175 if (l > r)
00176 break;
00177 swap(*(first+l), *(first+r));
00178 ++l; --r;
00179 }
00180 const int br2 = l;
00181
00182
00183 int leftCount;
00184 if (idealCutVal < minMaxVals.first)
00185 leftCount = 1;
00186 else if (idealCutVal > minMaxVals.second)
00187 leftCount = count-1;
00188 else if (br1 > count / 2)
00189 leftCount = br1;
00190 else if (br2 < count / 2)
00191 leftCount = br2;
00192 else
00193 leftCount = count / 2;
00194 assert(leftCount > 0);
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 assert(leftCount < count);
00209
00210
00211 Vector leftMaxValues(maxValues);
00212 leftMaxValues[cutDim] = cutVal;
00213
00214 Vector rightMinValues(minValues);
00215 rightMinValues[cutDim] = cutVal;
00216
00217
00218 nodes.push_back(Node(0, cutVal));
00219
00220
00221 const unsigned _UNUSED leftChild = buildNodes(first, first + leftCount, minValues, leftMaxValues);
00222 assert(leftChild == pos + 1);
00223 const unsigned rightChild = buildNodes(first + leftCount, last, rightMinValues, maxValues);
00224
00225
00226 nodes[pos].dimChildBucketSize = createDimChildBucketSize(cutDim, rightChild);
00227 return pos;
00228 }
00229
00230 template<typename T, typename Heap, typename CloudType>
00231 KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt(const CloudType& cloud, const Index dim, const unsigned creationOptionFlags, const Parameters& additionalParameters):
00232 NearestNeighbourSearch<T, CloudType>::NearestNeighbourSearch(cloud, dim, creationOptionFlags),
00233 bucketSize(additionalParameters.get<unsigned>("bucketSize", 8)),
00234 dimBitCount(getStorageBitCount<uint32_t>(this->dim)),
00235 dimMask((1<<dimBitCount)-1)
00236 {
00237 if (bucketSize < 2)
00238 throw runtime_error((boost::format("Requested bucket size %1%, but must be larger than 2") % bucketSize).str());
00239 if (cloud.cols() <= bucketSize)
00240 {
00241
00242 for (int i = 0; i < cloud.cols(); ++i)
00243 buckets.push_back(BucketEntry(&cloud.coeff(0, i), i));
00244 nodes.push_back(Node(createDimChildBucketSize(this->dim, cloud.cols()),uint32_t(0)));
00245 return;
00246 }
00247
00248 const uint64_t maxNodeCount((0x1ULL << (32-dimBitCount)) - 1);
00249 const uint64_t estimatedNodeCount(cloud.cols() / (bucketSize / 2));
00250 if (estimatedNodeCount > maxNodeCount)
00251 {
00252 throw runtime_error((boost::format("Cloud has a risk to have more nodes (%1%) than the kd-tree allows (%2%). The kd-tree has %3% bits for dimensions and %4% bits for node indices") % estimatedNodeCount % maxNodeCount % dimBitCount % (32-dimBitCount)).str());
00253 }
00254
00255
00256 BuildPoints buildPoints;
00257 buildPoints.reserve(cloud.cols());
00258 for (int i = 0; i < cloud.cols(); ++i)
00259 {
00260 const Vector& v(cloud.block(0,i,this->dim,1));
00261 buildPoints.push_back(i);
00262 #ifdef EIGEN3_API
00263 const_cast<Vector&>(minBound) = minBound.array().min(v.array());
00264 const_cast<Vector&>(maxBound) = maxBound.array().max(v.array());
00265 #else // EIGEN3_API
00266 const_cast<Vector&>(minBound) = minBound.cwise().min(v);
00267 const_cast<Vector&>(maxBound) = maxBound.cwise().max(v);
00268 #endif // EIGEN3_API
00269 }
00270
00271
00272 buildNodes(buildPoints.begin(), buildPoints.end(), minBound, maxBound);
00273 buildPoints.clear();
00274 }
00275
00276 template<typename T, typename Heap, typename CloudType>
00277 unsigned long KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::knn(const Matrix& query, IndexMatrix& indices, Matrix& dists2, const Index k, const T epsilon, const unsigned optionFlags, const T maxRadius) const
00278 {
00279 checkSizesKnn(query, indices, dists2, k, optionFlags);
00280
00281 const bool allowSelfMatch(optionFlags & NearestNeighbourSearch<T>::ALLOW_SELF_MATCH);
00282 const bool sortResults(optionFlags & NearestNeighbourSearch<T>::SORT_RESULTS);
00283 const bool collectStatistics(creationOptionFlags & NearestNeighbourSearch<T>::TOUCH_STATISTICS);
00284 const T maxRadius2(maxRadius * maxRadius);
00285 const T maxError2((1+epsilon)*(1+epsilon));
00286 const int colCount(query.cols());
00287
00288 assert(nodes.size() > 0);
00289
00290 IndexMatrix result(k, query.cols());
00291 unsigned long leafTouchedCount(0);
00292
00293 #pragma omp parallel
00294 {
00295
00296 Heap heap(k);
00297 std::vector<T> off(dim, 0);
00298
00299 #pragma omp for reduction(+:leafTouchedCount) schedule(guided,32)
00300 for (int i = 0; i < colCount; ++i)
00301 {
00302 leafTouchedCount += onePointKnn(query, indices, dists2, i, heap, off, maxError2, maxRadius2, allowSelfMatch, collectStatistics, sortResults);
00303 }
00304 }
00305 return leafTouchedCount;
00306 }
00307
00308 template<typename T, typename Heap, typename CloudType>
00309 unsigned long KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::knn(const Matrix& query, IndexMatrix& indices, Matrix& dists2, const Vector& maxRadii, const Index k, const T epsilon, const unsigned optionFlags) const
00310 {
00311 checkSizesKnn(query, indices, dists2, k, optionFlags, &maxRadii);
00312
00313 const bool allowSelfMatch(optionFlags & NearestNeighbourSearch<T>::ALLOW_SELF_MATCH);
00314 const bool sortResults(optionFlags & NearestNeighbourSearch<T>::SORT_RESULTS);
00315 const bool collectStatistics(creationOptionFlags & NearestNeighbourSearch<T>::TOUCH_STATISTICS);
00316 const T maxError2((1+epsilon)*(1+epsilon));
00317 const int colCount(query.cols());
00318
00319 assert(nodes.size() > 0);
00320 IndexMatrix result(k, query.cols());
00321 unsigned long leafTouchedCount(0);
00322
00323 #pragma omp parallel
00324 {
00325
00326 Heap heap(k);
00327 std::vector<T> off(dim, 0);
00328
00329 #pragma omp for reduction(+:leafTouchedCount) schedule(guided,32)
00330 for (int i = 0; i < colCount; ++i)
00331 {
00332 const T maxRadius(maxRadii[i]);
00333 const T maxRadius2(maxRadius * maxRadius);
00334 leafTouchedCount += onePointKnn(query, indices, dists2, i, heap, off, maxError2, maxRadius2, allowSelfMatch, collectStatistics, sortResults);
00335 }
00336 }
00337 return leafTouchedCount;
00338 }
00339
00340 template<typename T, typename Heap, typename CloudType>
00341 unsigned long KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::onePointKnn(const Matrix& query, IndexMatrix& indices, Matrix& dists2, int i, Heap& heap, std::vector<T>& off, const T maxError2, const T maxRadius2, const bool allowSelfMatch, const bool collectStatistics, const bool sortResults) const
00342 {
00343 fill(off.begin(), off.end(), 0);
00344 heap.reset();
00345 unsigned long leafTouchedCount(0);
00346
00347 if (allowSelfMatch)
00348 {
00349 if (collectStatistics)
00350 leafTouchedCount += recurseKnn<true, true>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00351 else
00352 recurseKnn<true, false>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00353 }
00354 else
00355 {
00356 if (collectStatistics)
00357 leafTouchedCount += recurseKnn<false, true>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00358 else
00359 recurseKnn<false, false>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00360 }
00361
00362 if (sortResults)
00363 heap.sort();
00364
00365 heap.getData(indices.col(i), dists2.col(i));
00366 return leafTouchedCount;
00367 }
00368
00369 template<typename T, typename Heap, typename CloudType> template<bool allowSelfMatch, bool collectStatistics>
00370 unsigned long KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::recurseKnn(const T* query, const unsigned n, T rd, Heap& heap, std::vector<T>& off, const T maxError2, const T maxRadius2) const
00371 {
00372 const Node& node(nodes[n]);
00373 const uint32_t cd(getDim(node.dimChildBucketSize));
00374
00375 if (cd == uint32_t(dim))
00376 {
00377
00378 const BucketEntry* bucket(&buckets[node.bucketIndex]);
00379 const uint32_t bucketSize(getChildBucketSize(node.dimChildBucketSize));
00380 for (uint32_t i = 0; i < bucketSize; ++i)
00381 {
00382
00383
00384
00385 T dist(0);
00386 const T* qPtr(query);
00387 const T* dPtr(bucket->pt);
00388 for (int i = 0; i < this->dim; ++i)
00389 {
00390 const T diff(*qPtr - *dPtr);
00391 dist += diff*diff;
00392 qPtr++; dPtr++;
00393 }
00394 if ((dist <= maxRadius2) &&
00395 (dist < heap.headValue()) &&
00396 (allowSelfMatch || (dist > numeric_limits<T>::epsilon()))
00397 )
00398 heap.replaceHead(bucket->index, dist);
00399 ++bucket;
00400 }
00401 return (unsigned long)(bucketSize);
00402 }
00403 else
00404 {
00405 const unsigned rightChild(getChildBucketSize(node.dimChildBucketSize));
00406 unsigned long leafVisitedCount(0);
00407 T& offcd(off[cd]);
00408
00409 const T old_off(offcd);
00410 const T new_off(query[cd] - node.cutVal);
00411 if (new_off > 0)
00412 {
00413 if (collectStatistics)
00414 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00415 else
00416 recurseKnn<allowSelfMatch, false>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00417 rd += - old_off*old_off + new_off*new_off;
00418 if ((rd <= maxRadius2) &&
00419 (rd * maxError2 < heap.headValue()))
00420 {
00421 offcd = new_off;
00422 if (collectStatistics)
00423 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, n + 1, rd, heap, off, maxError2, maxRadius2);
00424 else
00425 recurseKnn<allowSelfMatch, false>(query, n + 1, rd, heap, off, maxError2, maxRadius2);
00426 offcd = old_off;
00427 }
00428 }
00429 else
00430 {
00431 if (collectStatistics)
00432 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, n+1, rd, heap, off, maxError2, maxRadius2);
00433 else
00434 recurseKnn<allowSelfMatch, false>(query, n+1, rd, heap, off, maxError2, maxRadius2);
00435 rd += - old_off*old_off + new_off*new_off;
00436 if ((rd <= maxRadius2) &&
00437 (rd * maxError2 < heap.headValue()))
00438 {
00439 offcd = new_off;
00440 if (collectStatistics)
00441 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00442 else
00443 recurseKnn<allowSelfMatch, false>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00444 offcd = old_off;
00445 }
00446 }
00447 return leafVisitedCount;
00448 }
00449 }
00450
00451 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapSTL<int,float> >;
00452 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapBruteForceVector<int,float> >;
00453 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double> >;
00454 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double> >;
00455
00456 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapSTL<int,float>,Eigen::Matrix3Xf>;
00457 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapBruteForceVector<int,float>,Eigen::Matrix3Xf>;
00458 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double>,Eigen::Matrix3Xd>;
00459 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double>,Eigen::Matrix3Xd>;
00460
00461 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapSTL<int,float>,Eigen::Map<const Eigen::Matrix3Xf, Eigen::Aligned> >;
00462 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapBruteForceVector<int,float>,Eigen::Map<const Eigen::Matrix3Xf, Eigen::Aligned> >;
00463 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double>,Eigen::Map<const Eigen::Matrix3Xd, Eigen::Aligned> >;
00464 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double>,Eigen::Map<const Eigen::Matrix3Xd, Eigen::Aligned> >;
00465
00467 }