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 #ifdef HAVE_OPENMP
00041 #include <omp.h>
00042 #endif
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, typename CloudType>
00077 size_t argMax(const typename NearestNeighbourSearch<T, CloudType>::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, typename CloudType>
00094 pair<T,T> KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::getBounds(const BuildPointsIt first, const BuildPointsIt last, const unsigned dim)
00095 {
00096 T minVal(std::numeric_limits<T>::max());
00097 T maxVal(std::numeric_limits<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, typename CloudType>
00110 unsigned KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::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, CloudType>(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, typename CloudType>
00228 KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt(const CloudType& cloud, const Index dim, const unsigned creationOptionFlags, const Parameters& additionalParameters):
00229 NearestNeighbourSearch<T, CloudType>::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("Requested bucket size " + std::to_string(bucketSize) + ", but must be larger than 2");
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((0x1ULL << (32-dimBitCount)) - 1);
00246 const uint64_t estimatedNodeCount(cloud.cols() / (bucketSize / 2));
00247 if (estimatedNodeCount > maxNodeCount)
00248 {
00249 throw runtime_error("Cloud has a risk to have more nodes (" + std::to_string(estimatedNodeCount) + ") than the kd-tree allows (" + std::to_string(maxNodeCount) + "). "
00250 "The kd-tree has " + std::to_string(dimBitCount) + " bits for dimensions and " + std::to_string((32-dimBitCount)) + " bits for node indices");
00251 }
00252
00253
00254 BuildPoints buildPoints;
00255 buildPoints.reserve(cloud.cols());
00256 for (int i = 0; i < cloud.cols(); ++i)
00257 {
00258 const Vector& v(cloud.block(0,i,this->dim,1));
00259 buildPoints.push_back(i);
00260 #ifdef EIGEN3_API
00261 const_cast<Vector&>(minBound) = minBound.array().min(v.array());
00262 const_cast<Vector&>(maxBound) = maxBound.array().max(v.array());
00263 #else // EIGEN3_API
00264 const_cast<Vector&>(minBound) = minBound.cwise().min(v);
00265 const_cast<Vector&>(maxBound) = maxBound.cwise().max(v);
00266 #endif // EIGEN3_API
00267 }
00268
00269
00270 buildNodes(buildPoints.begin(), buildPoints.end(), minBound, maxBound);
00271 buildPoints.clear();
00272 }
00273
00274 template<typename T, typename Heap, typename CloudType>
00275 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
00276 {
00277 checkSizesKnn(query, indices, dists2, k, optionFlags);
00278
00279 const bool allowSelfMatch(optionFlags & NearestNeighbourSearch<T>::ALLOW_SELF_MATCH);
00280 const bool sortResults(optionFlags & NearestNeighbourSearch<T>::SORT_RESULTS);
00281 const bool collectStatistics(creationOptionFlags & NearestNeighbourSearch<T>::TOUCH_STATISTICS);
00282 const T maxRadius2(maxRadius * maxRadius);
00283 const T maxError2((1+epsilon)*(1+epsilon));
00284 const int colCount(query.cols());
00285
00286 assert(nodes.size() > 0);
00287
00288 IndexMatrix result(k, query.cols());
00289 unsigned long leafTouchedCount(0);
00290
00291 #pragma omp parallel
00292 {
00293
00294 Heap heap(k);
00295 std::vector<T> off(dim, 0);
00296
00297 #pragma omp for reduction(+:leafTouchedCount) schedule(guided,32)
00298 for (int i = 0; i < colCount; ++i)
00299 {
00300 leafTouchedCount += onePointKnn(query, indices, dists2, i, heap, off, maxError2, maxRadius2, allowSelfMatch, collectStatistics, sortResults);
00301 }
00302 }
00303 return leafTouchedCount;
00304 }
00305
00306 template<typename T, typename Heap, typename CloudType>
00307 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
00308 {
00309 checkSizesKnn(query, indices, dists2, k, optionFlags, &maxRadii);
00310
00311 const bool allowSelfMatch(optionFlags & NearestNeighbourSearch<T>::ALLOW_SELF_MATCH);
00312 const bool sortResults(optionFlags & NearestNeighbourSearch<T>::SORT_RESULTS);
00313 const bool collectStatistics(creationOptionFlags & NearestNeighbourSearch<T>::TOUCH_STATISTICS);
00314 const T maxError2((1+epsilon)*(1+epsilon));
00315 const int colCount(query.cols());
00316
00317 assert(nodes.size() > 0);
00318 IndexMatrix result(k, query.cols());
00319 unsigned long leafTouchedCount(0);
00320
00321 #pragma omp parallel
00322 {
00323
00324 Heap heap(k);
00325 std::vector<T> off(dim, 0);
00326
00327 #pragma omp for reduction(+:leafTouchedCount) schedule(guided,32)
00328 for (int i = 0; i < colCount; ++i)
00329 {
00330 const T maxRadius(maxRadii[i]);
00331 const T maxRadius2(maxRadius * maxRadius);
00332 leafTouchedCount += onePointKnn(query, indices, dists2, i, heap, off, maxError2, maxRadius2, allowSelfMatch, collectStatistics, sortResults);
00333 }
00334 }
00335 return leafTouchedCount;
00336 }
00337
00338 template<typename T, typename Heap, typename CloudType>
00339 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
00340 {
00341 fill(off.begin(), off.end(), static_cast<T>(0));
00342 heap.reset();
00343 unsigned long leafTouchedCount(0);
00344
00345 if (allowSelfMatch)
00346 {
00347 if (collectStatistics)
00348 leafTouchedCount += recurseKnn<true, true>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00349 else
00350 recurseKnn<true, false>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00351 }
00352 else
00353 {
00354 if (collectStatistics)
00355 leafTouchedCount += recurseKnn<false, true>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00356 else
00357 recurseKnn<false, false>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
00358 }
00359
00360 if (sortResults)
00361 heap.sort();
00362
00363 heap.getData(indices.col(i), dists2.col(i));
00364 return leafTouchedCount;
00365 }
00366
00367 template<typename T, typename Heap, typename CloudType> template<bool allowSelfMatch, bool collectStatistics>
00368 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
00369 {
00370 const Node& node(nodes[n]);
00371 const uint32_t cd(getDim(node.dimChildBucketSize));
00372
00373 if (cd == uint32_t(dim))
00374 {
00375
00376 const BucketEntry* bucket(&buckets[node.bucketIndex]);
00377 const uint32_t bucketSize(getChildBucketSize(node.dimChildBucketSize));
00378 for (uint32_t i = 0; i < bucketSize; ++i)
00379 {
00380
00381
00382
00383 T dist(0);
00384 const T* qPtr(query);
00385 const T* dPtr(bucket->pt);
00386 for (int i = 0; i < this->dim; ++i)
00387 {
00388 const T diff(*qPtr - *dPtr);
00389 dist += diff*diff;
00390 qPtr++; dPtr++;
00391 }
00392 if ((dist <= maxRadius2) &&
00393 (dist < heap.headValue()) &&
00394 (allowSelfMatch || (dist > numeric_limits<T>::epsilon()))
00395 )
00396 heap.replaceHead(bucket->index, dist);
00397 ++bucket;
00398 }
00399 return (unsigned long)(bucketSize);
00400 }
00401 else
00402 {
00403 const unsigned rightChild(getChildBucketSize(node.dimChildBucketSize));
00404 unsigned long leafVisitedCount(0);
00405 T& offcd(off[cd]);
00406
00407 const T old_off(offcd);
00408 const T new_off(query[cd] - node.cutVal);
00409 if (new_off > 0)
00410 {
00411 if (collectStatistics)
00412 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00413 else
00414 recurseKnn<allowSelfMatch, false>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00415 rd += - old_off*old_off + new_off*new_off;
00416 if ((rd <= maxRadius2) &&
00417 (rd * maxError2 < heap.headValue()))
00418 {
00419 offcd = new_off;
00420 if (collectStatistics)
00421 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, n + 1, rd, heap, off, maxError2, maxRadius2);
00422 else
00423 recurseKnn<allowSelfMatch, false>(query, n + 1, rd, heap, off, maxError2, maxRadius2);
00424 offcd = old_off;
00425 }
00426 }
00427 else
00428 {
00429 if (collectStatistics)
00430 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, n+1, rd, heap, off, maxError2, maxRadius2);
00431 else
00432 recurseKnn<allowSelfMatch, false>(query, n+1, rd, heap, off, maxError2, maxRadius2);
00433 rd += - old_off*old_off + new_off*new_off;
00434 if ((rd <= maxRadius2) &&
00435 (rd * maxError2 < heap.headValue()))
00436 {
00437 offcd = new_off;
00438 if (collectStatistics)
00439 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00440 else
00441 recurseKnn<allowSelfMatch, false>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
00442 offcd = old_off;
00443 }
00444 }
00445 return leafVisitedCount;
00446 }
00447 }
00448
00449 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapSTL<int,float> >;
00450 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapBruteForceVector<int,float> >;
00451 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double> >;
00452 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double> >;
00453
00454 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapSTL<int,float>,Eigen::Matrix3Xf>;
00455 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapBruteForceVector<int,float>,Eigen::Matrix3Xf>;
00456 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double>,Eigen::Matrix3Xd>;
00457 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double>,Eigen::Matrix3Xd>;
00458
00459 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapSTL<int,float>,Eigen::Map<const Eigen::Matrix3Xf, Eigen::Aligned> >;
00460 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<float,IndexHeapBruteForceVector<int,float>,Eigen::Map<const Eigen::Matrix3Xf, Eigen::Aligned> >;
00461 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double>,Eigen::Map<const Eigen::Matrix3Xd, Eigen::Aligned> >;
00462 template struct KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double>,Eigen::Map<const Eigen::Matrix3Xd, Eigen::Aligned> >;
00463
00465 }
00466