Home | History | Annotate | Download | only in src
      1 #include "precomp.hpp"
      2 
      3 #define MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 0
      4 
      5 static cvflann::IndexParams& get_params(const cv::flann::IndexParams& p)
      6 {
      7     return *(cvflann::IndexParams*)(p.params);
      8 }
      9 
     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 
     23 IndexParams::IndexParams()
     24 {
     25     params = new ::cvflann::IndexParams();
     26 }
     27 
     28 template<typename 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>
     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 
     45 String IndexParams::getString(const String& key, const String& defaultVal) const
     46 {
     47     return getParam(*this, key, defaultVal);
     48 }
     49 
     50 int IndexParams::getInt(const String& key, int defaultVal) const
     51 {
     52     return getParam(*this, key, defaultVal);
     53 }
     54 
     55 double IndexParams::getDouble(const String& key, double defaultVal) const
     56 {
     57     return getParam(*this, key, defaultVal);
     58 }
     59 
     60 
     61 void IndexParams::setString(const String& key, const String& value)
     62 {
     63     setParam(*this, key, value);
     64 }
     65 
     66 void IndexParams::setInt(const String& key, int value)
     67 {
     68     setParam(*this, key, value);
     69 }
     70 
     71 void IndexParams::setDouble(const String& key, double value)
     72 {
     73     setParam(*this, key, value);
     74 }
     75 
     76 void IndexParams::setFloat(const String& key, float value)
     77 {
     78     setParam(*this, key, value);
     79 }
     80 
     81 void IndexParams::setBool(const String& key, bool value)
     82 {
     83     setParam(*this, key, value);
     84 }
     85 
     86 void IndexParams::setAlgorithm(int value)
     87 {
     88     setParam(*this, "algorithm", (cvflann::flann_algorithm_t)value);
     89 }
     90 
     91 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 
    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 
    206 LinearIndexParams::LinearIndexParams()
    207 {
    208     ::cvflann::IndexParams& p = get_params(*this);
    209     p["algorithm"] = FLANN_INDEX_LINEAR;
    210 }
    211 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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 
    337 Index::Index()
    338 {
    339     index = 0;
    340     featureType = CV_32F;
    341     algo = FLANN_INDEX_LINEAR;
    342     distType = FLANN_DIST_L2;
    343 }
    344 
    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 
    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 
    407 template<typename IndexType> void deleteIndex_(void* index)
    408 {
    409     delete (IndexType*)index;
    410 }
    411 
    412 template<typename Distance> void deleteIndex(void* index)
    413 {
    414     deleteIndex_< ::cvflann::Index<Distance> >(index);
    415 }
    416 
    417 Index::~Index()
    418 {
    419     release();
    420 }
    421 
    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>
    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>
    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>
    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>
    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 
    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 
    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 
    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 
    631 flann_distance_t Index::getDistance() const
    632 {
    633     return distType;
    634 }
    635 
    636 flann_algorithm_t Index::getAlgorithm() const
    637 {
    638     return algo;
    639 }
    640 
    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 
    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 
    657 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>
    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>
    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 
    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