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