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