/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #ifndef _OPENCV_FLANN_HPP_ #define _OPENCV_FLANN_HPP_ #ifdef __cplusplus #include "opencv2/core/types_c.h" #include "opencv2/core.hpp" #include "opencv2/flann/miniflann.hpp" #include "opencv2/flann/flann_base.hpp" namespace cvflann { CV_EXPORTS flann_distance_t flann_distance_type(); FLANN_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order); } namespace cv { namespace flann { template struct CvType {}; template <> struct CvType { static int type() { return CV_8U; } }; template <> struct CvType { static int type() { return CV_8S; } }; template <> struct CvType { static int type() { return CV_16U; } }; template <> struct CvType { static int type() { return CV_16S; } }; template <> struct CvType { static int type() { return CV_32S; } }; template <> struct CvType { static int type() { return CV_32F; } }; template <> struct CvType { static int type() { return CV_64F; } }; // bring the flann parameters into this namespace using ::cvflann::get_param; using ::cvflann::print_params; // bring the flann distances into this namespace using ::cvflann::L2_Simple; using ::cvflann::L2; using ::cvflann::L1; using ::cvflann::MinkowskiDistance; using ::cvflann::MaxDistance; using ::cvflann::HammingLUT; using ::cvflann::Hamming; using ::cvflann::Hamming2; using ::cvflann::HistIntersectionDistance; using ::cvflann::HellingerDistance; using ::cvflann::ChiSquareDistance; using ::cvflann::KL_Divergence; template class GenericIndex { public: typedef typename Distance::ElementType ElementType; typedef typename Distance::ResultType DistanceType; GenericIndex(const Mat& features, const ::cvflann::IndexParams& params, Distance distance = Distance()); ~GenericIndex(); void knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& params); void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); int radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& params); int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params); void save(String filename) { nnIndex->save(filename); } int veclen() const { return nnIndex->veclen(); } int size() const { return nnIndex->size(); } ::cvflann::IndexParams getParameters() { return nnIndex->getParameters(); } FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); } private: ::cvflann::Index* nnIndex; }; #define FLANN_DISTANCE_CHECK \ if ( ::cvflann::flann_distance_type() != cvflann::FLANN_DIST_L2) { \ printf("[WARNING] You are using cv::flann::Index (or cv::flann::GenericIndex) and have also changed "\ "the distance using cvflann::set_distance_type. This is no longer working as expected "\ "(cv::flann::Index always uses L2). You should create the index templated on the distance, "\ "for example for L1 distance use: GenericIndex< L1 > \n"); \ } template GenericIndex::GenericIndex(const Mat& dataset, const ::cvflann::IndexParams& params, Distance distance) { CV_Assert(dataset.type() == CvType::type()); CV_Assert(dataset.isContinuous()); ::cvflann::Matrix m_dataset((ElementType*)dataset.ptr(0), dataset.rows, dataset.cols); nnIndex = new ::cvflann::Index(m_dataset, params, distance); FLANN_DISTANCE_CHECK nnIndex->buildIndex(); } template GenericIndex::~GenericIndex() { delete nnIndex; } template void GenericIndex::knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& searchParams) { ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); FLANN_DISTANCE_CHECK nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams); } template void GenericIndex::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams) { CV_Assert(queries.type() == CvType::type()); CV_Assert(queries.isContinuous()); ::cvflann::Matrix m_queries((ElementType*)queries.ptr(0), queries.rows, queries.cols); CV_Assert(indices.type() == CV_32S); CV_Assert(indices.isContinuous()); ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); CV_Assert(dists.type() == CvType::type()); CV_Assert(dists.isContinuous()); ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); FLANN_DISTANCE_CHECK nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); } template int GenericIndex::radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) { ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); FLANN_DISTANCE_CHECK return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); } template int GenericIndex::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) { CV_Assert(query.type() == CvType::type()); CV_Assert(query.isContinuous()); ::cvflann::Matrix m_query((ElementType*)query.ptr(0), query.rows, query.cols); CV_Assert(indices.type() == CV_32S); CV_Assert(indices.isContinuous()); ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); CV_Assert(dists.type() == CvType::type()); CV_Assert(dists.isContinuous()); ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); FLANN_DISTANCE_CHECK return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); } /** * @deprecated Use GenericIndex class instead */ template class #ifndef _MSC_VER FLANN_DEPRECATED #endif Index_ { public: typedef typename L2::ElementType ElementType; typedef typename L2::ResultType DistanceType; Index_(const Mat& features, const ::cvflann::IndexParams& params); ~Index_(); void knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& params); void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); int radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& params); int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params); void save(String filename) { if (nnIndex_L1) nnIndex_L1->save(filename); if (nnIndex_L2) nnIndex_L2->save(filename); } int veclen() const { if (nnIndex_L1) return nnIndex_L1->veclen(); if (nnIndex_L2) return nnIndex_L2->veclen(); } int size() const { if (nnIndex_L1) return nnIndex_L1->size(); if (nnIndex_L2) return nnIndex_L2->size(); } ::cvflann::IndexParams getParameters() { if (nnIndex_L1) return nnIndex_L1->getParameters(); if (nnIndex_L2) return nnIndex_L2->getParameters(); } FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { if (nnIndex_L1) return nnIndex_L1->getIndexParameters(); if (nnIndex_L2) return nnIndex_L2->getIndexParameters(); } private: // providing backwards compatibility for L2 and L1 distances (most common) ::cvflann::Index< L2 >* nnIndex_L2; ::cvflann::Index< L1 >* nnIndex_L1; }; #ifdef _MSC_VER template class FLANN_DEPRECATED Index_; #endif template Index_::Index_(const Mat& dataset, const ::cvflann::IndexParams& params) { printf("[WARNING] The cv::flann::Index_ class is deperecated, use cv::flann::GenericIndex instead\n"); CV_Assert(dataset.type() == CvType::type()); CV_Assert(dataset.isContinuous()); ::cvflann::Matrix m_dataset((ElementType*)dataset.ptr(0), dataset.rows, dataset.cols); if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) { nnIndex_L1 = NULL; nnIndex_L2 = new ::cvflann::Index< L2 >(m_dataset, params); } else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) { nnIndex_L1 = new ::cvflann::Index< L1 >(m_dataset, params); nnIndex_L2 = NULL; } else { printf("[ERROR] cv::flann::Index_ only provides backwards compatibility for the L1 and L2 distances. " "For other distance types you must use cv::flann::GenericIndex\n"); CV_Assert(0); } if (nnIndex_L1) nnIndex_L1->buildIndex(); if (nnIndex_L2) nnIndex_L2->buildIndex(); } template Index_::~Index_() { if (nnIndex_L1) delete nnIndex_L1; if (nnIndex_L2) delete nnIndex_L2; } template void Index_::knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& searchParams) { ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams); if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams); } template void Index_::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams) { CV_Assert(queries.type() == CvType::type()); CV_Assert(queries.isContinuous()); ::cvflann::Matrix m_queries((ElementType*)queries.ptr(0), queries.rows, queries.cols); CV_Assert(indices.type() == CV_32S); CV_Assert(indices.isContinuous()); ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); CV_Assert(dists.type() == CvType::type()); CV_Assert(dists.isContinuous()); ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); } template int Index_::radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) { ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); } template int Index_::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) { CV_Assert(query.type() == CvType::type()); CV_Assert(query.isContinuous()); ::cvflann::Matrix m_query((ElementType*)query.ptr(0), query.rows, query.cols); CV_Assert(indices.type() == CV_32S); CV_Assert(indices.isContinuous()); ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); CV_Assert(dists.type() == CvType::type()); CV_Assert(dists.isContinuous()); ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); } template int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params, Distance d = Distance()) { typedef typename Distance::ElementType ElementType; typedef typename Distance::ResultType DistanceType; CV_Assert(features.type() == CvType::type()); CV_Assert(features.isContinuous()); ::cvflann::Matrix m_features((ElementType*)features.ptr(0), features.rows, features.cols); CV_Assert(centers.type() == CvType::type()); CV_Assert(centers.isContinuous()); ::cvflann::Matrix m_centers((DistanceType*)centers.ptr(0), centers.rows, centers.cols); return ::cvflann::hierarchicalClustering(m_features, m_centers, params, d); } template FLANN_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params) { printf("[WARNING] cv::flann::hierarchicalClustering is deprecated, use " "cv::flann::hierarchicalClustering instead\n"); if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) { return hierarchicalClustering< L2 >(features, centers, params); } else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) { return hierarchicalClustering< L1 >(features, centers, params); } else { printf("[ERROR] cv::flann::hierarchicalClustering only provides backwards " "compatibility for the L1 and L2 distances. " "For other distance types you must use cv::flann::hierarchicalClustering\n"); CV_Assert(0); } } } } // namespace cv::flann #endif // __cplusplus #endif