knnvalidate.cpp
Go to the documentation of this file.
1 /*
2 
3 Copyright (c) 2010--2011, Stephane Magnenat, ASL, ETHZ, Switzerland
4 You can contact the author at <stephane at magnenat dot net>
5 
6 All rights reserved.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10  * Redistributions of source code must retain the above copyright
11  notice, this list of conditions and the following disclaimer.
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15  * Neither the name of the <organization> nor the
16  names of its contributors may be used to endorse or promote products
17  derived from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 */
31 
32 #include "nabo/nabo.h"
33 #include "helpers.h"
34 //#include "experimental/nabo_experimental.h"
35 #include <iostream>
36 #include <fstream>
37 #include <stdexcept>
38 
39 using namespace std;
40 using namespace Nabo;
41 
42 template<typename T, typename CloudType>
43 struct Loader
44 {
45  void loadMatrix(const char *fileName)
46  {
47  data = load<T>(fileName);
48  }
49  CloudType getValue() const
50  {
51  return data;
52  }
53 private:
54  CloudType data;
55 };
56 
57 template<typename T>
58 struct Loader<T, Eigen::Map<const Eigen::Matrix<T, 3, Eigen::Dynamic>, Eigen::Aligned> >
59 {
60  void loadMatrix(const char *fileName)
61  {
62  data = load<T>(fileName);
63  }
64  Eigen::Map<const Eigen::Matrix<T, 3, Eigen::Dynamic>, Eigen::Aligned> getValue() const
65  {
66  return Eigen::Map<const Eigen::Matrix<T, 3, Eigen::Dynamic>, Eigen::Aligned>(data.data(), 3, data.cols());
67  }
68 
69 private:
70  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> data;
71 };
72 
73 template<typename T, typename CloudType>
74 void validate(const char *fileName, const int K, const int dim, const int method, const T maxRadius)
75 {
77  typedef vector<NNS*> NNSV;
78  typedef typename NNS::Matrix Matrix;
79  typedef typename NNS::Vector Vector;
80  typedef typename NNS::IndexMatrix IndexMatrix;
81 
82  Loader<T, CloudType> loader;
83  loader.loadMatrix(fileName);
84 
85  // check if file is ok
86  const CloudType d = loader.getValue();
87  if (d.rows() != dim)
88  {
89  cerr << "Provided data has " << d.rows() << " dimensions, but the requested dimensions were " << dim << endl;
90  exit(2);
91  }
92  if (K >= d.cols())
93  {
94  cerr << "Requested more nearest neighbour than points in the data set" << endl;
95  exit(2);
96  }
97 
98  // create different methods
99  NNSV nnss;
100  unsigned searchTypeCount(NNS::SEARCH_TYPE_COUNT);
101  #ifndef HAVE_OPENCL
102  searchTypeCount -= 3;
103  #endif // HAVE_OPENCL
104  for (unsigned i = 0; i < searchTypeCount; ++i)
105  nnss.push_back(NNS::create(d, d.rows(), typename NNS::SearchType(i)));
106  //nnss.push_back(new KDTreeBalancedPtInLeavesStack<T>(d, false));
107 
108 
109  // check methods together
110  const int itCount(method != -1 ? method : d.cols() * 2);
111 
112  /*
113  // element-by-element search
114  typedef typename NNS::IndexVector IndexVector;
115  for (int i = 0; i < itCount; ++i)
116  {
117  const Vector q(createQuery<T>(d, *nnss[0], i, method));
118  const IndexVector indexes_bf(nnss[0]->knn(q, K, 0, NNS::SORT_RESULTS));
119  for (size_t j = 1; j < nnss.size(); ++j)
120  {
121  const IndexVector indexes_kdtree(nnss[j]->knn(q, K, 0, NNS::SORT_RESULTS));
122  if (indexes_bf.size() != K)
123  {
124  cerr << "Different number of points found between brute force and request" << endl;
125  exit(3);
126  }
127  if (indexes_bf.size() != indexes_kdtree.size())
128  {
129  cerr << "Different number of points found between brute force and NNS type "<< j << endl;
130  exit(3);
131  }
132  for (size_t k = 0; k < size_t(K); ++k)
133  {
134  Vector pbf(d.col(indexes_bf[k]));
135  //cerr << indexes_kdtree[k] << endl;
136  Vector pkdtree(d.col(indexes_kdtree[k]));
137  if (fabsf((pbf-q).squaredNorm() - (pkdtree-q).squaredNorm()) >= numeric_limits<float>::epsilon())
138  {
139  cerr << "Method " << j << ", cloud point " << i << ", neighbour " << k << " of " << K << " is different between bf and kdtree (dist " << (pbf-pkdtree).norm() << ")\n";
140  cerr << "* query:\n";
141  cerr << q << "\n";
142  cerr << "* indexes " << indexes_bf[k] << " (bf) vs " << indexes_kdtree[k] << " (kdtree)\n";
143  cerr << "* coordinates:\n";
144  cerr << "bf: (dist " << (pbf-q).norm() << ")\n";
145  cerr << pbf << "\n";
146  cerr << "kdtree (dist " << (pkdtree-q).norm() << ")\n";
147  cerr << pkdtree << endl;
148  exit(4);
149  }
150  }
151  }
152  }
153  */
154  // create big query
155  // check all-in-one query
156  Matrix q(createQuery<T>(d, itCount, method));
157  IndexMatrix indexes_bf(K, q.cols());
158  Matrix dists2_bf(K, q.cols());
159  nnss[0]->knn(q, indexes_bf, dists2_bf, K, 0, NNS::SORT_RESULTS, maxRadius);
160  assert(indexes_bf.cols() == q.cols());
161  for (size_t j = 1; j < nnss.size(); ++j)
162  {
163  IndexMatrix indexes_kdtree(K, q.cols());
164  Matrix dists2_kdtree(K, q.cols());
165  nnss[j]->knn(q, indexes_kdtree, dists2_kdtree, K, 0, NNS::SORT_RESULTS, maxRadius);
166  if (indexes_bf.rows() != K)
167  {
168  cerr << "Different number of points found between brute force and request" << endl;
169  exit(3);
170  }
171  if (indexes_bf.cols() != indexes_kdtree.cols())
172  {
173  cerr << "Different number of points found between brute force and NNS type "<< j << endl;
174  exit(3);
175  }
176 
177  for (int i = 0; i < q.cols(); ++i)
178  {
179  for (size_t k = 0; k < size_t(K); ++k)
180  {
181  if (dists2_bf(k,i) == NNS::InvalidValue)
182  continue;
183  const int pbfi(indexes_bf(k,i));
184  const Vector pbf(d.col(pbfi));
185  const int pkdt(indexes_kdtree(k,i));
186  if (pkdt < 0 || pkdt >= d.cols())
187  {
188  cerr << "Method " << j << ", query point " << i << ", neighbour " << k << " of " << K << " has invalid index " << pkdt << " out of range [0:" << d.cols() << "[" << endl;
189  exit(4);
190  }
191  const Vector pkdtree(d.col(pkdt));
192  const Vector pq(q.col(i));
193  const T distDiff(fabsf((pbf-pq).squaredNorm() - (pkdtree-pq).squaredNorm()));
194  if (distDiff > numeric_limits<T>::epsilon())
195  {
196  cerr << "Method " << j << ", query point " << i << ", neighbour " << k << " of " << K << " is different between bf and kdtree (dist2 " << distDiff << ")\n";
197  cerr << "* query point:\n";
198  cerr << pq << "\n";
199  cerr << "* indexes " << pbfi << " (bf) vs " << pkdt << " (kdtree)\n";
200  cerr << "* coordinates:\n";
201  cerr << "bf: (dist " << (pbf-pq).norm() << ")\n";
202  cerr << pbf << "\n";
203  cerr << "kdtree (dist " << (pkdtree-pq).norm() << ")\n";
204  cerr << pkdtree << endl;
205  cerr << "* bf neighbours:\n";
206  for (int l = 0; l < K; ++l)
207  cerr << indexes_bf(l,i) << " (dist " << (d.col(indexes_bf(l,i))-pq).norm() << ")\n";
208  cerr << "* kdtree neighbours:\n";
209  for (int l = 0; l < K; ++l)
210  cerr << indexes_kdtree(l,i) << " (dist " << (d.col(indexes_kdtree(l,i))-pq).norm() << ")\n";
211  exit(4);
212  }
213  }
214  }
215  }
216 
217 // cout << "\tstats kdtree: "
218 // << kdt.getStatistics().totalVisitCount << " on "
219 // << (long long)(itCount) * (long long)(d.cols()) << " ("
220 // << (100. * double(kdt.getStatistics().totalVisitCount)) / (double(itCount) * double(d.cols())) << " %"
221 // << ")\n" << endl;
222 
223  // delete searches
224  for (typename NNSV::iterator it(nnss.begin()); it != nnss.end(); ++it)
225  delete (*it);
226 }
227 
228 int main(int argc, char* argv[])
229 {
230  if (argc < 4)
231  {
232  cerr << "Usage " << argv[0] << " DATA K DIM METHOD [MAX_RADIUS]" << endl;
233  return 1;
234  }
235 
236  const int K(atoi(argv[2]));
237  const int dim(atoi(argv[3]));
238  const int method(atoi(argv[4]));
239  const float maxRadius(argc >= 6 ? float(atof(argv[5])) : numeric_limits<float>::infinity());
240 
241  if (dim == 3)
242  {
243  validate<float, Eigen::MatrixXf>(argv[1], K, dim, method, maxRadius);
244  validate<float, Eigen::Matrix3Xf>(argv[1], K, dim, method, maxRadius);
245  validate<float, Eigen::Map<const Eigen::Matrix3Xf, Eigen::Aligned> >(argv[1], K, dim, method, maxRadius);
246  } else
247  {
248  validate<float, Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> >(argv[1], K, dim, method, maxRadius);
249  }
250  //validate<double>(argv[1], K, method);
251 
252  return 0;
253 }
CloudType getValue() const
Definition: knnvalidate.cpp:49
void validate(const char *fileName, const int K, const int dim, const int method, const T maxRadius)
Definition: knnvalidate.cpp:74
Definition: any.hpp:450
int main(int argc, char *argv[])
CloudType data
Definition: knnvalidate.cpp:54
Eigen::Map< const Eigen::Matrix< T, 3, Eigen::Dynamic >, Eigen::Aligned > getValue() const
Definition: knnvalidate.cpp:64
NNSNabo::SearchType SearchType
Definition: python/nabo.cpp:12
Namespace for Nabo.
public interface
void loadMatrix(const char *fileName)
Definition: knnvalidate.cpp:45
q
Definition: test.py:8


libnabo
Author(s): Stéphane Magnenat
autogenerated on Mon Feb 28 2022 22:41:38