Path: blob/master/modules/features2d/src/matchers.cpp
16337 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// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "precomp.hpp"42#ifdef HAVE_OPENCV_FLANN43#include "opencv2/flann/miniflann.hpp"44#endif45#include <limits>46#include "opencl_kernels_features2d.hpp"4748#if defined(HAVE_EIGEN) && EIGEN_WORLD_VERSION == 249# if defined(_MSC_VER)50# pragma warning(push)51# pragma warning(disable:4701) // potentially uninitialized local variable52# pragma warning(disable:4702) // unreachable code53# pragma warning(disable:4714) // const marked as __forceinline not inlined54# endif55# include <Eigen/Array>56# if defined(_MSC_VER)57# pragma warning(pop)58# endif59#endif6061namespace cv62{6364/////////////////////// ocl functions for BFMatcher ///////////////////////////6566#ifdef HAVE_OPENCL67static void ensureSizeIsEnough(int rows, int cols, int type, UMat &m)68{69if (m.type() == type && m.rows >= rows && m.cols >= cols)70m = m(Rect(0, 0, cols, rows));71else72m.create(rows, cols, type);73}7475static bool ocl_matchSingle(InputArray query, InputArray train,76UMat &trainIdx, UMat &distance, int distType)77{78if (query.empty() || train.empty())79return false;8081const int query_rows = query.rows();82const int query_cols = query.cols();8384ensureSizeIsEnough(1, query_rows, CV_32S, trainIdx);85ensureSizeIsEnough(1, query_rows, CV_32F, distance);8687ocl::Device devDef = ocl::Device::getDefault();8889UMat uquery = query.getUMat(), utrain = train.getUMat();90int kercn = 1;91if (devDef.isIntel() &&92(0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&93(0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))94kercn = 4;9596int block_size = 16;97int max_desc_len = 0;98bool is_cpu = devDef.type() == ocl::Device::TYPE_CPU;99if (query_cols <= 64)100max_desc_len = 64 / kercn;101else if (query_cols <= 128 && !is_cpu)102max_desc_len = 128 / kercn;103104int depth = query.depth();105cv::String opts;106opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d",107ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size, max_desc_len);108ocl::Kernel k("BruteForceMatch_Match", ocl::features2d::brute_force_match_oclsrc, opts);109if(k.empty())110return false;111112size_t globalSize[] = {((size_t)query.size().height + block_size - 1) / block_size * block_size, (size_t)block_size};113size_t localSize[] = {(size_t)block_size, (size_t)block_size};114115int idx = 0;116idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));117idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));118idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));119idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));120idx = k.set(idx, uquery.rows);121idx = k.set(idx, uquery.cols);122idx = k.set(idx, utrain.rows);123idx = k.set(idx, utrain.cols);124idx = k.set(idx, (int)(uquery.step / sizeof(float)));125126return k.run(2, globalSize, localSize, false);127}128129static bool ocl_matchConvert(const Mat &trainIdx, const Mat &distance, std::vector< std::vector<DMatch> > &matches)130{131if (trainIdx.empty() || distance.empty())132return false;133134if( (trainIdx.type() != CV_32SC1) || (distance.type() != CV_32FC1 || distance.cols != trainIdx.cols) )135return false;136137const int nQuery = trainIdx.cols;138139matches.clear();140matches.reserve(nQuery);141142const int *trainIdx_ptr = trainIdx.ptr<int>();143const float *distance_ptr = distance.ptr<float>();144for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx, ++trainIdx_ptr, ++distance_ptr)145{146int trainIndex = *trainIdx_ptr;147148if (trainIndex == -1)149continue;150151float dst = *distance_ptr;152153DMatch m(queryIdx, trainIndex, 0, dst);154155std::vector<DMatch> temp;156temp.push_back(m);157matches.push_back(temp);158}159return true;160}161162static bool ocl_matchDownload(const UMat &trainIdx, const UMat &distance, std::vector< std::vector<DMatch> > &matches)163{164if (trainIdx.empty() || distance.empty())165return false;166167Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);168Mat distanceCPU = distance.getMat(ACCESS_READ);169170return ocl_matchConvert(trainIdxCPU, distanceCPU, matches);171}172173static bool ocl_knnMatchSingle(InputArray query, InputArray train, UMat &trainIdx,174UMat &distance, int distType)175{176if (query.empty() || train.empty())177return false;178179const int query_rows = query.rows();180const int query_cols = query.cols();181182ensureSizeIsEnough(1, query_rows, CV_32SC2, trainIdx);183ensureSizeIsEnough(1, query_rows, CV_32FC2, distance);184185trainIdx.setTo(Scalar::all(-1));186187ocl::Device devDef = ocl::Device::getDefault();188189UMat uquery = query.getUMat(), utrain = train.getUMat();190int kercn = 1;191if (devDef.isIntel() &&192(0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&193(0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))194kercn = 4;195196int block_size = 16;197int max_desc_len = 0;198bool is_cpu = devDef.type() == ocl::Device::TYPE_CPU;199if (query_cols <= 64)200max_desc_len = 64 / kercn;201else if (query_cols <= 128 && !is_cpu)202max_desc_len = 128 / kercn;203204int depth = query.depth();205cv::String opts;206opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d",207ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size, max_desc_len);208ocl::Kernel k("BruteForceMatch_knnMatch", ocl::features2d::brute_force_match_oclsrc, opts);209if(k.empty())210return false;211212size_t globalSize[] = {((size_t)query_rows + block_size - 1) / block_size * block_size, (size_t)block_size};213size_t localSize[] = {(size_t)block_size, (size_t)block_size};214215int idx = 0;216idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));217idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));218idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));219idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));220idx = k.set(idx, uquery.rows);221idx = k.set(idx, uquery.cols);222idx = k.set(idx, utrain.rows);223idx = k.set(idx, utrain.cols);224idx = k.set(idx, (int)(uquery.step / sizeof(float)));225226return k.run(2, globalSize, localSize, false);227}228229static bool ocl_knnMatchConvert(const Mat &trainIdx, const Mat &distance, std::vector< std::vector<DMatch> > &matches, bool compactResult)230{231if (trainIdx.empty() || distance.empty())232return false;233234if(trainIdx.type() != CV_32SC2 && trainIdx.type() != CV_32SC1) return false;235if(distance.type() != CV_32FC2 && distance.type() != CV_32FC1)return false;236if(distance.size() != trainIdx.size()) return false;237if(!trainIdx.isContinuous() || !distance.isContinuous()) return false;238239const int nQuery = trainIdx.type() == CV_32SC2 ? trainIdx.cols : trainIdx.rows;240const int k = trainIdx.type() == CV_32SC2 ? 2 : trainIdx.cols;241242matches.clear();243matches.reserve(nQuery);244245const int *trainIdx_ptr = trainIdx.ptr<int>();246const float *distance_ptr = distance.ptr<float>();247248for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx)249{250matches.push_back(std::vector<DMatch>());251std::vector<DMatch> &curMatches = matches.back();252curMatches.reserve(k);253254for (int i = 0; i < k; ++i, ++trainIdx_ptr, ++distance_ptr)255{256int trainIndex = *trainIdx_ptr;257258if (trainIndex != -1)259{260float dst = *distance_ptr;261262DMatch m(queryIdx, trainIndex, 0, dst);263264curMatches.push_back(m);265}266}267268if (compactResult && curMatches.empty())269matches.pop_back();270}271return true;272}273274static bool ocl_knnMatchDownload(const UMat &trainIdx, const UMat &distance, std::vector< std::vector<DMatch> > &matches, bool compactResult)275{276if (trainIdx.empty() || distance.empty())277return false;278279Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);280Mat distanceCPU = distance.getMat(ACCESS_READ);281282return ocl_knnMatchConvert(trainIdxCPU, distanceCPU, matches, compactResult);283}284285static bool ocl_radiusMatchSingle(InputArray query, InputArray train,286UMat &trainIdx, UMat &distance, UMat &nMatches, float maxDistance, int distType)287{288if (query.empty() || train.empty())289return false;290291const int query_rows = query.rows();292const int train_rows = train.rows();293294ensureSizeIsEnough(1, query_rows, CV_32SC1, nMatches);295296if (trainIdx.empty())297{298ensureSizeIsEnough(query_rows, std::max((train_rows / 100), 10), CV_32SC1, trainIdx);299ensureSizeIsEnough(query_rows, std::max((train_rows / 100), 10), CV_32FC1, distance);300}301302nMatches.setTo(Scalar::all(0));303304ocl::Device devDef = ocl::Device::getDefault();305UMat uquery = query.getUMat(), utrain = train.getUMat();306int kercn = 1;307if (devDef.isIntel() &&308(0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&309(0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))310kercn = 4;311312int block_size = 16;313int depth = query.depth();314cv::String opts;315opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d",316ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size);317ocl::Kernel k("BruteForceMatch_RadiusMatch", ocl::features2d::brute_force_match_oclsrc, opts);318if (k.empty())319return false;320321size_t globalSize[] = {((size_t)train_rows + block_size - 1) / block_size * block_size, ((size_t)query_rows + block_size - 1) / block_size * block_size};322size_t localSize[] = {(size_t)block_size, (size_t)block_size};323324int idx = 0;325idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));326idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));327idx = k.set(idx, maxDistance);328idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));329idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));330idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(nMatches));331idx = k.set(idx, uquery.rows);332idx = k.set(idx, uquery.cols);333idx = k.set(idx, utrain.rows);334idx = k.set(idx, utrain.cols);335idx = k.set(idx, trainIdx.cols);336idx = k.set(idx, (int)(uquery.step / sizeof(float)));337idx = k.set(idx, (int)(trainIdx.step / sizeof(int)));338339return k.run(2, globalSize, localSize, false);340}341342static bool ocl_radiusMatchConvert(const Mat &trainIdx, const Mat &distance, const Mat &_nMatches,343std::vector< std::vector<DMatch> > &matches, bool compactResult)344{345if (trainIdx.empty() || distance.empty() || _nMatches.empty())346return false;347348if( (trainIdx.type() != CV_32SC1) ||349(distance.type() != CV_32FC1 || distance.size() != trainIdx.size()) ||350(_nMatches.type() != CV_32SC1 || _nMatches.cols != trainIdx.rows) )351return false;352353const int nQuery = trainIdx.rows;354355matches.clear();356matches.reserve(nQuery);357358const int *nMatches_ptr = _nMatches.ptr<int>();359360for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx)361{362const int *trainIdx_ptr = trainIdx.ptr<int>(queryIdx);363const float *distance_ptr = distance.ptr<float>(queryIdx);364365const int nMatches = std::min(nMatches_ptr[queryIdx], trainIdx.cols);366367if (nMatches == 0)368{369if (!compactResult)370matches.push_back(std::vector<DMatch>());371continue;372}373374matches.push_back(std::vector<DMatch>(nMatches));375std::vector<DMatch> &curMatches = matches.back();376377for (int i = 0; i < nMatches; ++i, ++trainIdx_ptr, ++distance_ptr)378{379int trainIndex = *trainIdx_ptr;380381float dst = *distance_ptr;382383DMatch m(queryIdx, trainIndex, 0, dst);384385curMatches[i] = m;386}387388std::sort(curMatches.begin(), curMatches.end());389}390return true;391}392393static bool ocl_radiusMatchDownload(const UMat &trainIdx, const UMat &distance, const UMat &nMatches,394std::vector< std::vector<DMatch> > &matches, bool compactResult)395{396if (trainIdx.empty() || distance.empty() || nMatches.empty())397return false;398399Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);400Mat distanceCPU = distance.getMat(ACCESS_READ);401Mat nMatchesCPU = nMatches.getMat(ACCESS_READ);402403return ocl_radiusMatchConvert(trainIdxCPU, distanceCPU, nMatchesCPU, matches, compactResult);404}405#endif406407/****************************************************************************************\408* DescriptorMatcher *409\****************************************************************************************/410DescriptorMatcher::DescriptorCollection::DescriptorCollection()411{}412413DescriptorMatcher::DescriptorCollection::DescriptorCollection( const DescriptorCollection& collection )414{415mergedDescriptors = collection.mergedDescriptors.clone();416std::copy( collection.startIdxs.begin(), collection.startIdxs.begin(), startIdxs.begin() );417}418419DescriptorMatcher::DescriptorCollection::~DescriptorCollection()420{}421422void DescriptorMatcher::DescriptorCollection::set( const std::vector<Mat>& descriptors )423{424clear();425426size_t imageCount = descriptors.size();427CV_Assert( imageCount > 0 );428429startIdxs.resize( imageCount );430431int dim = -1;432int type = -1;433startIdxs[0] = 0;434for( size_t i = 1; i < imageCount; i++ )435{436int s = 0;437if( !descriptors[i-1].empty() )438{439dim = descriptors[i-1].cols;440type = descriptors[i-1].type();441s = descriptors[i-1].rows;442}443startIdxs[i] = startIdxs[i-1] + s;444}445if( imageCount == 1 )446{447if( descriptors[0].empty() ) return;448449dim = descriptors[0].cols;450type = descriptors[0].type();451}452CV_Assert( dim > 0 );453454int count = startIdxs[imageCount-1] + descriptors[imageCount-1].rows;455456if( count > 0 )457{458mergedDescriptors.create( count, dim, type );459for( size_t i = 0; i < imageCount; i++ )460{461if( !descriptors[i].empty() )462{463CV_Assert( descriptors[i].cols == dim && descriptors[i].type() == type );464Mat m = mergedDescriptors.rowRange( startIdxs[i], startIdxs[i] + descriptors[i].rows );465descriptors[i].copyTo(m);466}467}468}469}470471void DescriptorMatcher::DescriptorCollection::clear()472{473startIdxs.clear();474mergedDescriptors.release();475}476477const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int imgIdx, int localDescIdx ) const478{479CV_Assert( imgIdx < (int)startIdxs.size() );480int globalIdx = startIdxs[imgIdx] + localDescIdx;481CV_Assert( globalIdx < (int)size() );482483return getDescriptor( globalIdx );484}485486const Mat& DescriptorMatcher::DescriptorCollection::getDescriptors() const487{488return mergedDescriptors;489}490491const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int globalDescIdx ) const492{493CV_Assert( globalDescIdx < size() );494return mergedDescriptors.row( globalDescIdx );495}496497void DescriptorMatcher::DescriptorCollection::getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const498{499CV_Assert( (globalDescIdx>=0) && (globalDescIdx < size()) );500std::vector<int>::const_iterator img_it = std::upper_bound(startIdxs.begin(), startIdxs.end(), globalDescIdx);501--img_it;502imgIdx = (int)(img_it - startIdxs.begin());503localDescIdx = globalDescIdx - (*img_it);504}505506int DescriptorMatcher::DescriptorCollection::size() const507{508return mergedDescriptors.rows;509}510511/*512* DescriptorMatcher513*/514static void convertMatches( const std::vector<std::vector<DMatch> >& knnMatches, std::vector<DMatch>& matches )515{516matches.clear();517matches.reserve( knnMatches.size() );518for( size_t i = 0; i < knnMatches.size(); i++ )519{520CV_Assert( knnMatches[i].size() <= 1 );521if( !knnMatches[i].empty() )522matches.push_back( knnMatches[i][0] );523}524}525526DescriptorMatcher::~DescriptorMatcher()527{}528529void DescriptorMatcher::add( InputArrayOfArrays _descriptors )530{531if( _descriptors.isUMatVector() )532{533std::vector<UMat> descriptors;534_descriptors.getUMatVector( descriptors );535utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );536}537else if( _descriptors.isUMat() )538{539std::vector<UMat> descriptors = std::vector<UMat>(1, _descriptors.getUMat());540utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );541}542else if( _descriptors.isMatVector() )543{544std::vector<Mat> descriptors;545_descriptors.getMatVector(descriptors);546trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );547}548else if( _descriptors.isMat() )549{550std::vector<Mat> descriptors = std::vector<Mat>(1, _descriptors.getMat());551trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );552}553else554{555CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() );556}557}558559const std::vector<Mat>& DescriptorMatcher::getTrainDescriptors() const560{561return trainDescCollection;562}563564void DescriptorMatcher::clear()565{566utrainDescCollection.clear();567trainDescCollection.clear();568}569570bool DescriptorMatcher::empty() const571{572return trainDescCollection.empty() && utrainDescCollection.empty();573}574575void DescriptorMatcher::train()576{}577578void DescriptorMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors,579std::vector<DMatch>& matches, InputArray mask ) const580{581CV_INSTRUMENT_REGION();582583Ptr<DescriptorMatcher> tempMatcher = clone(true);584tempMatcher->add(trainDescriptors);585tempMatcher->match( queryDescriptors, matches, std::vector<Mat>(1, mask.getMat()) );586}587588void DescriptorMatcher::knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,589std::vector<std::vector<DMatch> >& matches, int knn,590InputArray mask, bool compactResult ) const591{592CV_INSTRUMENT_REGION();593594Ptr<DescriptorMatcher> tempMatcher = clone(true);595tempMatcher->add(trainDescriptors);596tempMatcher->knnMatch( queryDescriptors, matches, knn, std::vector<Mat>(1, mask.getMat()), compactResult );597}598599void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,600std::vector<std::vector<DMatch> >& matches, float maxDistance, InputArray mask,601bool compactResult ) const602{603CV_INSTRUMENT_REGION();604605Ptr<DescriptorMatcher> tempMatcher = clone(true);606tempMatcher->add(trainDescriptors);607tempMatcher->radiusMatch( queryDescriptors, matches, maxDistance, std::vector<Mat>(1, mask.getMat()), compactResult );608}609610void DescriptorMatcher::match( InputArray queryDescriptors, std::vector<DMatch>& matches, InputArrayOfArrays masks )611{612CV_INSTRUMENT_REGION();613614std::vector<std::vector<DMatch> > knnMatches;615knnMatch( queryDescriptors, knnMatches, 1, masks, true /*compactResult*/ );616convertMatches( knnMatches, matches );617}618619void DescriptorMatcher::checkMasks( InputArrayOfArrays _masks, int queryDescriptorsCount ) const620{621std::vector<Mat> masks;622_masks.getMatVector(masks);623624if( isMaskSupported() && !masks.empty() )625{626// Check masks627size_t imageCount = std::max(trainDescCollection.size(), utrainDescCollection.size() );628CV_Assert( masks.size() == imageCount );629for( size_t i = 0; i < imageCount; i++ )630{631if( !masks[i].empty() && (!trainDescCollection[i].empty() || !utrainDescCollection[i].empty() ) )632{633int rows = trainDescCollection[i].empty() ? utrainDescCollection[i].rows : trainDescCollection[i].rows;634CV_Assert( masks[i].rows == queryDescriptorsCount &&635masks[i].cols == rows && masks[i].type() == CV_8UC1);636}637}638}639}640641void DescriptorMatcher::knnMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,642InputArrayOfArrays masks, bool compactResult )643{644CV_INSTRUMENT_REGION();645646if( empty() || queryDescriptors.empty() )647return;648649CV_Assert( knn > 0 );650651checkMasks( masks, queryDescriptors.size().height );652653train();654knnMatchImpl( queryDescriptors, matches, knn, masks, compactResult );655}656657void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,658InputArrayOfArrays masks, bool compactResult )659{660CV_INSTRUMENT_REGION();661662matches.clear();663if( empty() || queryDescriptors.empty() )664return;665666CV_Assert( maxDistance > std::numeric_limits<float>::epsilon() );667668checkMasks( masks, queryDescriptors.size().height );669670train();671radiusMatchImpl( queryDescriptors, matches, maxDistance, masks, compactResult );672}673674void DescriptorMatcher::read( const FileNode& )675{}676677void DescriptorMatcher::write( FileStorage& ) const678{}679680bool DescriptorMatcher::isPossibleMatch( InputArray _mask, int queryIdx, int trainIdx )681{682Mat mask = _mask.getMat();683return mask.empty() || mask.at<uchar>(queryIdx, trainIdx);684}685686bool DescriptorMatcher::isMaskedOut( InputArrayOfArrays _masks, int queryIdx )687{688std::vector<Mat> masks;689_masks.getMatVector(masks);690691size_t outCount = 0;692for( size_t i = 0; i < masks.size(); i++ )693{694if( !masks[i].empty() && (countNonZero(masks[i].row(queryIdx)) == 0) )695outCount++;696}697698return !masks.empty() && outCount == masks.size() ;699}700701702////////////////////////////////////////////////////// BruteForceMatcher /////////////////////////////////////////////////703704BFMatcher::BFMatcher( int _normType, bool _crossCheck )705{706normType = _normType;707crossCheck = _crossCheck;708}709710Ptr<BFMatcher> BFMatcher::create(int _normType, bool _crossCheck )711{712return makePtr<BFMatcher>(_normType, _crossCheck);713}714715Ptr<DescriptorMatcher> BFMatcher::clone( bool emptyTrainData ) const716{717Ptr<BFMatcher> matcher = makePtr<BFMatcher>(normType, crossCheck);718if( !emptyTrainData )719{720matcher->trainDescCollection.resize(trainDescCollection.size());721std::transform( trainDescCollection.begin(), trainDescCollection.end(),722matcher->trainDescCollection.begin(), clone_op );723}724return matcher;725}726727#ifdef HAVE_OPENCL728static bool ocl_match(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches, int dstType)729{730UMat trainIdx, distance;731if (!ocl_matchSingle(query, _train, trainIdx, distance, dstType))732return false;733if (!ocl_matchDownload(trainIdx, distance, matches))734return false;735return true;736}737738static bool ocl_knnMatch(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches, int k, int dstType, bool compactResult)739{740UMat trainIdx, distance;741if (k != 2)742return false;743if (!ocl_knnMatchSingle(query, _train, trainIdx, distance, dstType))744return false;745if (!ocl_knnMatchDownload(trainIdx, distance, matches, compactResult) )746return false;747return true;748}749#endif750751void BFMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,752InputArrayOfArrays _masks, bool compactResult )753{754int trainDescType = trainDescCollection.empty() ? utrainDescCollection[0].type() : trainDescCollection[0].type();755CV_Assert( _queryDescriptors.type() == trainDescType );756757const int IMGIDX_SHIFT = 18;758const int IMGIDX_ONE = (1 << IMGIDX_SHIFT);759760if( _queryDescriptors.empty() || (trainDescCollection.empty() && utrainDescCollection.empty()))761{762matches.clear();763return;764}765766std::vector<Mat> masks;767_masks.getMatVector(masks);768769if(!trainDescCollection.empty() && !utrainDescCollection.empty())770{771for(int i = 0; i < (int)utrainDescCollection.size(); i++)772{773Mat tempMat;774utrainDescCollection[i].copyTo(tempMat);775trainDescCollection.push_back(tempMat);776}777utrainDescCollection.clear();778}779780#ifdef HAVE_OPENCL781int trainDescVectorSize = trainDescCollection.empty() ? (int)utrainDescCollection.size() : (int)trainDescCollection.size();782Size trainDescSize = trainDescCollection.empty() ? utrainDescCollection[0].size() : trainDescCollection[0].size();783int trainDescOffset = trainDescCollection.empty() ? (int)utrainDescCollection[0].offset : 0;784785if ( ocl::isOpenCLActivated() && _queryDescriptors.isUMat() && _queryDescriptors.dims()<=2 && trainDescVectorSize == 1 &&786_queryDescriptors.type() == CV_32FC1 && _queryDescriptors.offset() == 0 && trainDescOffset == 0 &&787trainDescSize.width == _queryDescriptors.size().width && masks.size() == 1 && masks[0].total() == 0 )788{789if(knn == 1)790{791if(trainDescCollection.empty())792{793if(ocl_match(_queryDescriptors, utrainDescCollection[0], matches, normType))794{795CV_IMPL_ADD(CV_IMPL_OCL);796return;797}798}799else800{801if(ocl_match(_queryDescriptors, trainDescCollection[0], matches, normType))802{803CV_IMPL_ADD(CV_IMPL_OCL);804return;805}806}807}808else809{810if(trainDescCollection.empty())811{812if(ocl_knnMatch(_queryDescriptors, utrainDescCollection[0], matches, knn, normType, compactResult) )813{814CV_IMPL_ADD(CV_IMPL_OCL);815return;816}817}818else819{820if(ocl_knnMatch(_queryDescriptors, trainDescCollection[0], matches, knn, normType, compactResult) )821{822CV_IMPL_ADD(CV_IMPL_OCL);823return;824}825}826}827}828#endif829830Mat queryDescriptors = _queryDescriptors.getMat();831if(trainDescCollection.empty() && !utrainDescCollection.empty())832{833for(int i = 0; i < (int)utrainDescCollection.size(); i++)834{835Mat tempMat;836utrainDescCollection[i].copyTo(tempMat);837trainDescCollection.push_back(tempMat);838}839utrainDescCollection.clear();840}841842matches.reserve(queryDescriptors.rows);843844Mat dist, nidx;845846int iIdx, imgCount = (int)trainDescCollection.size(), update = 0;847int dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ||848(normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;849850CV_Assert( (int64)imgCount*IMGIDX_ONE < INT_MAX );851852for( iIdx = 0; iIdx < imgCount; iIdx++ )853{854CV_Assert( trainDescCollection[iIdx].rows < IMGIDX_ONE );855batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, nidx,856normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck);857update += IMGIDX_ONE;858}859860if( dtype == CV_32S )861{862Mat temp;863dist.convertTo(temp, CV_32F);864dist = temp;865}866867for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )868{869const float* distptr = dist.ptr<float>(qIdx);870const int* nidxptr = nidx.ptr<int>(qIdx);871872matches.push_back( std::vector<DMatch>() );873std::vector<DMatch>& mq = matches.back();874mq.reserve(knn);875876for( int k = 0; k < nidx.cols; k++ )877{878if( nidxptr[k] < 0 )879break;880mq.push_back( DMatch(qIdx, nidxptr[k] & (IMGIDX_ONE - 1),881nidxptr[k] >> IMGIDX_SHIFT, distptr[k]) );882}883884if( mq.empty() && compactResult )885matches.pop_back();886}887}888889#ifdef HAVE_OPENCL890static bool ocl_radiusMatch(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches,891float maxDistance, int dstType, bool compactResult)892{893UMat trainIdx, distance, nMatches;894if (!ocl_radiusMatchSingle(query, _train, trainIdx, distance, nMatches, maxDistance, dstType))895return false;896if (!ocl_radiusMatchDownload(trainIdx, distance, nMatches, matches, compactResult))897return false;898return true;899}900#endif901902void BFMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches,903float maxDistance, InputArrayOfArrays _masks, bool compactResult )904{905int trainDescType = trainDescCollection.empty() ? utrainDescCollection[0].type() : trainDescCollection[0].type();906CV_Assert( _queryDescriptors.type() == trainDescType );907908if( _queryDescriptors.empty() || (trainDescCollection.empty() && utrainDescCollection.empty()))909{910matches.clear();911return;912}913914std::vector<Mat> masks;915_masks.getMatVector(masks);916917if(!trainDescCollection.empty() && !utrainDescCollection.empty())918{919for(int i = 0; i < (int)utrainDescCollection.size(); i++)920{921Mat tempMat;922utrainDescCollection[i].copyTo(tempMat);923trainDescCollection.push_back(tempMat);924}925utrainDescCollection.clear();926}927928#ifdef HAVE_OPENCL929int trainDescVectorSize = trainDescCollection.empty() ? (int)utrainDescCollection.size() : (int)trainDescCollection.size();930Size trainDescSize = trainDescCollection.empty() ? utrainDescCollection[0].size() : trainDescCollection[0].size();931int trainDescOffset = trainDescCollection.empty() ? (int)utrainDescCollection[0].offset : 0;932933if ( ocl::isOpenCLActivated() && _queryDescriptors.isUMat() && _queryDescriptors.dims()<=2 && trainDescVectorSize == 1 &&934_queryDescriptors.type() == CV_32FC1 && _queryDescriptors.offset() == 0 && trainDescOffset == 0 &&935trainDescSize.width == _queryDescriptors.size().width && masks.size() == 1 && masks[0].total() == 0 )936{937if (trainDescCollection.empty())938{939if(ocl_radiusMatch(_queryDescriptors, utrainDescCollection[0], matches, maxDistance, normType, compactResult) )940{941CV_IMPL_ADD(CV_IMPL_OCL);942return;943}944}945else946{947if (ocl_radiusMatch(_queryDescriptors, trainDescCollection[0], matches, maxDistance, normType, compactResult) )948{949CV_IMPL_ADD(CV_IMPL_OCL);950return;951}952}953}954#endif955956Mat queryDescriptors = _queryDescriptors.getMat();957if(trainDescCollection.empty() && !utrainDescCollection.empty())958{959for(int i = 0; i < (int)utrainDescCollection.size(); i++)960{961Mat tempMat;962utrainDescCollection[i].copyTo(tempMat);963trainDescCollection.push_back(tempMat);964}965utrainDescCollection.clear();966}967968matches.resize(queryDescriptors.rows);969Mat dist, distf;970971int iIdx, imgCount = (int)trainDescCollection.size();972int dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ||973(normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;974975for( iIdx = 0; iIdx < imgCount; iIdx++ )976{977batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, noArray(),978normType, 0, masks.empty() ? Mat() : masks[iIdx], 0, false);979if( dtype == CV_32S )980dist.convertTo(distf, CV_32F);981else982distf = dist;983984for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )985{986const float* distptr = distf.ptr<float>(qIdx);987988std::vector<DMatch>& mq = matches[qIdx];989for( int k = 0; k < distf.cols; k++ )990{991if( distptr[k] <= maxDistance )992mq.push_back( DMatch(qIdx, k, iIdx, distptr[k]) );993}994}995}996997int qIdx0 = 0;998for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )999{1000if( matches[qIdx].empty() && compactResult )1001continue;10021003if( qIdx0 < qIdx )1004std::swap(matches[qIdx], matches[qIdx0]);10051006std::sort( matches[qIdx0].begin(), matches[qIdx0].end() );1007qIdx0++;1008}1009}10101011///////////////////////////////////////////////////////////////////////////////////////////////////////10121013/*1014* Factory function for DescriptorMatcher creating1015*/1016Ptr<DescriptorMatcher> DescriptorMatcher::create( const String& descriptorMatcherType )1017{1018Ptr<DescriptorMatcher> dm;1019#ifdef HAVE_OPENCV_FLANN1020if( !descriptorMatcherType.compare( "FlannBased" ) )1021{1022dm = makePtr<FlannBasedMatcher>();1023}1024else1025#endif1026if( !descriptorMatcherType.compare( "BruteForce" ) ) // L21027{1028dm = makePtr<BFMatcher>(int(NORM_L2)); // anonymous enums can't be template parameters1029}1030else if( !descriptorMatcherType.compare( "BruteForce-SL2" ) ) // Squared L21031{1032dm = makePtr<BFMatcher>(int(NORM_L2SQR));1033}1034else if( !descriptorMatcherType.compare( "BruteForce-L1" ) )1035{1036dm = makePtr<BFMatcher>(int(NORM_L1));1037}1038else if( !descriptorMatcherType.compare("BruteForce-Hamming") ||1039!descriptorMatcherType.compare("BruteForce-HammingLUT") )1040{1041dm = makePtr<BFMatcher>(int(NORM_HAMMING));1042}1043else if( !descriptorMatcherType.compare("BruteForce-Hamming(2)") )1044{1045dm = makePtr<BFMatcher>(int(NORM_HAMMING2));1046}1047else1048CV_Error( Error::StsBadArg, "Unknown matcher name" );10491050return dm;1051}10521053Ptr<DescriptorMatcher> DescriptorMatcher::create( const MatcherType& matcherType )1054{105510561057String name;10581059switch(matcherType)1060{1061#ifdef HAVE_OPENCV_FLANN1062case FLANNBASED:1063name = "FlannBased";1064break;1065#endif1066case BRUTEFORCE:1067name = "BruteForce";1068break;1069case BRUTEFORCE_L1:1070name = "BruteForce-L1";1071break;1072case BRUTEFORCE_HAMMING:1073name = "BruteForce-Hamming";1074break;1075case BRUTEFORCE_HAMMINGLUT:1076name = "BruteForce-HammingLUT";1077break;1078case BRUTEFORCE_SL2:1079name = "BruteForce-SL2";1080break;1081default:1082CV_Error( Error::StsBadArg, "Specified descriptor matcher type is not supported." );1083break;1084}10851086return DescriptorMatcher::create(name);10871088}10891090#ifdef HAVE_OPENCV_FLANN10911092/*1093* Flann based matcher1094*/1095FlannBasedMatcher::FlannBasedMatcher( const Ptr<flann::IndexParams>& _indexParams, const Ptr<flann::SearchParams>& _searchParams )1096: indexParams(_indexParams), searchParams(_searchParams), addedDescCount(0)1097{1098CV_Assert( _indexParams );1099CV_Assert( _searchParams );1100}11011102Ptr<FlannBasedMatcher> FlannBasedMatcher::create()1103{1104return makePtr<FlannBasedMatcher>();1105}11061107void FlannBasedMatcher::add( InputArrayOfArrays _descriptors )1108{1109DescriptorMatcher::add( _descriptors );11101111if( _descriptors.isUMatVector() )1112{1113std::vector<UMat> descriptors;1114_descriptors.getUMatVector( descriptors );11151116for( size_t i = 0; i < descriptors.size(); i++ )1117{1118addedDescCount += descriptors[i].rows;1119}1120}1121else if( _descriptors.isUMat() )1122{1123addedDescCount += _descriptors.getUMat().rows;1124}1125else if( _descriptors.isMatVector() )1126{1127std::vector<Mat> descriptors;1128_descriptors.getMatVector(descriptors);1129for( size_t i = 0; i < descriptors.size(); i++ )1130{1131addedDescCount += descriptors[i].rows;1132}1133}1134else if( _descriptors.isMat() )1135{1136addedDescCount += _descriptors.getMat().rows;1137}1138else1139{1140CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() );1141}1142}11431144void FlannBasedMatcher::clear()1145{1146DescriptorMatcher::clear();11471148mergedDescriptors.clear();1149flannIndex.release();11501151addedDescCount = 0;1152}11531154void FlannBasedMatcher::train()1155{1156CV_INSTRUMENT_REGION();11571158if( !flannIndex || mergedDescriptors.size() < addedDescCount )1159{1160// FIXIT: Workaround for 'utrainDescCollection' issue (PR #2142)1161if (!utrainDescCollection.empty())1162{1163CV_Assert(trainDescCollection.size() == 0);1164for (size_t i = 0; i < utrainDescCollection.size(); ++i)1165trainDescCollection.push_back(utrainDescCollection[i].getMat(ACCESS_READ));1166}1167mergedDescriptors.set( trainDescCollection );1168flannIndex = makePtr<flann::Index>( mergedDescriptors.getDescriptors(), *indexParams );1169}1170}11711172using namespace cv::flann;11731174void FlannBasedMatcher::read( const FileNode& fn)1175{1176if (!indexParams)1177indexParams = makePtr<flann::IndexParams>();11781179FileNode ip = fn["indexParams"];1180CV_Assert(ip.type() == FileNode::SEQ);11811182for(int i = 0; i < (int)ip.size(); ++i)1183{1184CV_Assert(ip[i].type() == FileNode::MAP);1185String _name = (String)ip[i]["name"];1186FlannIndexType type = (FlannIndexType)(int)ip[i]["type"];1187CV_CheckLE((int)type, (int)LAST_VALUE_FLANN_INDEX_TYPE, "");11881189switch(type)1190{1191case FLANN_INDEX_TYPE_8U:1192case FLANN_INDEX_TYPE_8S:1193case FLANN_INDEX_TYPE_16U:1194case FLANN_INDEX_TYPE_16S:1195case FLANN_INDEX_TYPE_32S:1196indexParams->setInt(_name, (int) ip[i]["value"]);1197break;1198case FLANN_INDEX_TYPE_32F:1199indexParams->setFloat(_name, (float) ip[i]["value"]);1200break;1201case FLANN_INDEX_TYPE_64F:1202indexParams->setDouble(_name, (double) ip[i]["value"]);1203break;1204case FLANN_INDEX_TYPE_STRING:1205indexParams->setString(_name, (String) ip[i]["value"]);1206break;1207case FLANN_INDEX_TYPE_BOOL:1208indexParams->setBool(_name, (int) ip[i]["value"] != 0);1209break;1210case FLANN_INDEX_TYPE_ALGORITHM:1211indexParams->setAlgorithm((int) ip[i]["value"]);1212break;1213// don't default: - compiler warning is here1214};1215}12161217if (!searchParams)1218searchParams = makePtr<flann::SearchParams>();12191220FileNode sp = fn["searchParams"];1221CV_Assert(sp.type() == FileNode::SEQ);12221223for(int i = 0; i < (int)sp.size(); ++i)1224{1225CV_Assert(sp[i].type() == FileNode::MAP);1226String _name = (String)sp[i]["name"];1227FlannIndexType type = (FlannIndexType)(int)sp[i]["type"];1228CV_CheckLE((int)type, (int)LAST_VALUE_FLANN_INDEX_TYPE, "");12291230switch(type)1231{1232case FLANN_INDEX_TYPE_8U:1233case FLANN_INDEX_TYPE_8S:1234case FLANN_INDEX_TYPE_16U:1235case FLANN_INDEX_TYPE_16S:1236case FLANN_INDEX_TYPE_32S:1237searchParams->setInt(_name, (int) sp[i]["value"]);1238break;1239case FLANN_INDEX_TYPE_32F:1240searchParams->setFloat(_name, (float) ip[i]["value"]);1241break;1242case FLANN_INDEX_TYPE_64F:1243searchParams->setDouble(_name, (double) ip[i]["value"]);1244break;1245case FLANN_INDEX_TYPE_STRING:1246searchParams->setString(_name, (String) ip[i]["value"]);1247break;1248case FLANN_INDEX_TYPE_BOOL:1249searchParams->setBool(_name, (int) ip[i]["value"] != 0);1250break;1251case FLANN_INDEX_TYPE_ALGORITHM:1252searchParams->setAlgorithm((int) ip[i]["value"]);1253break;1254// don't default: - compiler warning is here1255};1256}12571258flannIndex.release();1259}12601261void FlannBasedMatcher::write( FileStorage& fs) const1262{1263writeFormat(fs);1264fs << "indexParams" << "[";12651266if (indexParams)1267{1268std::vector<String> names;1269std::vector<FlannIndexType> types;1270std::vector<String> strValues;1271std::vector<double> numValues;12721273indexParams->getAll(names, types, strValues, numValues);12741275for(size_t i = 0; i < names.size(); ++i)1276{1277fs << "{" << "name" << names[i] << "type" << types[i] << "value";1278FlannIndexType type = (FlannIndexType)types[i];1279if ((int)type < 0 || type > LAST_VALUE_FLANN_INDEX_TYPE)1280{1281fs << (double)numValues[i];1282fs << "typename" << strValues[i];1283fs << "}";1284continue;1285}1286switch(type)1287{1288case FLANN_INDEX_TYPE_8U:1289fs << (uchar)numValues[i];1290break;1291case FLANN_INDEX_TYPE_8S:1292fs << (char)numValues[i];1293break;1294case FLANN_INDEX_TYPE_16U:1295fs << (ushort)numValues[i];1296break;1297case FLANN_INDEX_TYPE_16S:1298fs << (short)numValues[i];1299break;1300case FLANN_INDEX_TYPE_32S:1301case FLANN_INDEX_TYPE_BOOL:1302case FLANN_INDEX_TYPE_ALGORITHM:1303fs << (int)numValues[i];1304break;1305case FLANN_INDEX_TYPE_32F:1306fs << (float)numValues[i];1307break;1308case FLANN_INDEX_TYPE_64F:1309fs << (double)numValues[i];1310break;1311case FLANN_INDEX_TYPE_STRING:1312fs << strValues[i];1313break;1314// don't default: - compiler warning is here1315}1316fs << "}";1317}1318}13191320fs << "]" << "searchParams" << "[";13211322if (searchParams)1323{1324std::vector<String> names;1325std::vector<FlannIndexType> types;1326std::vector<String> strValues;1327std::vector<double> numValues;13281329searchParams->getAll(names, types, strValues, numValues);13301331for(size_t i = 0; i < names.size(); ++i)1332{1333fs << "{" << "name" << names[i] << "type" << types[i] << "value";1334FlannIndexType type = (FlannIndexType)types[i];1335if ((int)type < 0 || type > LAST_VALUE_FLANN_INDEX_TYPE)1336{1337fs << (double)numValues[i];1338fs << "typename" << strValues[i];1339fs << "}";1340continue;1341}1342switch(type)1343{1344case FLANN_INDEX_TYPE_8U:1345fs << (uchar)numValues[i];1346break;1347case FLANN_INDEX_TYPE_8S:1348fs << (char)numValues[i];1349break;1350case FLANN_INDEX_TYPE_16U:1351fs << (ushort)numValues[i];1352break;1353case FLANN_INDEX_TYPE_16S:1354fs << (short)numValues[i];1355break;1356case FLANN_INDEX_TYPE_32S:1357case FLANN_INDEX_TYPE_BOOL:1358case FLANN_INDEX_TYPE_ALGORITHM:1359fs << (int)numValues[i];1360break;1361case CV_32F:1362fs << (float)numValues[i];1363break;1364case CV_64F:1365fs << (double)numValues[i];1366break;1367case FLANN_INDEX_TYPE_STRING:1368fs << strValues[i];1369break;1370// don't default: - compiler warning is here1371}1372fs << "}";1373}1374}1375fs << "]";1376}13771378bool FlannBasedMatcher::isMaskSupported() const1379{1380return false;1381}13821383Ptr<DescriptorMatcher> FlannBasedMatcher::clone( bool emptyTrainData ) const1384{1385Ptr<FlannBasedMatcher> matcher = makePtr<FlannBasedMatcher>(indexParams, searchParams);1386if( !emptyTrainData )1387{1388CV_Error( Error::StsNotImplemented, "deep clone functionality is not implemented, because "1389"Flann::Index has not copy constructor or clone method ");1390#if 01391//matcher->flannIndex;1392matcher->addedDescCount = addedDescCount;1393matcher->mergedDescriptors = DescriptorCollection( mergedDescriptors );1394std::transform( trainDescCollection.begin(), trainDescCollection.end(),1395matcher->trainDescCollection.begin(), clone_op );1396#endif1397}1398return matcher;1399}14001401void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collection, const Mat& indices, const Mat& dists,1402std::vector<std::vector<DMatch> >& matches )1403{1404matches.resize( indices.rows );1405for( int i = 0; i < indices.rows; i++ )1406{1407for( int j = 0; j < indices.cols; j++ )1408{1409int idx = indices.at<int>(i, j);1410if( idx >= 0 )1411{1412int imgIdx, trainIdx;1413collection.getLocalIdx( idx, imgIdx, trainIdx );1414float dist = 0;1415if (dists.type() == CV_32S)1416dist = static_cast<float>( dists.at<int>(i,j) );1417else1418dist = std::sqrt(dists.at<float>(i,j));1419matches[i].push_back( DMatch( i, trainIdx, imgIdx, dist ) );1420}1421}1422}1423}14241425void FlannBasedMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,1426InputArrayOfArrays /*masks*/, bool /*compactResult*/ )1427{1428CV_INSTRUMENT_REGION();14291430Mat queryDescriptors = _queryDescriptors.getMat();1431Mat indices( queryDescriptors.rows, knn, CV_32SC1 );1432Mat dists( queryDescriptors.rows, knn, CV_32FC1);1433flannIndex->knnSearch( queryDescriptors, indices, dists, knn, *searchParams );14341435convertToDMatches( mergedDescriptors, indices, dists, matches );1436}14371438void FlannBasedMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,1439InputArrayOfArrays /*masks*/, bool /*compactResult*/ )1440{1441CV_INSTRUMENT_REGION();14421443Mat queryDescriptors = _queryDescriptors.getMat();1444const int count = mergedDescriptors.size(); // TODO do count as param?1445Mat indices( queryDescriptors.rows, count, CV_32SC1, Scalar::all(-1) );1446Mat dists( queryDescriptors.rows, count, CV_32FC1, Scalar::all(-1) );1447for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )1448{1449Mat queryDescriptorsRow = queryDescriptors.row(qIdx);1450Mat indicesRow = indices.row(qIdx);1451Mat distsRow = dists.row(qIdx);1452flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, count, *searchParams );1453}14541455convertToDMatches( mergedDescriptors, indices, dists, matches );1456}14571458#endif14591460}146114621463