Path: blob/master/modules/flann/include/opencv2/flann.hpp
16358 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#ifndef OPENCV_FLANN_HPP43#define OPENCV_FLANN_HPP4445#include "opencv2/core.hpp"46#include "opencv2/flann/miniflann.hpp"47#include "opencv2/flann/flann_base.hpp"4849/**50@defgroup flann Clustering and Search in Multi-Dimensional Spaces5152This section documents OpenCV's interface to the FLANN library. FLANN (Fast Library for Approximate53Nearest Neighbors) is a library that contains a collection of algorithms optimized for fast nearest54neighbor search in large datasets and for high dimensional features. More information about FLANN55can be found in @cite Muja2009 .56*/5758namespace cvflann59{60CV_EXPORTS flann_distance_t flann_distance_type();61CV_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order);62}636465namespace cv66{67namespace flann68{697071//! @addtogroup flann72//! @{7374template <typename T> struct CvType {};75template <> struct CvType<unsigned char> { static int type() { return CV_8U; } };76template <> struct CvType<char> { static int type() { return CV_8S; } };77template <> struct CvType<unsigned short> { static int type() { return CV_16U; } };78template <> struct CvType<short> { static int type() { return CV_16S; } };79template <> struct CvType<int> { static int type() { return CV_32S; } };80template <> struct CvType<float> { static int type() { return CV_32F; } };81template <> struct CvType<double> { static int type() { return CV_64F; } };828384// bring the flann parameters into this namespace85using ::cvflann::get_param;86using ::cvflann::print_params;8788// bring the flann distances into this namespace89using ::cvflann::L2_Simple;90using ::cvflann::L2;91using ::cvflann::L1;92using ::cvflann::MinkowskiDistance;93using ::cvflann::MaxDistance;94using ::cvflann::HammingLUT;95using ::cvflann::Hamming;96using ::cvflann::Hamming2;97using ::cvflann::HistIntersectionDistance;98using ::cvflann::HellingerDistance;99using ::cvflann::ChiSquareDistance;100using ::cvflann::KL_Divergence;101102103/** @brief The FLANN nearest neighbor index class. This class is templated with the type of elements for which104the index is built.105106`Distance` functor specifies the metric to be used to calculate the distance between two points.107There are several `Distance` functors that are readily available:108109@link cvflann::L2_Simple cv::flann::L2_Simple @endlink- Squared Euclidean distance functor.110This is the simpler, unrolled version. This is preferable for very low dimensionality data (eg 3D points)111112@link cvflann::L2 cv::flann::L2 @endlink- Squared Euclidean distance functor, optimized version.113114@link cvflann::L1 cv::flann::L1 @endlink - Manhattan distance functor, optimized version.115116@link cvflann::MinkowskiDistance cv::flann::MinkowskiDistance @endlink - The Minkowsky distance functor.117This is highly optimised with loop unrolling.118The computation of squared root at the end is omitted for efficiency.119120@link cvflann::MaxDistance cv::flann::MaxDistance @endlink - The max distance functor. It computes the121maximum distance between two vectors. This distance is not a valid kdtree distance, it's not122dimensionwise additive.123124@link cvflann::HammingLUT cv::flann::HammingLUT @endlink - %Hamming distance functor. It counts the bit125differences between two strings using a lookup table implementation.126127@link cvflann::Hamming cv::flann::Hamming @endlink - %Hamming distance functor. Population count is128performed using library calls, if available. Lookup table implementation is used as a fallback.129130@link cvflann::Hamming2 cv::flann::Hamming2 @endlink- %Hamming distance functor. Population count is131implemented in 12 arithmetic operations (one of which is multiplication).132133@link cvflann::HistIntersectionDistance cv::flann::HistIntersectionDistance @endlink - The histogram134intersection distance functor.135136@link cvflann::HellingerDistance cv::flann::HellingerDistance @endlink - The Hellinger distance functor.137138@link cvflann::ChiSquareDistance cv::flann::ChiSquareDistance @endlink - The chi-square distance functor.139140@link cvflann::KL_Divergence cv::flann::KL_Divergence @endlink - The Kullback-Leibler divergence functor.141142Although the provided implementations cover a vast range of cases, it is also possible to use143a custom implementation. The distance functor is a class whose `operator()` computes the distance144between two features. If the distance is also a kd-tree compatible distance, it should also provide an145`accum_dist()` method that computes the distance between individual feature dimensions.146147In addition to `operator()` and `accum_dist()`, a distance functor should also define the148`ElementType` and the `ResultType` as the types of the elements it operates on and the type of the149result it computes. If a distance functor can be used as a kd-tree distance (meaning that the full150distance between a pair of features can be accumulated from the partial distances between the151individual dimensions) a typedef `is_kdtree_distance` should be present inside the distance functor.152If the distance is not a kd-tree distance, but it's a distance in a vector space (the individual153dimensions of the elements it operates on can be accessed independently) a typedef154`is_vector_space_distance` should be defined inside the functor. If neither typedef is defined, the155distance is assumed to be a metric distance and will only be used with indexes operating on156generic metric distances.157*/158template <typename Distance>159class GenericIndex160{161public:162typedef typename Distance::ElementType ElementType;163typedef typename Distance::ResultType DistanceType;164165/** @brief Constructs a nearest neighbor search index for a given dataset.166167@param features Matrix of containing the features(points) to index. The size of the matrix is168num_features x feature_dimensionality and the data type of the elements in the matrix must169coincide with the type of the index.170@param params Structure containing the index parameters. The type of index that will be171constructed depends on the type of this parameter. See the description.172@param distance173174The method constructs a fast search structure from a set of features using the specified algorithm175with specified parameters, as defined by params. params is a reference to one of the following class176IndexParams descendants:177178- **LinearIndexParams** When passing an object of this type, the index will perform a linear,179brute-force search. :180@code181struct LinearIndexParams : public IndexParams182{183};184@endcode185- **KDTreeIndexParams** When passing an object of this type the index constructed will consist of186a set of randomized kd-trees which will be searched in parallel. :187@code188struct KDTreeIndexParams : public IndexParams189{190KDTreeIndexParams( int trees = 4 );191};192@endcode193- **KMeansIndexParams** When passing an object of this type the index constructed will be a194hierarchical k-means tree. :195@code196struct KMeansIndexParams : public IndexParams197{198KMeansIndexParams(199int branching = 32,200int iterations = 11,201flann_centers_init_t centers_init = CENTERS_RANDOM,202float cb_index = 0.2 );203};204@endcode205- **CompositeIndexParams** When using a parameters object of this type the index created206combines the randomized kd-trees and the hierarchical k-means tree. :207@code208struct CompositeIndexParams : public IndexParams209{210CompositeIndexParams(211int trees = 4,212int branching = 32,213int iterations = 11,214flann_centers_init_t centers_init = CENTERS_RANDOM,215float cb_index = 0.2 );216};217@endcode218- **LshIndexParams** When using a parameters object of this type the index created uses219multi-probe LSH (by Multi-Probe LSH: Efficient Indexing for High-Dimensional Similarity Search220by Qin Lv, William Josephson, Zhe Wang, Moses Charikar, Kai Li., Proceedings of the 33rd221International Conference on Very Large Data Bases (VLDB). Vienna, Austria. September 2007) :222@code223struct LshIndexParams : public IndexParams224{225LshIndexParams(226unsigned int table_number,227unsigned int key_size,228unsigned int multi_probe_level );229};230@endcode231- **AutotunedIndexParams** When passing an object of this type the index created is232automatically tuned to offer the best performance, by choosing the optimal index type233(randomized kd-trees, hierarchical kmeans, linear) and parameters for the dataset provided. :234@code235struct AutotunedIndexParams : public IndexParams236{237AutotunedIndexParams(238float target_precision = 0.9,239float build_weight = 0.01,240float memory_weight = 0,241float sample_fraction = 0.1 );242};243@endcode244- **SavedIndexParams** This object type is used for loading a previously saved index from the245disk. :246@code247struct SavedIndexParams : public IndexParams248{249SavedIndexParams( String filename );250};251@endcode252*/253GenericIndex(const Mat& features, const ::cvflann::IndexParams& params, Distance distance = Distance());254255~GenericIndex();256257/** @brief Performs a K-nearest neighbor search for a given query point using the index.258259@param query The query point260@param indices Vector that will contain the indices of the K-nearest neighbors found. It must have261at least knn size.262@param dists Vector that will contain the distances to the K-nearest neighbors found. It must have263at least knn size.264@param knn Number of nearest neighbors to search for.265@param params SearchParams266*/267void knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices,268std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& params);269void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params);270271/** @brief Performs a radius nearest neighbor search for a given query point using the index.272273@param query The query point.274@param indices Vector that will contain the indices of the nearest neighbors found.275@param dists Vector that will contain the distances to the nearest neighbors found. It has the same276number of elements as indices.277@param radius The search radius.278@param params SearchParams279280This function returns the number of nearest neighbors found.281*/282int radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices,283std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& params);284int radiusSearch(const Mat& query, Mat& indices, Mat& dists,285DistanceType radius, const ::cvflann::SearchParams& params);286287void save(String filename) { nnIndex->save(filename); }288289int veclen() const { return nnIndex->veclen(); }290291int size() const { return nnIndex->size(); }292293::cvflann::IndexParams getParameters() { return nnIndex->getParameters(); }294295CV_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); }296297private:298::cvflann::Index<Distance>* nnIndex;299};300301//! @cond IGNORED302303#define FLANN_DISTANCE_CHECK \304if ( ::cvflann::flann_distance_type() != cvflann::FLANN_DIST_L2) { \305printf("[WARNING] You are using cv::flann::Index (or cv::flann::GenericIndex) and have also changed "\306"the distance using cvflann::set_distance_type. This is no longer working as expected "\307"(cv::flann::Index always uses L2). You should create the index templated on the distance, "\308"for example for L1 distance use: GenericIndex< L1<float> > \n"); \309}310311312template <typename Distance>313GenericIndex<Distance>::GenericIndex(const Mat& dataset, const ::cvflann::IndexParams& params, Distance distance)314{315CV_Assert(dataset.type() == CvType<ElementType>::type());316CV_Assert(dataset.isContinuous());317::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);318319nnIndex = new ::cvflann::Index<Distance>(m_dataset, params, distance);320321FLANN_DISTANCE_CHECK322323nnIndex->buildIndex();324}325326template <typename Distance>327GenericIndex<Distance>::~GenericIndex()328{329delete nnIndex;330}331332template <typename Distance>333void GenericIndex<Distance>::knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& searchParams)334{335::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());336::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());337::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());338339FLANN_DISTANCE_CHECK340341nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams);342}343344345template <typename Distance>346void GenericIndex<Distance>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams)347{348CV_Assert(queries.type() == CvType<ElementType>::type());349CV_Assert(queries.isContinuous());350::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(0), queries.rows, queries.cols);351352CV_Assert(indices.type() == CV_32S);353CV_Assert(indices.isContinuous());354::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);355356CV_Assert(dists.type() == CvType<DistanceType>::type());357CV_Assert(dists.isContinuous());358::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);359360FLANN_DISTANCE_CHECK361362nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);363}364365template <typename Distance>366int GenericIndex<Distance>::radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)367{368::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());369::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());370::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());371372FLANN_DISTANCE_CHECK373374return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);375}376377template <typename Distance>378int GenericIndex<Distance>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)379{380CV_Assert(query.type() == CvType<ElementType>::type());381CV_Assert(query.isContinuous());382::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(0), query.rows, query.cols);383384CV_Assert(indices.type() == CV_32S);385CV_Assert(indices.isContinuous());386::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);387388CV_Assert(dists.type() == CvType<DistanceType>::type());389CV_Assert(dists.isContinuous());390::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);391392FLANN_DISTANCE_CHECK393394return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);395}396397//! @endcond398399/**400* @deprecated Use GenericIndex class instead401*/402template <typename T>403class Index_404{405public:406typedef typename L2<T>::ElementType ElementType;407typedef typename L2<T>::ResultType DistanceType;408409CV_DEPRECATED Index_(const Mat& dataset, const ::cvflann::IndexParams& params)410{411printf("[WARNING] The cv::flann::Index_<T> class is deperecated, use cv::flann::GenericIndex<Distance> instead\n");412413CV_Assert(dataset.type() == CvType<ElementType>::type());414CV_Assert(dataset.isContinuous());415::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);416417if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) {418nnIndex_L1 = NULL;419nnIndex_L2 = new ::cvflann::Index< L2<ElementType> >(m_dataset, params);420}421else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) {422nnIndex_L1 = new ::cvflann::Index< L1<ElementType> >(m_dataset, params);423nnIndex_L2 = NULL;424}425else {426printf("[ERROR] cv::flann::Index_<T> only provides backwards compatibility for the L1 and L2 distances. "427"For other distance types you must use cv::flann::GenericIndex<Distance>\n");428CV_Assert(0);429}430if (nnIndex_L1) nnIndex_L1->buildIndex();431if (nnIndex_L2) nnIndex_L2->buildIndex();432}433CV_DEPRECATED ~Index_()434{435if (nnIndex_L1) delete nnIndex_L1;436if (nnIndex_L2) delete nnIndex_L2;437}438439CV_DEPRECATED void knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& searchParams)440{441::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());442::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());443::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());444445if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams);446if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams);447}448CV_DEPRECATED void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams)449{450CV_Assert(queries.type() == CvType<ElementType>::type());451CV_Assert(queries.isContinuous());452::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(0), queries.rows, queries.cols);453454CV_Assert(indices.type() == CV_32S);455CV_Assert(indices.isContinuous());456::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);457458CV_Assert(dists.type() == CvType<DistanceType>::type());459CV_Assert(dists.isContinuous());460::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);461462if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);463if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);464}465466CV_DEPRECATED int radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)467{468::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());469::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());470::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());471472if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);473if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);474}475476CV_DEPRECATED int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)477{478CV_Assert(query.type() == CvType<ElementType>::type());479CV_Assert(query.isContinuous());480::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(0), query.rows, query.cols);481482CV_Assert(indices.type() == CV_32S);483CV_Assert(indices.isContinuous());484::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);485486CV_Assert(dists.type() == CvType<DistanceType>::type());487CV_Assert(dists.isContinuous());488::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);489490if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);491if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);492}493494CV_DEPRECATED void save(String filename)495{496if (nnIndex_L1) nnIndex_L1->save(filename);497if (nnIndex_L2) nnIndex_L2->save(filename);498}499500CV_DEPRECATED int veclen() const501{502if (nnIndex_L1) return nnIndex_L1->veclen();503if (nnIndex_L2) return nnIndex_L2->veclen();504}505506CV_DEPRECATED int size() const507{508if (nnIndex_L1) return nnIndex_L1->size();509if (nnIndex_L2) return nnIndex_L2->size();510}511512CV_DEPRECATED ::cvflann::IndexParams getParameters()513{514if (nnIndex_L1) return nnIndex_L1->getParameters();515if (nnIndex_L2) return nnIndex_L2->getParameters();516517}518519CV_DEPRECATED const ::cvflann::IndexParams* getIndexParameters()520{521if (nnIndex_L1) return nnIndex_L1->getIndexParameters();522if (nnIndex_L2) return nnIndex_L2->getIndexParameters();523}524525private:526// providing backwards compatibility for L2 and L1 distances (most common)527::cvflann::Index< L2<ElementType> >* nnIndex_L2;528::cvflann::Index< L1<ElementType> >* nnIndex_L1;529};530531532/** @brief Clusters features using hierarchical k-means algorithm.533534@param features The points to be clustered. The matrix must have elements of type535Distance::ElementType.536@param centers The centers of the clusters obtained. The matrix must have type537Distance::ResultType. The number of rows in this matrix represents the number of clusters desired,538however, because of the way the cut in the hierarchical tree is chosen, the number of clusters539computed will be the highest number of the form (branching-1)\*k+1 that's lower than the number of540clusters desired, where branching is the tree's branching factor (see description of the541KMeansIndexParams).542@param params Parameters used in the construction of the hierarchical k-means tree.543@param d Distance to be used for clustering.544545The method clusters the given feature vectors by constructing a hierarchical k-means tree and546choosing a cut in the tree that minimizes the cluster's variance. It returns the number of clusters547found.548*/549template <typename Distance>550int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params,551Distance d = Distance())552{553typedef typename Distance::ElementType ElementType;554typedef typename Distance::ResultType DistanceType;555556CV_Assert(features.type() == CvType<ElementType>::type());557CV_Assert(features.isContinuous());558::cvflann::Matrix<ElementType> m_features((ElementType*)features.ptr<ElementType>(0), features.rows, features.cols);559560CV_Assert(centers.type() == CvType<DistanceType>::type());561CV_Assert(centers.isContinuous());562::cvflann::Matrix<DistanceType> m_centers((DistanceType*)centers.ptr<DistanceType>(0), centers.rows, centers.cols);563564return ::cvflann::hierarchicalClustering<Distance>(m_features, m_centers, params, d);565}566567/** @deprecated568*/569template <typename ELEM_TYPE, typename DIST_TYPE>570CV_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params)571{572printf("[WARNING] cv::flann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE> is deprecated, use "573"cv::flann::hierarchicalClustering<Distance> instead\n");574575if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) {576return hierarchicalClustering< L2<ELEM_TYPE> >(features, centers, params);577}578else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) {579return hierarchicalClustering< L1<ELEM_TYPE> >(features, centers, params);580}581else {582printf("[ERROR] cv::flann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE> only provides backwards "583"compatibility for the L1 and L2 distances. "584"For other distance types you must use cv::flann::hierarchicalClustering<Distance>\n");585CV_Assert(0);586}587}588589//! @} flann590591} } // namespace cv::flann592593#endif594595596