Home | History | Annotate | Download | only in opencv2
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 #ifndef _OPENCV_FLANN_HPP_
     44 #define _OPENCV_FLANN_HPP_
     45 
     46 #include "opencv2/core.hpp"
     47 #include "opencv2/flann/miniflann.hpp"
     48 #include "opencv2/flann/flann_base.hpp"
     49 
     50 /**
     51 @defgroup flann Clustering and Search in Multi-Dimensional Spaces
     52 
     53 This section documents OpenCV's interface to the FLANN library. FLANN (Fast Library for Approximate
     54 Nearest Neighbors) is a library that contains a collection of algorithms optimized for fast nearest
     55 neighbor search in large datasets and for high dimensional features. More information about FLANN
     56 can be found in @cite Muja2009 .
     57 */
     58 
     59 namespace cvflann
     60 {
     61     CV_EXPORTS flann_distance_t flann_distance_type();
     62     FLANN_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order);
     63 }
     64 
     65 
     66 namespace cv
     67 {
     68 namespace flann
     69 {
     70 
     71 
     72 //! @addtogroup flann
     73 //! @{
     74 
     75 template <typename T> struct CvType {};
     76 template <> struct CvType<unsigned char> { static int type() { return CV_8U; } };
     77 template <> struct CvType<char> { static int type() { return CV_8S; } };
     78 template <> struct CvType<unsigned short> { static int type() { return CV_16U; } };
     79 template <> struct CvType<short> { static int type() { return CV_16S; } };
     80 template <> struct CvType<int> { static int type() { return CV_32S; } };
     81 template <> struct CvType<float> { static int type() { return CV_32F; } };
     82 template <> struct CvType<double> { static int type() { return CV_64F; } };
     83 
     84 
     85 // bring the flann parameters into this namespace
     86 using ::cvflann::get_param;
     87 using ::cvflann::print_params;
     88 
     89 // bring the flann distances into this namespace
     90 using ::cvflann::L2_Simple;
     91 using ::cvflann::L2;
     92 using ::cvflann::L1;
     93 using ::cvflann::MinkowskiDistance;
     94 using ::cvflann::MaxDistance;
     95 using ::cvflann::HammingLUT;
     96 using ::cvflann::Hamming;
     97 using ::cvflann::Hamming2;
     98 using ::cvflann::HistIntersectionDistance;
     99 using ::cvflann::HellingerDistance;
    100 using ::cvflann::ChiSquareDistance;
    101 using ::cvflann::KL_Divergence;
    102 
    103 
    104 /** @brief The FLANN nearest neighbor index class. This class is templated with the type of elements for which
    105 the index is built.
    106  */
    107 template <typename Distance>
    108 class GenericIndex
    109 {
    110 public:
    111         typedef typename Distance::ElementType ElementType;
    112         typedef typename Distance::ResultType DistanceType;
    113 
    114         /** @brief Constructs a nearest neighbor search index for a given dataset.
    115 
    116         @param features Matrix of containing the features(points) to index. The size of the matrix is
    117         num_features x feature_dimensionality and the data type of the elements in the matrix must
    118         coincide with the type of the index.
    119         @param params Structure containing the index parameters. The type of index that will be
    120         constructed depends on the type of this parameter. See the description.
    121         @param distance
    122 
    123         The method constructs a fast search structure from a set of features using the specified algorithm
    124         with specified parameters, as defined by params. params is a reference to one of the following class
    125         IndexParams descendants:
    126 
    127         - **LinearIndexParams** When passing an object of this type, the index will perform a linear,
    128         brute-force search. :
    129         @code
    130         struct LinearIndexParams : public IndexParams
    131         {
    132         };
    133         @endcode
    134         - **KDTreeIndexParams** When passing an object of this type the index constructed will consist of
    135         a set of randomized kd-trees which will be searched in parallel. :
    136         @code
    137         struct KDTreeIndexParams : public IndexParams
    138         {
    139             KDTreeIndexParams( int trees = 4 );
    140         };
    141         @endcode
    142         - **KMeansIndexParams** When passing an object of this type the index constructed will be a
    143         hierarchical k-means tree. :
    144         @code
    145         struct KMeansIndexParams : public IndexParams
    146         {
    147             KMeansIndexParams(
    148                 int branching = 32,
    149                 int iterations = 11,
    150                 flann_centers_init_t centers_init = CENTERS_RANDOM,
    151                 float cb_index = 0.2 );
    152         };
    153         @endcode
    154         - **CompositeIndexParams** When using a parameters object of this type the index created
    155         combines the randomized kd-trees and the hierarchical k-means tree. :
    156         @code
    157         struct CompositeIndexParams : public IndexParams
    158         {
    159             CompositeIndexParams(
    160                 int trees = 4,
    161                 int branching = 32,
    162                 int iterations = 11,
    163                 flann_centers_init_t centers_init = CENTERS_RANDOM,
    164                 float cb_index = 0.2 );
    165         };
    166         @endcode
    167         - **LshIndexParams** When using a parameters object of this type the index created uses
    168         multi-probe LSH (by Multi-Probe LSH: Efficient Indexing for High-Dimensional Similarity Search
    169         by Qin Lv, William Josephson, Zhe Wang, Moses Charikar, Kai Li., Proceedings of the 33rd
    170         International Conference on Very Large Data Bases (VLDB). Vienna, Austria. September 2007) :
    171         @code
    172         struct LshIndexParams : public IndexParams
    173         {
    174             LshIndexParams(
    175                 unsigned int table_number,
    176                 unsigned int key_size,
    177                 unsigned int multi_probe_level );
    178         };
    179         @endcode
    180         - **AutotunedIndexParams** When passing an object of this type the index created is
    181         automatically tuned to offer the best performance, by choosing the optimal index type
    182         (randomized kd-trees, hierarchical kmeans, linear) and parameters for the dataset provided. :
    183         @code
    184         struct AutotunedIndexParams : public IndexParams
    185         {
    186             AutotunedIndexParams(
    187                 float target_precision = 0.9,
    188                 float build_weight = 0.01,
    189                 float memory_weight = 0,
    190                 float sample_fraction = 0.1 );
    191         };
    192         @endcode
    193         - **SavedIndexParams** This object type is used for loading a previously saved index from the
    194         disk. :
    195         @code
    196         struct SavedIndexParams : public IndexParams
    197         {
    198             SavedIndexParams( String filename );
    199         };
    200         @endcode
    201          */
    202         GenericIndex(const Mat& features, const ::cvflann::IndexParams& params, Distance distance = Distance());
    203 
    204         ~GenericIndex();
    205 
    206         /** @brief Performs a K-nearest neighbor search for a given query point using the index.
    207 
    208         @param query The query point
    209         @param indices Vector that will contain the indices of the K-nearest neighbors found. It must have
    210         at least knn size.
    211         @param dists Vector that will contain the distances to the K-nearest neighbors found. It must have
    212         at least knn size.
    213         @param knn Number of nearest neighbors to search for.
    214         @param params SearchParams
    215          */
    216         void knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices,
    217                        std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& params);
    218         void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params);
    219 
    220         int radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices,
    221                          std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& params);
    222         int radiusSearch(const Mat& query, Mat& indices, Mat& dists,
    223                          DistanceType radius, const ::cvflann::SearchParams& params);
    224 
    225         void save(String filename) { nnIndex->save(filename); }
    226 
    227         int veclen() const { return nnIndex->veclen(); }
    228 
    229         int size() const { return nnIndex->size(); }
    230 
    231         ::cvflann::IndexParams getParameters() { return nnIndex->getParameters(); }
    232 
    233         FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); }
    234 
    235 private:
    236         ::cvflann::Index<Distance>* nnIndex;
    237 };
    238 
    239 //! @cond IGNORED
    240 
    241 #define FLANN_DISTANCE_CHECK \
    242     if ( ::cvflann::flann_distance_type() != cvflann::FLANN_DIST_L2) { \
    243         printf("[WARNING] You are using cv::flann::Index (or cv::flann::GenericIndex) and have also changed "\
    244         "the distance using cvflann::set_distance_type. This is no longer working as expected "\
    245         "(cv::flann::Index always uses L2). You should create the index templated on the distance, "\
    246         "for example for L1 distance use: GenericIndex< L1<float> > \n"); \
    247     }
    248 
    249 
    250 template <typename Distance>
    251 GenericIndex<Distance>::GenericIndex(const Mat& dataset, const ::cvflann::IndexParams& params, Distance distance)
    252 {
    253     CV_Assert(dataset.type() == CvType<ElementType>::type());
    254     CV_Assert(dataset.isContinuous());
    255     ::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);
    256 
    257     nnIndex = new ::cvflann::Index<Distance>(m_dataset, params, distance);
    258 
    259     FLANN_DISTANCE_CHECK
    260 
    261     nnIndex->buildIndex();
    262 }
    263 
    264 template <typename Distance>
    265 GenericIndex<Distance>::~GenericIndex()
    266 {
    267     delete nnIndex;
    268 }
    269 
    270 template <typename Distance>
    271 void GenericIndex<Distance>::knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& searchParams)
    272 {
    273     ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
    274     ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
    275     ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
    276 
    277     FLANN_DISTANCE_CHECK
    278 
    279     nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
    280 }
    281 
    282 
    283 template <typename Distance>
    284 void GenericIndex<Distance>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams)
    285 {
    286     CV_Assert(queries.type() == CvType<ElementType>::type());
    287     CV_Assert(queries.isContinuous());
    288     ::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(0), queries.rows, queries.cols);
    289 
    290     CV_Assert(indices.type() == CV_32S);
    291     CV_Assert(indices.isContinuous());
    292     ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
    293 
    294     CV_Assert(dists.type() == CvType<DistanceType>::type());
    295     CV_Assert(dists.isContinuous());
    296     ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
    297 
    298     FLANN_DISTANCE_CHECK
    299 
    300     nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
    301 }
    302 
    303 template <typename Distance>
    304 int GenericIndex<Distance>::radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
    305 {
    306     ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
    307     ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
    308     ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
    309 
    310     FLANN_DISTANCE_CHECK
    311 
    312     return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
    313 }
    314 
    315 template <typename Distance>
    316 int GenericIndex<Distance>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
    317 {
    318     CV_Assert(query.type() == CvType<ElementType>::type());
    319     CV_Assert(query.isContinuous());
    320     ::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(0), query.rows, query.cols);
    321 
    322     CV_Assert(indices.type() == CV_32S);
    323     CV_Assert(indices.isContinuous());
    324     ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
    325 
    326     CV_Assert(dists.type() == CvType<DistanceType>::type());
    327     CV_Assert(dists.isContinuous());
    328     ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
    329 
    330     FLANN_DISTANCE_CHECK
    331 
    332     return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
    333 }
    334 
    335 //! @endcond
    336 
    337 /**
    338  * @deprecated Use GenericIndex class instead
    339  */
    340 template <typename T>
    341 class
    342 #ifndef _MSC_VER
    343  FLANN_DEPRECATED
    344 #endif
    345  Index_ {
    346 public:
    347         typedef typename L2<T>::ElementType ElementType;
    348         typedef typename L2<T>::ResultType DistanceType;
    349 
    350     Index_(const Mat& features, const ::cvflann::IndexParams& params);
    351 
    352     ~Index_();
    353 
    354     void knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& params);
    355     void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params);
    356 
    357     int radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& params);
    358     int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params);
    359 
    360     void save(String filename)
    361         {
    362             if (nnIndex_L1) nnIndex_L1->save(filename);
    363             if (nnIndex_L2) nnIndex_L2->save(filename);
    364         }
    365 
    366     int veclen() const
    367     {
    368             if (nnIndex_L1) return nnIndex_L1->veclen();
    369             if (nnIndex_L2) return nnIndex_L2->veclen();
    370         }
    371 
    372     int size() const
    373     {
    374             if (nnIndex_L1) return nnIndex_L1->size();
    375             if (nnIndex_L2) return nnIndex_L2->size();
    376         }
    377 
    378         ::cvflann::IndexParams getParameters()
    379         {
    380             if (nnIndex_L1) return nnIndex_L1->getParameters();
    381             if (nnIndex_L2) return nnIndex_L2->getParameters();
    382 
    383         }
    384 
    385         FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters()
    386         {
    387             if (nnIndex_L1) return nnIndex_L1->getIndexParameters();
    388             if (nnIndex_L2) return nnIndex_L2->getIndexParameters();
    389         }
    390 
    391 private:
    392         // providing backwards compatibility for L2 and L1 distances (most common)
    393         ::cvflann::Index< L2<ElementType> >* nnIndex_L2;
    394         ::cvflann::Index< L1<ElementType> >* nnIndex_L1;
    395 };
    396 
    397 #ifdef _MSC_VER
    398 template <typename T>
    399 class FLANN_DEPRECATED Index_;
    400 #endif
    401 
    402 //! @cond IGNORED
    403 
    404 template <typename T>
    405 Index_<T>::Index_(const Mat& dataset, const ::cvflann::IndexParams& params)
    406 {
    407     printf("[WARNING] The cv::flann::Index_<T> class is deperecated, use cv::flann::GenericIndex<Distance> instead\n");
    408 
    409     CV_Assert(dataset.type() == CvType<ElementType>::type());
    410     CV_Assert(dataset.isContinuous());
    411     ::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);
    412 
    413     if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) {
    414         nnIndex_L1 = NULL;
    415         nnIndex_L2 = new ::cvflann::Index< L2<ElementType> >(m_dataset, params);
    416     }
    417     else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) {
    418         nnIndex_L1 = new ::cvflann::Index< L1<ElementType> >(m_dataset, params);
    419         nnIndex_L2 = NULL;
    420     }
    421     else {
    422         printf("[ERROR] cv::flann::Index_<T> only provides backwards compatibility for the L1 and L2 distances. "
    423         "For other distance types you must use cv::flann::GenericIndex<Distance>\n");
    424         CV_Assert(0);
    425     }
    426     if (nnIndex_L1) nnIndex_L1->buildIndex();
    427     if (nnIndex_L2) nnIndex_L2->buildIndex();
    428 }
    429 
    430 template <typename T>
    431 Index_<T>::~Index_()
    432 {
    433     if (nnIndex_L1) delete nnIndex_L1;
    434     if (nnIndex_L2) delete nnIndex_L2;
    435 }
    436 
    437 template <typename T>
    438 void Index_<T>::knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& searchParams)
    439 {
    440     ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
    441     ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
    442     ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
    443 
    444     if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
    445     if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
    446 }
    447 
    448 
    449 template <typename T>
    450 void Index_<T>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams)
    451 {
    452     CV_Assert(queries.type() == CvType<ElementType>::type());
    453     CV_Assert(queries.isContinuous());
    454     ::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(0), queries.rows, queries.cols);
    455 
    456     CV_Assert(indices.type() == CV_32S);
    457     CV_Assert(indices.isContinuous());
    458     ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
    459 
    460     CV_Assert(dists.type() == CvType<DistanceType>::type());
    461     CV_Assert(dists.isContinuous());
    462     ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
    463 
    464     if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
    465     if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
    466 }
    467 
    468 template <typename T>
    469 int Index_<T>::radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
    470 {
    471     ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
    472     ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
    473     ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
    474 
    475     if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
    476     if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
    477 }
    478 
    479 template <typename T>
    480 int Index_<T>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
    481 {
    482     CV_Assert(query.type() == CvType<ElementType>::type());
    483     CV_Assert(query.isContinuous());
    484     ::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(0), query.rows, query.cols);
    485 
    486     CV_Assert(indices.type() == CV_32S);
    487     CV_Assert(indices.isContinuous());
    488     ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
    489 
    490     CV_Assert(dists.type() == CvType<DistanceType>::type());
    491     CV_Assert(dists.isContinuous());
    492     ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
    493 
    494     if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
    495     if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
    496 }
    497 
    498 //! @endcond
    499 
    500 /** @brief Clusters features using hierarchical k-means algorithm.
    501 
    502 @param features The points to be clustered. The matrix must have elements of type
    503 Distance::ElementType.
    504 @param centers The centers of the clusters obtained. The matrix must have type
    505 Distance::ResultType. The number of rows in this matrix represents the number of clusters desired,
    506 however, because of the way the cut in the hierarchical tree is chosen, the number of clusters
    507 computed will be the highest number of the form (branching-1)\*k+1 that's lower than the number of
    508 clusters desired, where branching is the tree's branching factor (see description of the
    509 KMeansIndexParams).
    510 @param params Parameters used in the construction of the hierarchical k-means tree.
    511 @param d Distance to be used for clustering.
    512 
    513 The method clusters the given feature vectors by constructing a hierarchical k-means tree and
    514 choosing a cut in the tree that minimizes the cluster's variance. It returns the number of clusters
    515 found.
    516  */
    517 template <typename Distance>
    518 int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params,
    519                            Distance d = Distance())
    520 {
    521     typedef typename Distance::ElementType ElementType;
    522     typedef typename Distance::ResultType DistanceType;
    523 
    524     CV_Assert(features.type() == CvType<ElementType>::type());
    525     CV_Assert(features.isContinuous());
    526     ::cvflann::Matrix<ElementType> m_features((ElementType*)features.ptr<ElementType>(0), features.rows, features.cols);
    527 
    528     CV_Assert(centers.type() == CvType<DistanceType>::type());
    529     CV_Assert(centers.isContinuous());
    530     ::cvflann::Matrix<DistanceType> m_centers((DistanceType*)centers.ptr<DistanceType>(0), centers.rows, centers.cols);
    531 
    532     return ::cvflann::hierarchicalClustering<Distance>(m_features, m_centers, params, d);
    533 }
    534 
    535 /** @deprecated
    536 */
    537 template <typename ELEM_TYPE, typename DIST_TYPE>
    538 FLANN_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params)
    539 {
    540     printf("[WARNING] cv::flann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE> is deprecated, use "
    541         "cv::flann::hierarchicalClustering<Distance> instead\n");
    542 
    543     if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) {
    544         return hierarchicalClustering< L2<ELEM_TYPE> >(features, centers, params);
    545     }
    546     else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) {
    547         return hierarchicalClustering< L1<ELEM_TYPE> >(features, centers, params);
    548     }
    549     else {
    550         printf("[ERROR] cv::flann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE> only provides backwards "
    551         "compatibility for the L1 and L2 distances. "
    552         "For other distance types you must use cv::flann::hierarchicalClustering<Distance>\n");
    553         CV_Assert(0);
    554     }
    555 }
    556 
    557 //! @} flann
    558 
    559 } } // namespace cv::flann
    560 
    561 #endif
    562