1 #include "precomp.hpp"
2
3 #define MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 0
4
get_params(const cv::flann::IndexParams & p)5 static cvflann::IndexParams& get_params(const cv::flann::IndexParams& p)
6 {
7 return *(cvflann::IndexParams*)(p.params);
8 }
9
~IndexParams()10 cv::flann::IndexParams::~IndexParams()
11 {
12 delete &get_params(*this);
13 }
14
15 namespace cv
16 {
17
18 namespace flann
19 {
20
21 using namespace cvflann;
22
IndexParams()23 IndexParams::IndexParams()
24 {
25 params = new ::cvflann::IndexParams();
26 }
27
28 template<typename T>
getParam(const IndexParams & _p,const String & key,const T & defaultVal=T ())29 T getParam(const IndexParams& _p, const String& key, const T& defaultVal=T())
30 {
31 ::cvflann::IndexParams& p = get_params(_p);
32 ::cvflann::IndexParams::const_iterator it = p.find(key);
33 if( it == p.end() )
34 return defaultVal;
35 return it->second.cast<T>();
36 }
37
38 template<typename T>
setParam(IndexParams & _p,const String & key,const T & value)39 void setParam(IndexParams& _p, const String& key, const T& value)
40 {
41 ::cvflann::IndexParams& p = get_params(_p);
42 p[key] = value;
43 }
44
getString(const String & key,const String & defaultVal) const45 String IndexParams::getString(const String& key, const String& defaultVal) const
46 {
47 return getParam(*this, key, defaultVal);
48 }
49
getInt(const String & key,int defaultVal) const50 int IndexParams::getInt(const String& key, int defaultVal) const
51 {
52 return getParam(*this, key, defaultVal);
53 }
54
getDouble(const String & key,double defaultVal) const55 double IndexParams::getDouble(const String& key, double defaultVal) const
56 {
57 return getParam(*this, key, defaultVal);
58 }
59
60
setString(const String & key,const String & value)61 void IndexParams::setString(const String& key, const String& value)
62 {
63 setParam(*this, key, value);
64 }
65
setInt(const String & key,int value)66 void IndexParams::setInt(const String& key, int value)
67 {
68 setParam(*this, key, value);
69 }
70
setDouble(const String & key,double value)71 void IndexParams::setDouble(const String& key, double value)
72 {
73 setParam(*this, key, value);
74 }
75
setFloat(const String & key,float value)76 void IndexParams::setFloat(const String& key, float value)
77 {
78 setParam(*this, key, value);
79 }
80
setBool(const String & key,bool value)81 void IndexParams::setBool(const String& key, bool value)
82 {
83 setParam(*this, key, value);
84 }
85
setAlgorithm(int value)86 void IndexParams::setAlgorithm(int value)
87 {
88 setParam(*this, "algorithm", (cvflann::flann_algorithm_t)value);
89 }
90
getAll(std::vector<String> & names,std::vector<int> & types,std::vector<String> & strValues,std::vector<double> & numValues) const91 void IndexParams::getAll(std::vector<String>& names,
92 std::vector<int>& types,
93 std::vector<String>& strValues,
94 std::vector<double>& numValues) const
95 {
96 names.clear();
97 types.clear();
98 strValues.clear();
99 numValues.clear();
100
101 ::cvflann::IndexParams& p = get_params(*this);
102 ::cvflann::IndexParams::const_iterator it = p.begin(), it_end = p.end();
103
104 for( ; it != it_end; ++it )
105 {
106 names.push_back(it->first);
107 try
108 {
109 String val = it->second.cast<String>();
110 types.push_back(CV_USRTYPE1);
111 strValues.push_back(val);
112 numValues.push_back(-1);
113 continue;
114 }
115 catch (...) {}
116
117 strValues.push_back(it->second.type().name());
118
119 try
120 {
121 double val = it->second.cast<double>();
122 types.push_back( CV_64F );
123 numValues.push_back(val);
124 continue;
125 }
126 catch (...) {}
127 try
128 {
129 float val = it->second.cast<float>();
130 types.push_back( CV_32F );
131 numValues.push_back(val);
132 continue;
133 }
134 catch (...) {}
135 try
136 {
137 int val = it->second.cast<int>();
138 types.push_back( CV_32S );
139 numValues.push_back(val);
140 continue;
141 }
142 catch (...) {}
143 try
144 {
145 short val = it->second.cast<short>();
146 types.push_back( CV_16S );
147 numValues.push_back(val);
148 continue;
149 }
150 catch (...) {}
151 try
152 {
153 ushort val = it->second.cast<ushort>();
154 types.push_back( CV_16U );
155 numValues.push_back(val);
156 continue;
157 }
158 catch (...) {}
159 try
160 {
161 char val = it->second.cast<char>();
162 types.push_back( CV_8S );
163 numValues.push_back(val);
164 continue;
165 }
166 catch (...) {}
167 try
168 {
169 uchar val = it->second.cast<uchar>();
170 types.push_back( CV_8U );
171 numValues.push_back(val);
172 continue;
173 }
174 catch (...) {}
175 try
176 {
177 bool val = it->second.cast<bool>();
178 types.push_back( CV_MAKETYPE(CV_USRTYPE1,2) );
179 numValues.push_back(val);
180 continue;
181 }
182 catch (...) {}
183 try
184 {
185 cvflann::flann_algorithm_t val = it->second.cast<cvflann::flann_algorithm_t>();
186 types.push_back( CV_MAKETYPE(CV_USRTYPE1,3) );
187 numValues.push_back(val);
188 continue;
189 }
190 catch (...) {}
191
192
193 types.push_back(-1); // unknown type
194 numValues.push_back(-1);
195 }
196 }
197
198
KDTreeIndexParams(int trees)199 KDTreeIndexParams::KDTreeIndexParams(int trees)
200 {
201 ::cvflann::IndexParams& p = get_params(*this);
202 p["algorithm"] = FLANN_INDEX_KDTREE;
203 p["trees"] = trees;
204 }
205
LinearIndexParams()206 LinearIndexParams::LinearIndexParams()
207 {
208 ::cvflann::IndexParams& p = get_params(*this);
209 p["algorithm"] = FLANN_INDEX_LINEAR;
210 }
211
CompositeIndexParams(int trees,int branching,int iterations,flann_centers_init_t centers_init,float cb_index)212 CompositeIndexParams::CompositeIndexParams(int trees, int branching, int iterations,
213 flann_centers_init_t centers_init, float cb_index )
214 {
215 ::cvflann::IndexParams& p = get_params(*this);
216 p["algorithm"] = FLANN_INDEX_KMEANS;
217 // number of randomized trees to use (for kdtree)
218 p["trees"] = trees;
219 // branching factor
220 p["branching"] = branching;
221 // max iterations to perform in one kmeans clustering (kmeans tree)
222 p["iterations"] = iterations;
223 // algorithm used for picking the initial cluster centers for kmeans tree
224 p["centers_init"] = centers_init;
225 // cluster boundary index. Used when searching the kmeans tree
226 p["cb_index"] = cb_index;
227 }
228
AutotunedIndexParams(float target_precision,float build_weight,float memory_weight,float sample_fraction)229 AutotunedIndexParams::AutotunedIndexParams(float target_precision, float build_weight,
230 float memory_weight, float sample_fraction)
231 {
232 ::cvflann::IndexParams& p = get_params(*this);
233 p["algorithm"] = FLANN_INDEX_AUTOTUNED;
234 // precision desired (used for autotuning, -1 otherwise)
235 p["target_precision"] = target_precision;
236 // build tree time weighting factor
237 p["build_weight"] = build_weight;
238 // index memory weighting factor
239 p["memory_weight"] = memory_weight;
240 // what fraction of the dataset to use for autotuning
241 p["sample_fraction"] = sample_fraction;
242 }
243
244
KMeansIndexParams(int branching,int iterations,flann_centers_init_t centers_init,float cb_index)245 KMeansIndexParams::KMeansIndexParams(int branching, int iterations,
246 flann_centers_init_t centers_init, float cb_index )
247 {
248 ::cvflann::IndexParams& p = get_params(*this);
249 p["algorithm"] = FLANN_INDEX_KMEANS;
250 // branching factor
251 p["branching"] = branching;
252 // max iterations to perform in one kmeans clustering (kmeans tree)
253 p["iterations"] = iterations;
254 // algorithm used for picking the initial cluster centers for kmeans tree
255 p["centers_init"] = centers_init;
256 // cluster boundary index. Used when searching the kmeans tree
257 p["cb_index"] = cb_index;
258 }
259
HierarchicalClusteringIndexParams(int branching,flann_centers_init_t centers_init,int trees,int leaf_size)260 HierarchicalClusteringIndexParams::HierarchicalClusteringIndexParams(int branching ,
261 flann_centers_init_t centers_init,
262 int trees, int leaf_size)
263 {
264 ::cvflann::IndexParams& p = get_params(*this);
265 p["algorithm"] = FLANN_INDEX_HIERARCHICAL;
266 // The branching factor used in the hierarchical clustering
267 p["branching"] = branching;
268 // Algorithm used for picking the initial cluster centers
269 p["centers_init"] = centers_init;
270 // number of parallel trees to build
271 p["trees"] = trees;
272 // maximum leaf size
273 p["leaf_size"] = leaf_size;
274 }
275
LshIndexParams(int table_number,int key_size,int multi_probe_level)276 LshIndexParams::LshIndexParams(int table_number, int key_size, int multi_probe_level)
277 {
278 ::cvflann::IndexParams& p = get_params(*this);
279 p["algorithm"] = FLANN_INDEX_LSH;
280 // The number of hash tables to use
281 p["table_number"] = table_number;
282 // The length of the key in the hash tables
283 p["key_size"] = key_size;
284 // Number of levels to use in multi-probe (0 for standard LSH)
285 p["multi_probe_level"] = multi_probe_level;
286 }
287
SavedIndexParams(const String & _filename)288 SavedIndexParams::SavedIndexParams(const String& _filename)
289 {
290 String filename = _filename;
291 ::cvflann::IndexParams& p = get_params(*this);
292
293 p["algorithm"] = FLANN_INDEX_SAVED;
294 p["filename"] = filename;
295 }
296
SearchParams(int checks,float eps,bool sorted)297 SearchParams::SearchParams( int checks, float eps, bool sorted )
298 {
299 ::cvflann::IndexParams& p = get_params(*this);
300
301 // how many leafs to visit when searching for neighbours (-1 for unlimited)
302 p["checks"] = checks;
303 // search for eps-approximate neighbours (default: 0)
304 p["eps"] = eps;
305 // only for radius search, require neighbours sorted by distance (default: true)
306 p["sorted"] = sorted;
307 }
308
309
310 template<typename Distance, typename IndexType> void
buildIndex_(void * & index,const Mat & data,const IndexParams & params,const Distance & dist=Distance ())311 buildIndex_(void*& index, const Mat& data, const IndexParams& params, const Distance& dist = Distance())
312 {
313 typedef typename Distance::ElementType ElementType;
314 if(DataType<ElementType>::type != data.type())
315 CV_Error_(Error::StsUnsupportedFormat, ("type=%d\n", data.type()));
316 if(!data.isContinuous())
317 CV_Error(Error::StsBadArg, "Only continuous arrays are supported");
318
319 ::cvflann::Matrix<ElementType> dataset((ElementType*)data.data, data.rows, data.cols);
320 IndexType* _index = new IndexType(dataset, get_params(params), dist);
321 _index->buildIndex();
322 index = _index;
323 }
324
325 template<typename Distance> void
buildIndex(void * & index,const Mat & data,const IndexParams & params,const Distance & dist=Distance ())326 buildIndex(void*& index, const Mat& data, const IndexParams& params, const Distance& dist = Distance())
327 {
328 buildIndex_<Distance, ::cvflann::Index<Distance> >(index, data, params, dist);
329 }
330
331 #if CV_NEON
332 typedef ::cvflann::Hamming<uchar> HammingDistance;
333 #else
334 typedef ::cvflann::HammingLUT HammingDistance;
335 #endif
336
Index()337 Index::Index()
338 {
339 index = 0;
340 featureType = CV_32F;
341 algo = FLANN_INDEX_LINEAR;
342 distType = FLANN_DIST_L2;
343 }
344
Index(InputArray _data,const IndexParams & params,flann_distance_t _distType)345 Index::Index(InputArray _data, const IndexParams& params, flann_distance_t _distType)
346 {
347 index = 0;
348 featureType = CV_32F;
349 algo = FLANN_INDEX_LINEAR;
350 distType = FLANN_DIST_L2;
351 build(_data, params, _distType);
352 }
353
build(InputArray _data,const IndexParams & params,flann_distance_t _distType)354 void Index::build(InputArray _data, const IndexParams& params, flann_distance_t _distType)
355 {
356 release();
357 algo = getParam<flann_algorithm_t>(params, "algorithm", FLANN_INDEX_LINEAR);
358 if( algo == FLANN_INDEX_SAVED )
359 {
360 load(_data, getParam<String>(params, "filename", String()));
361 return;
362 }
363
364 Mat data = _data.getMat();
365 index = 0;
366 featureType = data.type();
367 distType = _distType;
368
369 if ( algo == FLANN_INDEX_LSH)
370 {
371 distType = FLANN_DIST_HAMMING;
372 }
373
374 switch( distType )
375 {
376 case FLANN_DIST_HAMMING:
377 buildIndex< HammingDistance >(index, data, params);
378 break;
379 case FLANN_DIST_L2:
380 buildIndex< ::cvflann::L2<float> >(index, data, params);
381 break;
382 case FLANN_DIST_L1:
383 buildIndex< ::cvflann::L1<float> >(index, data, params);
384 break;
385 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES
386 case FLANN_DIST_MAX:
387 buildIndex< ::cvflann::MaxDistance<float> >(index, data, params);
388 break;
389 case FLANN_DIST_HIST_INTERSECT:
390 buildIndex< ::cvflann::HistIntersectionDistance<float> >(index, data, params);
391 break;
392 case FLANN_DIST_HELLINGER:
393 buildIndex< ::cvflann::HellingerDistance<float> >(index, data, params);
394 break;
395 case FLANN_DIST_CHI_SQUARE:
396 buildIndex< ::cvflann::ChiSquareDistance<float> >(index, data, params);
397 break;
398 case FLANN_DIST_KL:
399 buildIndex< ::cvflann::KL_Divergence<float> >(index, data, params);
400 break;
401 #endif
402 default:
403 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type");
404 }
405 }
406
deleteIndex_(void * index)407 template<typename IndexType> void deleteIndex_(void* index)
408 {
409 delete (IndexType*)index;
410 }
411
deleteIndex(void * index)412 template<typename Distance> void deleteIndex(void* index)
413 {
414 deleteIndex_< ::cvflann::Index<Distance> >(index);
415 }
416
~Index()417 Index::~Index()
418 {
419 release();
420 }
421
release()422 void Index::release()
423 {
424 if( !index )
425 return;
426
427 switch( distType )
428 {
429 case FLANN_DIST_HAMMING:
430 deleteIndex< HammingDistance >(index);
431 break;
432 case FLANN_DIST_L2:
433 deleteIndex< ::cvflann::L2<float> >(index);
434 break;
435 case FLANN_DIST_L1:
436 deleteIndex< ::cvflann::L1<float> >(index);
437 break;
438 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES
439 case FLANN_DIST_MAX:
440 deleteIndex< ::cvflann::MaxDistance<float> >(index);
441 break;
442 case FLANN_DIST_HIST_INTERSECT:
443 deleteIndex< ::cvflann::HistIntersectionDistance<float> >(index);
444 break;
445 case FLANN_DIST_HELLINGER:
446 deleteIndex< ::cvflann::HellingerDistance<float> >(index);
447 break;
448 case FLANN_DIST_CHI_SQUARE:
449 deleteIndex< ::cvflann::ChiSquareDistance<float> >(index);
450 break;
451 case FLANN_DIST_KL:
452 deleteIndex< ::cvflann::KL_Divergence<float> >(index);
453 break;
454 #endif
455 default:
456 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type");
457 }
458 index = 0;
459 }
460
461 template<typename Distance, typename IndexType>
runKnnSearch_(void * index,const Mat & query,Mat & indices,Mat & dists,int knn,const SearchParams & params)462 void runKnnSearch_(void* index, const Mat& query, Mat& indices, Mat& dists,
463 int knn, const SearchParams& params)
464 {
465 typedef typename Distance::ElementType ElementType;
466 typedef typename Distance::ResultType DistanceType;
467 int type = DataType<ElementType>::type;
468 int dtype = DataType<DistanceType>::type;
469 CV_Assert(query.type() == type && indices.type() == CV_32S && dists.type() == dtype);
470 CV_Assert(query.isContinuous() && indices.isContinuous() && dists.isContinuous());
471
472 ::cvflann::Matrix<ElementType> _query((ElementType*)query.data, query.rows, query.cols);
473 ::cvflann::Matrix<int> _indices(indices.ptr<int>(), indices.rows, indices.cols);
474 ::cvflann::Matrix<DistanceType> _dists(dists.ptr<DistanceType>(), dists.rows, dists.cols);
475
476 ((IndexType*)index)->knnSearch(_query, _indices, _dists, knn,
477 (const ::cvflann::SearchParams&)get_params(params));
478 }
479
480 template<typename Distance>
runKnnSearch(void * index,const Mat & query,Mat & indices,Mat & dists,int knn,const SearchParams & params)481 void runKnnSearch(void* index, const Mat& query, Mat& indices, Mat& dists,
482 int knn, const SearchParams& params)
483 {
484 runKnnSearch_<Distance, ::cvflann::Index<Distance> >(index, query, indices, dists, knn, params);
485 }
486
487 template<typename Distance, typename IndexType>
runRadiusSearch_(void * index,const Mat & query,Mat & indices,Mat & dists,double radius,const SearchParams & params)488 int runRadiusSearch_(void* index, const Mat& query, Mat& indices, Mat& dists,
489 double radius, const SearchParams& params)
490 {
491 typedef typename Distance::ElementType ElementType;
492 typedef typename Distance::ResultType DistanceType;
493 int type = DataType<ElementType>::type;
494 int dtype = DataType<DistanceType>::type;
495 CV_Assert(query.type() == type && indices.type() == CV_32S && dists.type() == dtype);
496 CV_Assert(query.isContinuous() && indices.isContinuous() && dists.isContinuous());
497
498 ::cvflann::Matrix<ElementType> _query((ElementType*)query.data, query.rows, query.cols);
499 ::cvflann::Matrix<int> _indices(indices.ptr<int>(), indices.rows, indices.cols);
500 ::cvflann::Matrix<DistanceType> _dists(dists.ptr<DistanceType>(), dists.rows, dists.cols);
501
502 return ((IndexType*)index)->radiusSearch(_query, _indices, _dists,
503 saturate_cast<float>(radius),
504 (const ::cvflann::SearchParams&)get_params(params));
505 }
506
507 template<typename Distance>
runRadiusSearch(void * index,const Mat & query,Mat & indices,Mat & dists,double radius,const SearchParams & params)508 int runRadiusSearch(void* index, const Mat& query, Mat& indices, Mat& dists,
509 double radius, const SearchParams& params)
510 {
511 return runRadiusSearch_<Distance, ::cvflann::Index<Distance> >(index, query, indices, dists, radius, params);
512 }
513
514
createIndicesDists(OutputArray _indices,OutputArray _dists,Mat & indices,Mat & dists,int rows,int minCols,int maxCols,int dtype)515 static void createIndicesDists(OutputArray _indices, OutputArray _dists,
516 Mat& indices, Mat& dists, int rows,
517 int minCols, int maxCols, int dtype)
518 {
519 if( _indices.needed() )
520 {
521 indices = _indices.getMat();
522 if( !indices.isContinuous() || indices.type() != CV_32S ||
523 indices.rows != rows || indices.cols < minCols || indices.cols > maxCols )
524 {
525 if( !indices.isContinuous() )
526 _indices.release();
527 _indices.create( rows, minCols, CV_32S );
528 indices = _indices.getMat();
529 }
530 }
531 else
532 indices.create( rows, minCols, CV_32S );
533
534 if( _dists.needed() )
535 {
536 dists = _dists.getMat();
537 if( !dists.isContinuous() || dists.type() != dtype ||
538 dists.rows != rows || dists.cols < minCols || dists.cols > maxCols )
539 {
540 if( !indices.isContinuous() )
541 _dists.release();
542 _dists.create( rows, minCols, dtype );
543 dists = _dists.getMat();
544 }
545 }
546 else
547 dists.create( rows, minCols, dtype );
548 }
549
550
knnSearch(InputArray _query,OutputArray _indices,OutputArray _dists,int knn,const SearchParams & params)551 void Index::knnSearch(InputArray _query, OutputArray _indices,
552 OutputArray _dists, int knn, const SearchParams& params)
553 {
554 Mat query = _query.getMat(), indices, dists;
555 int dtype = distType == FLANN_DIST_HAMMING ? CV_32S : CV_32F;
556
557 createIndicesDists( _indices, _dists, indices, dists, query.rows, knn, knn, dtype );
558
559 switch( distType )
560 {
561 case FLANN_DIST_HAMMING:
562 runKnnSearch<HammingDistance>(index, query, indices, dists, knn, params);
563 break;
564 case FLANN_DIST_L2:
565 runKnnSearch< ::cvflann::L2<float> >(index, query, indices, dists, knn, params);
566 break;
567 case FLANN_DIST_L1:
568 runKnnSearch< ::cvflann::L1<float> >(index, query, indices, dists, knn, params);
569 break;
570 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES
571 case FLANN_DIST_MAX:
572 runKnnSearch< ::cvflann::MaxDistance<float> >(index, query, indices, dists, knn, params);
573 break;
574 case FLANN_DIST_HIST_INTERSECT:
575 runKnnSearch< ::cvflann::HistIntersectionDistance<float> >(index, query, indices, dists, knn, params);
576 break;
577 case FLANN_DIST_HELLINGER:
578 runKnnSearch< ::cvflann::HellingerDistance<float> >(index, query, indices, dists, knn, params);
579 break;
580 case FLANN_DIST_CHI_SQUARE:
581 runKnnSearch< ::cvflann::ChiSquareDistance<float> >(index, query, indices, dists, knn, params);
582 break;
583 case FLANN_DIST_KL:
584 runKnnSearch< ::cvflann::KL_Divergence<float> >(index, query, indices, dists, knn, params);
585 break;
586 #endif
587 default:
588 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type");
589 }
590 }
591
radiusSearch(InputArray _query,OutputArray _indices,OutputArray _dists,double radius,int maxResults,const SearchParams & params)592 int Index::radiusSearch(InputArray _query, OutputArray _indices,
593 OutputArray _dists, double radius, int maxResults,
594 const SearchParams& params)
595 {
596 Mat query = _query.getMat(), indices, dists;
597 int dtype = distType == FLANN_DIST_HAMMING ? CV_32S : CV_32F;
598 CV_Assert( maxResults > 0 );
599 createIndicesDists( _indices, _dists, indices, dists, query.rows, maxResults, INT_MAX, dtype );
600
601 if( algo == FLANN_INDEX_LSH )
602 CV_Error( Error::StsNotImplemented, "LSH index does not support radiusSearch operation" );
603
604 switch( distType )
605 {
606 case FLANN_DIST_HAMMING:
607 return runRadiusSearch< HammingDistance >(index, query, indices, dists, radius, params);
608
609 case FLANN_DIST_L2:
610 return runRadiusSearch< ::cvflann::L2<float> >(index, query, indices, dists, radius, params);
611 case FLANN_DIST_L1:
612 return runRadiusSearch< ::cvflann::L1<float> >(index, query, indices, dists, radius, params);
613 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES
614 case FLANN_DIST_MAX:
615 return runRadiusSearch< ::cvflann::MaxDistance<float> >(index, query, indices, dists, radius, params);
616 case FLANN_DIST_HIST_INTERSECT:
617 return runRadiusSearch< ::cvflann::HistIntersectionDistance<float> >(index, query, indices, dists, radius, params);
618 case FLANN_DIST_HELLINGER:
619 return runRadiusSearch< ::cvflann::HellingerDistance<float> >(index, query, indices, dists, radius, params);
620 case FLANN_DIST_CHI_SQUARE:
621 return runRadiusSearch< ::cvflann::ChiSquareDistance<float> >(index, query, indices, dists, radius, params);
622 case FLANN_DIST_KL:
623 return runRadiusSearch< ::cvflann::KL_Divergence<float> >(index, query, indices, dists, radius, params);
624 #endif
625 default:
626 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type");
627 }
628 return -1;
629 }
630
getDistance() const631 flann_distance_t Index::getDistance() const
632 {
633 return distType;
634 }
635
getAlgorithm() const636 flann_algorithm_t Index::getAlgorithm() const
637 {
638 return algo;
639 }
640
saveIndex_(const Index * index0,const void * index,FILE * fout)641 template<typename IndexType> void saveIndex_(const Index* index0, const void* index, FILE* fout)
642 {
643 IndexType* _index = (IndexType*)index;
644 ::cvflann::save_header(fout, *_index);
645 // some compilers may store short enumerations as bytes,
646 // so make sure we always write integers (which are 4-byte values in any modern C compiler)
647 int idistType = (int)index0->getDistance();
648 ::cvflann::save_value<int>(fout, idistType);
649 _index->saveIndex(fout);
650 }
651
saveIndex(const Index * index0,const void * index,FILE * fout)652 template<typename Distance> void saveIndex(const Index* index0, const void* index, FILE* fout)
653 {
654 saveIndex_< ::cvflann::Index<Distance> >(index0, index, fout);
655 }
656
save(const String & filename) const657 void Index::save(const String& filename) const
658 {
659 FILE* fout = fopen(filename.c_str(), "wb");
660 if (fout == NULL)
661 CV_Error_( Error::StsError, ("Can not open file %s for writing FLANN index\n", filename.c_str()) );
662
663 switch( distType )
664 {
665 case FLANN_DIST_HAMMING:
666 saveIndex< HammingDistance >(this, index, fout);
667 break;
668 case FLANN_DIST_L2:
669 saveIndex< ::cvflann::L2<float> >(this, index, fout);
670 break;
671 case FLANN_DIST_L1:
672 saveIndex< ::cvflann::L1<float> >(this, index, fout);
673 break;
674 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES
675 case FLANN_DIST_MAX:
676 saveIndex< ::cvflann::MaxDistance<float> >(this, index, fout);
677 break;
678 case FLANN_DIST_HIST_INTERSECT:
679 saveIndex< ::cvflann::HistIntersectionDistance<float> >(this, index, fout);
680 break;
681 case FLANN_DIST_HELLINGER:
682 saveIndex< ::cvflann::HellingerDistance<float> >(this, index, fout);
683 break;
684 case FLANN_DIST_CHI_SQUARE:
685 saveIndex< ::cvflann::ChiSquareDistance<float> >(this, index, fout);
686 break;
687 case FLANN_DIST_KL:
688 saveIndex< ::cvflann::KL_Divergence<float> >(this, index, fout);
689 break;
690 #endif
691 default:
692 fclose(fout);
693 fout = 0;
694 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type");
695 }
696 if( fout )
697 fclose(fout);
698 }
699
700
701 template<typename Distance, typename IndexType>
loadIndex_(Index * index0,void * & index,const Mat & data,FILE * fin,const Distance & dist=Distance ())702 bool loadIndex_(Index* index0, void*& index, const Mat& data, FILE* fin, const Distance& dist=Distance())
703 {
704 typedef typename Distance::ElementType ElementType;
705 CV_Assert(DataType<ElementType>::type == data.type() && data.isContinuous());
706
707 ::cvflann::Matrix<ElementType> dataset((ElementType*)data.data, data.rows, data.cols);
708
709 ::cvflann::IndexParams params;
710 params["algorithm"] = index0->getAlgorithm();
711 IndexType* _index = new IndexType(dataset, params, dist);
712 _index->loadIndex(fin);
713 index = _index;
714 return true;
715 }
716
717 template<typename Distance>
loadIndex(Index * index0,void * & index,const Mat & data,FILE * fin,const Distance & dist=Distance ())718 bool loadIndex(Index* index0, void*& index, const Mat& data, FILE* fin, const Distance& dist=Distance())
719 {
720 return loadIndex_<Distance, ::cvflann::Index<Distance> >(index0, index, data, fin, dist);
721 }
722
load(InputArray _data,const String & filename)723 bool Index::load(InputArray _data, const String& filename)
724 {
725 Mat data = _data.getMat();
726 bool ok = true;
727 release();
728 FILE* fin = fopen(filename.c_str(), "rb");
729 if (fin == NULL)
730 return false;
731
732 ::cvflann::IndexHeader header = ::cvflann::load_header(fin);
733 algo = header.index_type;
734 featureType = header.data_type == FLANN_UINT8 ? CV_8U :
735 header.data_type == FLANN_INT8 ? CV_8S :
736 header.data_type == FLANN_UINT16 ? CV_16U :
737 header.data_type == FLANN_INT16 ? CV_16S :
738 header.data_type == FLANN_INT32 ? CV_32S :
739 header.data_type == FLANN_FLOAT32 ? CV_32F :
740 header.data_type == FLANN_FLOAT64 ? CV_64F : -1;
741
742 if( (int)header.rows != data.rows || (int)header.cols != data.cols ||
743 featureType != data.type() )
744 {
745 fprintf(stderr, "Reading FLANN index error: the saved data size (%d, %d) or type (%d) is different from the passed one (%d, %d), %d\n",
746 (int)header.rows, (int)header.cols, featureType, data.rows, data.cols, data.type());
747 fclose(fin);
748 return false;
749 }
750
751 int idistType = 0;
752 ::cvflann::load_value(fin, idistType);
753 distType = (flann_distance_t)idistType;
754
755 if( !((distType == FLANN_DIST_HAMMING && featureType == CV_8U) ||
756 (distType != FLANN_DIST_HAMMING && featureType == CV_32F)) )
757 {
758 fprintf(stderr, "Reading FLANN index error: unsupported feature type %d for the index type %d\n", featureType, algo);
759 fclose(fin);
760 return false;
761 }
762
763 switch( distType )
764 {
765 case FLANN_DIST_HAMMING:
766 loadIndex< HammingDistance >(this, index, data, fin);
767 break;
768 case FLANN_DIST_L2:
769 loadIndex< ::cvflann::L2<float> >(this, index, data, fin);
770 break;
771 case FLANN_DIST_L1:
772 loadIndex< ::cvflann::L1<float> >(this, index, data, fin);
773 break;
774 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES
775 case FLANN_DIST_MAX:
776 loadIndex< ::cvflann::MaxDistance<float> >(this, index, data, fin);
777 break;
778 case FLANN_DIST_HIST_INTERSECT:
779 loadIndex< ::cvflann::HistIntersectionDistance<float> >(index, data, fin);
780 break;
781 case FLANN_DIST_HELLINGER:
782 loadIndex< ::cvflann::HellingerDistance<float> >(this, index, data, fin);
783 break;
784 case FLANN_DIST_CHI_SQUARE:
785 loadIndex< ::cvflann::ChiSquareDistance<float> >(this, index, data, fin);
786 break;
787 case FLANN_DIST_KL:
788 loadIndex< ::cvflann::KL_Divergence<float> >(this, index, data, fin);
789 break;
790 #endif
791 default:
792 fprintf(stderr, "Reading FLANN index error: unsupported distance type %d\n", distType);
793 ok = false;
794 }
795
796 if( fin )
797 fclose(fin);
798 return ok;
799 }
800
801 }
802
803 }
804