Home | History | Annotate | Download | only in src
      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 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, 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 documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // 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 damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "precomp.hpp"
     43 #include <limits>
     44 #include "opencl_kernels_features2d.hpp"
     45 
     46 #if defined(HAVE_EIGEN) && EIGEN_WORLD_VERSION == 2
     47 #include <Eigen/Array>
     48 #endif
     49 
     50 namespace cv
     51 {
     52 
     53 /////////////////////// ocl functions for BFMatcher ///////////////////////////
     54 
     55 static void ensureSizeIsEnough(int rows, int cols, int type, UMat &m)
     56 {
     57     if (m.type() == type && m.rows >= rows && m.cols >= cols)
     58         m = m(Rect(0, 0, cols, rows));
     59     else
     60         m.create(rows, cols, type);
     61 }
     62 
     63 static bool ocl_matchSingle(InputArray query, InputArray train,
     64         UMat &trainIdx, UMat &distance, int distType)
     65 {
     66     if (query.empty() || train.empty())
     67         return false;
     68 
     69     const int query_rows = query.rows();
     70     const int query_cols = query.cols();
     71 
     72     ensureSizeIsEnough(1, query_rows, CV_32S, trainIdx);
     73     ensureSizeIsEnough(1, query_rows, CV_32F, distance);
     74 
     75     ocl::Device devDef = ocl::Device::getDefault();
     76 
     77     UMat uquery = query.getUMat(), utrain = train.getUMat();
     78     int kercn = 1;
     79     if (devDef.isIntel() &&
     80         (0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&
     81         (0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))
     82         kercn = 4;
     83 
     84     int block_size = 16;
     85     int max_desc_len = 0;
     86     bool is_cpu = devDef.type() == ocl::Device::TYPE_CPU;
     87     if (query_cols <= 64)
     88         max_desc_len = 64 / kercn;
     89     else if (query_cols <= 128 && !is_cpu)
     90         max_desc_len = 128 / kercn;
     91 
     92     int depth = query.depth();
     93     cv::String opts;
     94     opts = 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",
     95         ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size, max_desc_len);
     96     ocl::Kernel k("BruteForceMatch_Match", ocl::features2d::brute_force_match_oclsrc, opts);
     97     if(k.empty())
     98         return false;
     99 
    100     size_t globalSize[] = {(query.size().height + block_size - 1) / block_size * block_size, block_size};
    101     size_t localSize[] = {block_size, block_size};
    102 
    103     int idx = 0;
    104     idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));
    105     idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));
    106     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));
    107     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));
    108     idx = k.set(idx, uquery.rows);
    109     idx = k.set(idx, uquery.cols);
    110     idx = k.set(idx, utrain.rows);
    111     idx = k.set(idx, utrain.cols);
    112     idx = k.set(idx, (int)(uquery.step / sizeof(float)));
    113 
    114     return k.run(2, globalSize, localSize, false);
    115 }
    116 
    117 static bool ocl_matchConvert(const Mat &trainIdx, const Mat &distance, std::vector< std::vector<DMatch> > &matches)
    118 {
    119     if (trainIdx.empty() || distance.empty())
    120         return false;
    121 
    122     if( (trainIdx.type() != CV_32SC1) || (distance.type() != CV_32FC1 || distance.cols != trainIdx.cols) )
    123         return false;
    124 
    125     const int nQuery = trainIdx.cols;
    126 
    127     matches.clear();
    128     matches.reserve(nQuery);
    129 
    130     const int *trainIdx_ptr = trainIdx.ptr<int>();
    131     const float *distance_ptr =  distance.ptr<float>();
    132     for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx, ++trainIdx_ptr, ++distance_ptr)
    133     {
    134         int trainIndex = *trainIdx_ptr;
    135 
    136         if (trainIndex == -1)
    137             continue;
    138 
    139         float dst = *distance_ptr;
    140 
    141         DMatch m(queryIdx, trainIndex, 0, dst);
    142 
    143         std::vector<DMatch> temp;
    144         temp.push_back(m);
    145         matches.push_back(temp);
    146     }
    147     return true;
    148 }
    149 
    150 static bool ocl_matchDownload(const UMat &trainIdx, const UMat &distance, std::vector< std::vector<DMatch> > &matches)
    151 {
    152     if (trainIdx.empty() || distance.empty())
    153         return false;
    154 
    155     Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);
    156     Mat distanceCPU = distance.getMat(ACCESS_READ);
    157 
    158     return ocl_matchConvert(trainIdxCPU, distanceCPU, matches);
    159 }
    160 
    161 static bool ocl_knnMatchSingle(InputArray query, InputArray train, UMat &trainIdx,
    162                                UMat &distance, int distType)
    163 {
    164     if (query.empty() || train.empty())
    165         return false;
    166 
    167     const int query_rows = query.rows();
    168     const int query_cols = query.cols();
    169 
    170     ensureSizeIsEnough(1, query_rows, CV_32SC2, trainIdx);
    171     ensureSizeIsEnough(1, query_rows, CV_32FC2, distance);
    172 
    173     trainIdx.setTo(Scalar::all(-1));
    174 
    175     ocl::Device devDef = ocl::Device::getDefault();
    176 
    177     UMat uquery = query.getUMat(), utrain = train.getUMat();
    178     int kercn = 1;
    179     if (devDef.isIntel() &&
    180         (0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&
    181         (0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))
    182         kercn = 4;
    183 
    184     int block_size = 16;
    185     int max_desc_len = 0;
    186     bool is_cpu = devDef.type() == ocl::Device::TYPE_CPU;
    187     if (query_cols <= 64)
    188         max_desc_len = 64 / kercn;
    189     else if (query_cols <= 128 && !is_cpu)
    190         max_desc_len = 128 / kercn;
    191 
    192     int depth = query.depth();
    193     cv::String opts;
    194     opts = 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",
    195         ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size, max_desc_len);
    196     ocl::Kernel k("BruteForceMatch_knnMatch", ocl::features2d::brute_force_match_oclsrc, opts);
    197     if(k.empty())
    198         return false;
    199 
    200     size_t globalSize[] = {(query_rows + block_size - 1) / block_size * block_size, block_size};
    201     size_t localSize[] = {block_size, block_size};
    202 
    203     int idx = 0;
    204     idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));
    205     idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));
    206     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));
    207     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));
    208     idx = k.set(idx, uquery.rows);
    209     idx = k.set(idx, uquery.cols);
    210     idx = k.set(idx, utrain.rows);
    211     idx = k.set(idx, utrain.cols);
    212     idx = k.set(idx, (int)(uquery.step / sizeof(float)));
    213 
    214     return k.run(2, globalSize, localSize, false);
    215 }
    216 
    217 static bool ocl_knnMatchConvert(const Mat &trainIdx, const Mat &distance, std::vector< std::vector<DMatch> > &matches, bool compactResult)
    218 {
    219     if (trainIdx.empty() || distance.empty())
    220         return false;
    221 
    222     if(trainIdx.type() != CV_32SC2 && trainIdx.type() != CV_32SC1) return false;
    223     if(distance.type() != CV_32FC2 && distance.type() != CV_32FC1)return false;
    224     if(distance.size() != trainIdx.size()) return false;
    225     if(!trainIdx.isContinuous() || !distance.isContinuous()) return false;
    226 
    227     const int nQuery = trainIdx.type() == CV_32SC2 ? trainIdx.cols : trainIdx.rows;
    228     const int k = trainIdx.type() == CV_32SC2 ? 2 : trainIdx.cols;
    229 
    230     matches.clear();
    231     matches.reserve(nQuery);
    232 
    233     const int *trainIdx_ptr = trainIdx.ptr<int>();
    234     const float *distance_ptr = distance.ptr<float>();
    235 
    236     for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx)
    237     {
    238         matches.push_back(std::vector<DMatch>());
    239         std::vector<DMatch> &curMatches = matches.back();
    240         curMatches.reserve(k);
    241 
    242         for (int i = 0; i < k; ++i, ++trainIdx_ptr, ++distance_ptr)
    243         {
    244             int trainIndex = *trainIdx_ptr;
    245 
    246             if (trainIndex != -1)
    247             {
    248                 float dst = *distance_ptr;
    249 
    250                 DMatch m(queryIdx, trainIndex, 0, dst);
    251 
    252                 curMatches.push_back(m);
    253             }
    254         }
    255 
    256         if (compactResult && curMatches.empty())
    257             matches.pop_back();
    258     }
    259     return true;
    260 }
    261 
    262 static bool ocl_knnMatchDownload(const UMat &trainIdx, const UMat &distance, std::vector< std::vector<DMatch> > &matches, bool compactResult)
    263 {
    264     if (trainIdx.empty() || distance.empty())
    265         return false;
    266 
    267     Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);
    268     Mat distanceCPU = distance.getMat(ACCESS_READ);
    269 
    270     return ocl_knnMatchConvert(trainIdxCPU, distanceCPU, matches, compactResult);
    271 }
    272 
    273 static bool ocl_radiusMatchSingle(InputArray query, InputArray train,
    274         UMat &trainIdx,   UMat &distance, UMat &nMatches, float maxDistance, int distType)
    275 {
    276     if (query.empty() || train.empty())
    277         return false;
    278 
    279     const int query_rows = query.rows();
    280     const int train_rows = train.rows();
    281 
    282     ensureSizeIsEnough(1, query_rows, CV_32SC1, nMatches);
    283 
    284     if (trainIdx.empty())
    285     {
    286         ensureSizeIsEnough(query_rows, std::max((train_rows / 100), 10), CV_32SC1, trainIdx);
    287         ensureSizeIsEnough(query_rows, std::max((train_rows / 100), 10), CV_32FC1, distance);
    288     }
    289 
    290     nMatches.setTo(Scalar::all(0));
    291 
    292     ocl::Device devDef = ocl::Device::getDefault();
    293     UMat uquery = query.getUMat(), utrain = train.getUMat();
    294     int kercn = 1;
    295     if (devDef.isIntel() &&
    296         (0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&
    297         (0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))
    298         kercn = 4;
    299 
    300     int block_size = 16;
    301     int depth = query.depth();
    302     cv::String opts;
    303     opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d",
    304         ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size);
    305     ocl::Kernel k("BruteForceMatch_RadiusMatch", ocl::features2d::brute_force_match_oclsrc, opts);
    306     if (k.empty())
    307         return false;
    308 
    309     size_t globalSize[] = {(train_rows + block_size - 1) / block_size * block_size, (query_rows + block_size - 1) / block_size * block_size};
    310     size_t localSize[] = {block_size, block_size};
    311 
    312     int idx = 0;
    313     idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));
    314     idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));
    315     idx = k.set(idx, maxDistance);
    316     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));
    317     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));
    318     idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(nMatches));
    319     idx = k.set(idx, uquery.rows);
    320     idx = k.set(idx, uquery.cols);
    321     idx = k.set(idx, utrain.rows);
    322     idx = k.set(idx, utrain.cols);
    323     idx = k.set(idx, trainIdx.cols);
    324     idx = k.set(idx, (int)(uquery.step / sizeof(float)));
    325     idx = k.set(idx, (int)(trainIdx.step / sizeof(int)));
    326 
    327     return k.run(2, globalSize, localSize, false);
    328 }
    329 
    330 static bool ocl_radiusMatchConvert(const Mat &trainIdx, const Mat &distance, const Mat &_nMatches,
    331         std::vector< std::vector<DMatch> > &matches, bool compactResult)
    332 {
    333     if (trainIdx.empty() || distance.empty() || _nMatches.empty())
    334         return false;
    335 
    336     if( (trainIdx.type() != CV_32SC1) ||
    337         (distance.type() != CV_32FC1 || distance.size() != trainIdx.size()) ||
    338         (_nMatches.type() != CV_32SC1 || _nMatches.cols != trainIdx.rows) )
    339         return false;
    340 
    341     const int nQuery = trainIdx.rows;
    342 
    343     matches.clear();
    344     matches.reserve(nQuery);
    345 
    346     const int *nMatches_ptr = _nMatches.ptr<int>();
    347 
    348     for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx)
    349     {
    350         const int *trainIdx_ptr = trainIdx.ptr<int>(queryIdx);
    351         const float *distance_ptr = distance.ptr<float>(queryIdx);
    352 
    353         const int nMatches = std::min(nMatches_ptr[queryIdx], trainIdx.cols);
    354 
    355         if (nMatches == 0)
    356         {
    357             if (!compactResult)
    358                 matches.push_back(std::vector<DMatch>());
    359             continue;
    360         }
    361 
    362         matches.push_back(std::vector<DMatch>(nMatches));
    363         std::vector<DMatch> &curMatches = matches.back();
    364 
    365         for (int i = 0; i < nMatches; ++i, ++trainIdx_ptr, ++distance_ptr)
    366         {
    367             int trainIndex = *trainIdx_ptr;
    368 
    369             float dst = *distance_ptr;
    370 
    371             DMatch m(queryIdx, trainIndex, 0, dst);
    372 
    373             curMatches[i] = m;
    374         }
    375 
    376         std::sort(curMatches.begin(), curMatches.end());
    377     }
    378     return true;
    379 }
    380 
    381 static bool ocl_radiusMatchDownload(const UMat &trainIdx, const UMat &distance, const UMat &nMatches,
    382         std::vector< std::vector<DMatch> > &matches, bool compactResult)
    383 {
    384     if (trainIdx.empty() || distance.empty() || nMatches.empty())
    385         return false;
    386 
    387     Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);
    388     Mat distanceCPU = distance.getMat(ACCESS_READ);
    389     Mat nMatchesCPU = nMatches.getMat(ACCESS_READ);
    390 
    391     return ocl_radiusMatchConvert(trainIdxCPU, distanceCPU, nMatchesCPU, matches, compactResult);
    392 }
    393 
    394 /****************************************************************************************\
    395 *                                      DescriptorMatcher                                 *
    396 \****************************************************************************************/
    397 DescriptorMatcher::DescriptorCollection::DescriptorCollection()
    398 {}
    399 
    400 DescriptorMatcher::DescriptorCollection::DescriptorCollection( const DescriptorCollection& collection )
    401 {
    402     mergedDescriptors = collection.mergedDescriptors.clone();
    403     std::copy( collection.startIdxs.begin(), collection.startIdxs.begin(), startIdxs.begin() );
    404 }
    405 
    406 DescriptorMatcher::DescriptorCollection::~DescriptorCollection()
    407 {}
    408 
    409 void DescriptorMatcher::DescriptorCollection::set( const std::vector<Mat>& descriptors )
    410 {
    411     clear();
    412 
    413     size_t imageCount = descriptors.size();
    414     CV_Assert( imageCount > 0 );
    415 
    416     startIdxs.resize( imageCount );
    417 
    418     int dim = -1;
    419     int type = -1;
    420     startIdxs[0] = 0;
    421     for( size_t i = 1; i < imageCount; i++ )
    422     {
    423         int s = 0;
    424         if( !descriptors[i-1].empty() )
    425         {
    426             dim = descriptors[i-1].cols;
    427             type = descriptors[i-1].type();
    428             s = descriptors[i-1].rows;
    429         }
    430         startIdxs[i] = startIdxs[i-1] + s;
    431     }
    432     if( imageCount == 1 )
    433     {
    434         if( descriptors[0].empty() ) return;
    435 
    436         dim = descriptors[0].cols;
    437         type = descriptors[0].type();
    438     }
    439     CV_Assert( dim > 0 );
    440 
    441     int count = startIdxs[imageCount-1] + descriptors[imageCount-1].rows;
    442 
    443     if( count > 0 )
    444     {
    445         mergedDescriptors.create( count, dim, type );
    446         for( size_t i = 0; i < imageCount; i++ )
    447         {
    448             if( !descriptors[i].empty() )
    449             {
    450                 CV_Assert( descriptors[i].cols == dim && descriptors[i].type() == type );
    451                 Mat m = mergedDescriptors.rowRange( startIdxs[i], startIdxs[i] + descriptors[i].rows );
    452                 descriptors[i].copyTo(m);
    453             }
    454         }
    455     }
    456 }
    457 
    458 void DescriptorMatcher::DescriptorCollection::clear()
    459 {
    460     startIdxs.clear();
    461     mergedDescriptors.release();
    462 }
    463 
    464 const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int imgIdx, int localDescIdx ) const
    465 {
    466     CV_Assert( imgIdx < (int)startIdxs.size() );
    467     int globalIdx = startIdxs[imgIdx] + localDescIdx;
    468     CV_Assert( globalIdx < (int)size() );
    469 
    470     return getDescriptor( globalIdx );
    471 }
    472 
    473 const Mat& DescriptorMatcher::DescriptorCollection::getDescriptors() const
    474 {
    475     return mergedDescriptors;
    476 }
    477 
    478 const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int globalDescIdx ) const
    479 {
    480     CV_Assert( globalDescIdx < size() );
    481     return mergedDescriptors.row( globalDescIdx );
    482 }
    483 
    484 void DescriptorMatcher::DescriptorCollection::getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const
    485 {
    486     CV_Assert( (globalDescIdx>=0) && (globalDescIdx < size()) );
    487     std::vector<int>::const_iterator img_it = std::upper_bound(startIdxs.begin(), startIdxs.end(), globalDescIdx);
    488     --img_it;
    489     imgIdx = (int)(img_it - startIdxs.begin());
    490     localDescIdx = globalDescIdx - (*img_it);
    491 }
    492 
    493 int DescriptorMatcher::DescriptorCollection::size() const
    494 {
    495     return mergedDescriptors.rows;
    496 }
    497 
    498 /*
    499  * DescriptorMatcher
    500  */
    501 static void convertMatches( const std::vector<std::vector<DMatch> >& knnMatches, std::vector<DMatch>& matches )
    502 {
    503     matches.clear();
    504     matches.reserve( knnMatches.size() );
    505     for( size_t i = 0; i < knnMatches.size(); i++ )
    506     {
    507         CV_Assert( knnMatches[i].size() <= 1 );
    508         if( !knnMatches[i].empty() )
    509             matches.push_back( knnMatches[i][0] );
    510     }
    511 }
    512 
    513 DescriptorMatcher::~DescriptorMatcher()
    514 {}
    515 
    516 void DescriptorMatcher::add( InputArrayOfArrays _descriptors )
    517 {
    518     if(_descriptors.isUMatVector())
    519     {
    520         std::vector<UMat> descriptors;
    521         _descriptors.getUMatVector(descriptors);
    522         utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );
    523     }
    524     else if(_descriptors.isUMat())
    525     {
    526         std::vector<UMat> descriptors = std::vector<UMat>(1, _descriptors.getUMat());
    527         utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );
    528     }
    529     else if(_descriptors.isMatVector())
    530     {
    531         std::vector<Mat> descriptors;
    532         _descriptors.getMatVector(descriptors);
    533         trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
    534     }
    535     else if(_descriptors.isMat())
    536     {
    537         std::vector<Mat> descriptors = std::vector<Mat>(1, _descriptors.getMat());
    538         trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
    539     }
    540     else
    541         CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() );
    542 }
    543 
    544 const std::vector<Mat>& DescriptorMatcher::getTrainDescriptors() const
    545 {
    546     return trainDescCollection;
    547 }
    548 
    549 void DescriptorMatcher::clear()
    550 {
    551     utrainDescCollection.clear();
    552     trainDescCollection.clear();
    553 }
    554 
    555 bool DescriptorMatcher::empty() const
    556 {
    557     return trainDescCollection.empty() && utrainDescCollection.empty();
    558 }
    559 
    560 void DescriptorMatcher::train()
    561 {}
    562 
    563 void DescriptorMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors,
    564                               std::vector<DMatch>& matches, InputArray mask ) const
    565 {
    566     Ptr<DescriptorMatcher> tempMatcher = clone(true);
    567     tempMatcher->add(trainDescriptors);
    568     tempMatcher->match( queryDescriptors, matches, std::vector<Mat>(1, mask.getMat()) );
    569 }
    570 
    571 void DescriptorMatcher::knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,
    572                                   std::vector<std::vector<DMatch> >& matches, int knn,
    573                                   InputArray mask, bool compactResult ) const
    574 {
    575     Ptr<DescriptorMatcher> tempMatcher = clone(true);
    576     tempMatcher->add(trainDescriptors);
    577     tempMatcher->knnMatch( queryDescriptors, matches, knn, std::vector<Mat>(1, mask.getMat()), compactResult );
    578 }
    579 
    580 void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,
    581                                      std::vector<std::vector<DMatch> >& matches, float maxDistance, InputArray mask,
    582                                      bool compactResult ) const
    583 {
    584     Ptr<DescriptorMatcher> tempMatcher = clone(true);
    585     tempMatcher->add(trainDescriptors);
    586     tempMatcher->radiusMatch( queryDescriptors, matches, maxDistance, std::vector<Mat>(1, mask.getMat()), compactResult );
    587 }
    588 
    589 void DescriptorMatcher::match( InputArray queryDescriptors, std::vector<DMatch>& matches, InputArrayOfArrays masks )
    590 {
    591     std::vector<std::vector<DMatch> > knnMatches;
    592     knnMatch( queryDescriptors, knnMatches, 1, masks, true /*compactResult*/ );
    593     convertMatches( knnMatches, matches );
    594 }
    595 
    596 void DescriptorMatcher::checkMasks( InputArrayOfArrays _masks, int queryDescriptorsCount ) const
    597 {
    598     std::vector<Mat> masks;
    599     _masks.getMatVector(masks);
    600 
    601     if( isMaskSupported() && !masks.empty() )
    602     {
    603         // Check masks
    604         size_t imageCount = std::max(trainDescCollection.size(), utrainDescCollection.size() );
    605         CV_Assert( masks.size() == imageCount );
    606         for( size_t i = 0; i < imageCount; i++ )
    607         {
    608             if( !masks[i].empty() && (!trainDescCollection[i].empty() || !utrainDescCollection[i].empty() ) )
    609             {
    610                 int rows = trainDescCollection[i].empty() ? utrainDescCollection[i].rows : trainDescCollection[i].rows;
    611                     CV_Assert( masks[i].rows == queryDescriptorsCount &&
    612                         (masks[i].cols == rows || masks[i].cols == rows) &&
    613                         masks[i].type() == CV_8UC1 );
    614             }
    615         }
    616     }
    617 }
    618 
    619 void DescriptorMatcher::knnMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
    620                                   InputArrayOfArrays masks, bool compactResult )
    621 {
    622     if( empty() || queryDescriptors.empty() )
    623         return;
    624 
    625     CV_Assert( knn > 0 );
    626 
    627     checkMasks( masks, queryDescriptors.size().height );
    628 
    629     train();
    630     knnMatchImpl( queryDescriptors, matches, knn, masks, compactResult );
    631 }
    632 
    633 void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
    634                                      InputArrayOfArrays masks, bool compactResult )
    635 {
    636     matches.clear();
    637     if( empty() || queryDescriptors.empty() )
    638         return;
    639 
    640     CV_Assert( maxDistance > std::numeric_limits<float>::epsilon() );
    641 
    642     checkMasks( masks, queryDescriptors.size().height );
    643 
    644     train();
    645     radiusMatchImpl( queryDescriptors, matches, maxDistance, masks, compactResult );
    646 }
    647 
    648 void DescriptorMatcher::read( const FileNode& )
    649 {}
    650 
    651 void DescriptorMatcher::write( FileStorage& ) const
    652 {}
    653 
    654 bool DescriptorMatcher::isPossibleMatch( InputArray _mask, int queryIdx, int trainIdx )
    655 {
    656     Mat mask = _mask.getMat();
    657     return mask.empty() || mask.at<uchar>(queryIdx, trainIdx);
    658 }
    659 
    660 bool DescriptorMatcher::isMaskedOut( InputArrayOfArrays _masks, int queryIdx )
    661 {
    662     std::vector<Mat> masks;
    663     _masks.getMatVector(masks);
    664 
    665     size_t outCount = 0;
    666     for( size_t i = 0; i < masks.size(); i++ )
    667     {
    668         if( !masks[i].empty() && (countNonZero(masks[i].row(queryIdx)) == 0) )
    669             outCount++;
    670     }
    671 
    672     return !masks.empty() && outCount == masks.size() ;
    673 }
    674 
    675 
    676 ////////////////////////////////////////////////////// BruteForceMatcher /////////////////////////////////////////////////
    677 
    678 BFMatcher::BFMatcher( int _normType, bool _crossCheck )
    679 {
    680     normType = _normType;
    681     crossCheck = _crossCheck;
    682 }
    683 
    684 Ptr<DescriptorMatcher> BFMatcher::clone( bool emptyTrainData ) const
    685 {
    686     Ptr<BFMatcher> matcher = makePtr<BFMatcher>(normType, crossCheck);
    687     if( !emptyTrainData )
    688     {
    689         matcher->trainDescCollection.resize(trainDescCollection.size());
    690         std::transform( trainDescCollection.begin(), trainDescCollection.end(),
    691                         matcher->trainDescCollection.begin(), clone_op );
    692     }
    693     return matcher;
    694 }
    695 
    696 static bool ocl_match(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches, int dstType)
    697 {
    698     UMat trainIdx, distance;
    699     if (!ocl_matchSingle(query, _train, trainIdx, distance, dstType))
    700         return false;
    701     if (!ocl_matchDownload(trainIdx, distance, matches))
    702         return false;
    703     return true;
    704 }
    705 
    706 static bool ocl_knnMatch(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches, int k, int dstType, bool compactResult)
    707 {
    708     UMat trainIdx, distance;
    709     if (k != 2)
    710         return false;
    711     if (!ocl_knnMatchSingle(query, _train, trainIdx, distance, dstType))
    712         return false;
    713     if (!ocl_knnMatchDownload(trainIdx, distance, matches, compactResult) )
    714         return false;
    715     return true;
    716 }
    717 
    718 void BFMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
    719                              InputArrayOfArrays _masks, bool compactResult )
    720 {
    721     int trainDescType = trainDescCollection.empty() ? utrainDescCollection[0].type() : trainDescCollection[0].type();
    722     CV_Assert( _queryDescriptors.type() == trainDescType );
    723 
    724     const int IMGIDX_SHIFT = 18;
    725     const int IMGIDX_ONE = (1 << IMGIDX_SHIFT);
    726 
    727     if( _queryDescriptors.empty() || (trainDescCollection.empty() && utrainDescCollection.empty()))
    728     {
    729         matches.clear();
    730         return;
    731     }
    732 
    733     std::vector<Mat> masks;
    734     _masks.getMatVector(masks);
    735 
    736     if(!trainDescCollection.empty() && !utrainDescCollection.empty())
    737     {
    738         for(int i = 0; i < (int)utrainDescCollection.size(); i++)
    739         {
    740             Mat tempMat;
    741             utrainDescCollection[i].copyTo(tempMat);
    742             trainDescCollection.push_back(tempMat);
    743         }
    744         utrainDescCollection.clear();
    745     }
    746 
    747     int trainDescVectorSize = trainDescCollection.empty() ? (int)utrainDescCollection.size() : (int)trainDescCollection.size();
    748     Size trainDescSize = trainDescCollection.empty() ? utrainDescCollection[0].size() : trainDescCollection[0].size();
    749     int trainDescOffset = trainDescCollection.empty() ? (int)utrainDescCollection[0].offset : 0;
    750 
    751     if ( ocl::useOpenCL() && _queryDescriptors.isUMat() && _queryDescriptors.dims()<=2 && trainDescVectorSize == 1 &&
    752         _queryDescriptors.type() == CV_32FC1 && _queryDescriptors.offset() == 0 && trainDescOffset == 0 &&
    753         trainDescSize.width == _queryDescriptors.size().width && masks.size() == 1 && masks[0].total() == 0 )
    754     {
    755         if(knn == 1)
    756         {
    757             if(trainDescCollection.empty())
    758             {
    759                 if(ocl_match(_queryDescriptors, utrainDescCollection[0], matches, normType))
    760                 {
    761                     CV_IMPL_ADD(CV_IMPL_OCL);
    762                     return;
    763                 }
    764             }
    765             else
    766             {
    767                 if(ocl_match(_queryDescriptors, trainDescCollection[0], matches, normType))
    768                 {
    769                     CV_IMPL_ADD(CV_IMPL_OCL);
    770                     return;
    771                 }
    772             }
    773         }
    774         else
    775         {
    776             if(trainDescCollection.empty())
    777             {
    778                 if(ocl_knnMatch(_queryDescriptors, utrainDescCollection[0], matches, knn, normType, compactResult) )
    779                 {
    780                     CV_IMPL_ADD(CV_IMPL_OCL);
    781                     return;
    782                 }
    783             }
    784             else
    785             {
    786                 if(ocl_knnMatch(_queryDescriptors, trainDescCollection[0], matches, knn, normType, compactResult) )
    787                 {
    788                     CV_IMPL_ADD(CV_IMPL_OCL);
    789                     return;
    790                 }
    791             }
    792         }
    793     }
    794 
    795     Mat queryDescriptors = _queryDescriptors.getMat();
    796     if(trainDescCollection.empty() && !utrainDescCollection.empty())
    797     {
    798         for(int i = 0; i < (int)utrainDescCollection.size(); i++)
    799         {
    800             Mat tempMat;
    801             utrainDescCollection[i].copyTo(tempMat);
    802             trainDescCollection.push_back(tempMat);
    803         }
    804         utrainDescCollection.clear();
    805     }
    806 
    807     matches.reserve(queryDescriptors.rows);
    808 
    809     Mat dist, nidx;
    810 
    811     int iIdx, imgCount = (int)trainDescCollection.size(), update = 0;
    812     int dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ||
    813         (normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;
    814 
    815     CV_Assert( (int64)imgCount*IMGIDX_ONE < INT_MAX );
    816 
    817     for( iIdx = 0; iIdx < imgCount; iIdx++ )
    818     {
    819         CV_Assert( trainDescCollection[iIdx].rows < IMGIDX_ONE );
    820         batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, nidx,
    821                       normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck);
    822         update += IMGIDX_ONE;
    823     }
    824 
    825     if( dtype == CV_32S )
    826     {
    827         Mat temp;
    828         dist.convertTo(temp, CV_32F);
    829         dist = temp;
    830     }
    831 
    832     for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
    833     {
    834         const float* distptr = dist.ptr<float>(qIdx);
    835         const int* nidxptr = nidx.ptr<int>(qIdx);
    836 
    837         matches.push_back( std::vector<DMatch>() );
    838         std::vector<DMatch>& mq = matches.back();
    839         mq.reserve(knn);
    840 
    841         for( int k = 0; k < nidx.cols; k++ )
    842         {
    843             if( nidxptr[k] < 0 )
    844                 break;
    845             mq.push_back( DMatch(qIdx, nidxptr[k] & (IMGIDX_ONE - 1),
    846                           nidxptr[k] >> IMGIDX_SHIFT, distptr[k]) );
    847         }
    848 
    849         if( mq.empty() && compactResult )
    850             matches.pop_back();
    851     }
    852 }
    853 
    854 static bool ocl_radiusMatch(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches,
    855         float maxDistance, int dstType, bool compactResult)
    856 {
    857     UMat trainIdx, distance, nMatches;
    858     if (!ocl_radiusMatchSingle(query, _train, trainIdx, distance, nMatches, maxDistance, dstType))
    859         return false;
    860     if (!ocl_radiusMatchDownload(trainIdx, distance, nMatches, matches, compactResult))
    861         return false;
    862     return true;
    863 }
    864 
    865 void BFMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches,
    866                                 float maxDistance, InputArrayOfArrays _masks, bool compactResult )
    867 {
    868     int trainDescType = trainDescCollection.empty() ? utrainDescCollection[0].type() : trainDescCollection[0].type();
    869     CV_Assert( _queryDescriptors.type() == trainDescType );
    870 
    871     if( _queryDescriptors.empty() || (trainDescCollection.empty() && utrainDescCollection.empty()))
    872     {
    873         matches.clear();
    874         return;
    875     }
    876 
    877     std::vector<Mat> masks;
    878     _masks.getMatVector(masks);
    879 
    880     if(!trainDescCollection.empty() && !utrainDescCollection.empty())
    881     {
    882         for(int i = 0; i < (int)utrainDescCollection.size(); i++)
    883         {
    884             Mat tempMat;
    885             utrainDescCollection[i].copyTo(tempMat);
    886             trainDescCollection.push_back(tempMat);
    887         }
    888         utrainDescCollection.clear();
    889     }
    890 
    891     int trainDescVectorSize = trainDescCollection.empty() ? (int)utrainDescCollection.size() : (int)trainDescCollection.size();
    892     Size trainDescSize = trainDescCollection.empty() ? utrainDescCollection[0].size() : trainDescCollection[0].size();
    893     int trainDescOffset = trainDescCollection.empty() ? (int)utrainDescCollection[0].offset : 0;
    894 
    895     if ( ocl::useOpenCL() && _queryDescriptors.isUMat() && _queryDescriptors.dims()<=2 && trainDescVectorSize == 1 &&
    896         _queryDescriptors.type() == CV_32FC1 && _queryDescriptors.offset() == 0 && trainDescOffset == 0 &&
    897         trainDescSize.width == _queryDescriptors.size().width && masks.size() == 1 && masks[0].total() == 0 )
    898     {
    899         if (trainDescCollection.empty())
    900         {
    901             if(ocl_radiusMatch(_queryDescriptors, utrainDescCollection[0], matches, maxDistance, normType, compactResult) )
    902             {
    903                 CV_IMPL_ADD(CV_IMPL_OCL);
    904                 return;
    905             }
    906         }
    907         else
    908         {
    909             if (ocl_radiusMatch(_queryDescriptors, trainDescCollection[0], matches, maxDistance, normType, compactResult) )
    910             {
    911                 CV_IMPL_ADD(CV_IMPL_OCL);
    912                 return;
    913             }
    914         }
    915     }
    916 
    917     Mat queryDescriptors = _queryDescriptors.getMat();
    918     if(trainDescCollection.empty() && !utrainDescCollection.empty())
    919     {
    920         for(int i = 0; i < (int)utrainDescCollection.size(); i++)
    921         {
    922             Mat tempMat;
    923             utrainDescCollection[i].copyTo(tempMat);
    924             trainDescCollection.push_back(tempMat);
    925         }
    926         utrainDescCollection.clear();
    927     }
    928 
    929     matches.resize(queryDescriptors.rows);
    930     Mat dist, distf;
    931 
    932     int iIdx, imgCount = (int)trainDescCollection.size();
    933     int dtype = normType == NORM_HAMMING ||
    934         (normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;
    935 
    936     for( iIdx = 0; iIdx < imgCount; iIdx++ )
    937     {
    938         batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, noArray(),
    939                       normType, 0, masks.empty() ? Mat() : masks[iIdx], 0, false);
    940         if( dtype == CV_32S )
    941             dist.convertTo(distf, CV_32F);
    942         else
    943             distf = dist;
    944 
    945         for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
    946         {
    947             const float* distptr = distf.ptr<float>(qIdx);
    948 
    949             std::vector<DMatch>& mq = matches[qIdx];
    950             for( int k = 0; k < distf.cols; k++ )
    951             {
    952                 if( distptr[k] <= maxDistance )
    953                     mq.push_back( DMatch(qIdx, k, iIdx, distptr[k]) );
    954             }
    955         }
    956     }
    957 
    958     int qIdx0 = 0;
    959     for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
    960     {
    961         if( matches[qIdx].empty() && compactResult )
    962             continue;
    963 
    964         if( qIdx0 < qIdx )
    965             std::swap(matches[qIdx], matches[qIdx0]);
    966 
    967         std::sort( matches[qIdx0].begin(), matches[qIdx0].end() );
    968         qIdx0++;
    969     }
    970 }
    971 
    972 ///////////////////////////////////////////////////////////////////////////////////////////////////////
    973 
    974 /*
    975  * Factory function for DescriptorMatcher creating
    976  */
    977 Ptr<DescriptorMatcher> DescriptorMatcher::create( const String& descriptorMatcherType )
    978 {
    979     Ptr<DescriptorMatcher> dm;
    980     if( !descriptorMatcherType.compare( "FlannBased" ) )
    981     {
    982         dm = makePtr<FlannBasedMatcher>();
    983     }
    984     else if( !descriptorMatcherType.compare( "BruteForce" ) ) // L2
    985     {
    986         dm = makePtr<BFMatcher>(int(NORM_L2)); // anonymous enums can't be template parameters
    987     }
    988     else if( !descriptorMatcherType.compare( "BruteForce-SL2" ) ) // Squared L2
    989     {
    990         dm = makePtr<BFMatcher>(int(NORM_L2SQR));
    991     }
    992     else if( !descriptorMatcherType.compare( "BruteForce-L1" ) )
    993     {
    994         dm = makePtr<BFMatcher>(int(NORM_L1));
    995     }
    996     else if( !descriptorMatcherType.compare("BruteForce-Hamming") ||
    997              !descriptorMatcherType.compare("BruteForce-HammingLUT") )
    998     {
    999         dm = makePtr<BFMatcher>(int(NORM_HAMMING));
   1000     }
   1001     else if( !descriptorMatcherType.compare("BruteForce-Hamming(2)") )
   1002     {
   1003         dm = makePtr<BFMatcher>(int(NORM_HAMMING2));
   1004     }
   1005     else
   1006         CV_Error( Error::StsBadArg, "Unknown matcher name" );
   1007 
   1008     return dm;
   1009 }
   1010 
   1011 
   1012 /*
   1013  * Flann based matcher
   1014  */
   1015 FlannBasedMatcher::FlannBasedMatcher( const Ptr<flann::IndexParams>& _indexParams, const Ptr<flann::SearchParams>& _searchParams )
   1016     : indexParams(_indexParams), searchParams(_searchParams), addedDescCount(0)
   1017 {
   1018     CV_Assert( _indexParams );
   1019     CV_Assert( _searchParams );
   1020 }
   1021 
   1022 void FlannBasedMatcher::add( InputArrayOfArrays _descriptors )
   1023 {
   1024     DescriptorMatcher::add( _descriptors );
   1025     std::vector<UMat> descriptors;
   1026     _descriptors.getUMatVector(descriptors);
   1027 
   1028     for( size_t i = 0; i < descriptors.size(); i++ )
   1029     {
   1030         addedDescCount += descriptors[i].rows;
   1031     }
   1032 }
   1033 
   1034 void FlannBasedMatcher::clear()
   1035 {
   1036     DescriptorMatcher::clear();
   1037 
   1038     mergedDescriptors.clear();
   1039     flannIndex.release();
   1040 
   1041     addedDescCount = 0;
   1042 }
   1043 
   1044 void FlannBasedMatcher::train()
   1045 {
   1046     if( !flannIndex || mergedDescriptors.size() < addedDescCount )
   1047     {
   1048         // FIXIT: Workaround for 'utrainDescCollection' issue (PR #2142)
   1049         if (!utrainDescCollection.empty())
   1050         {
   1051             CV_Assert(trainDescCollection.size() == 0);
   1052             for (size_t i = 0; i < utrainDescCollection.size(); ++i)
   1053                 trainDescCollection.push_back(utrainDescCollection[i].getMat(ACCESS_READ));
   1054         }
   1055         mergedDescriptors.set( trainDescCollection );
   1056         flannIndex = makePtr<flann::Index>( mergedDescriptors.getDescriptors(), *indexParams );
   1057     }
   1058 }
   1059 
   1060 void FlannBasedMatcher::read( const FileNode& fn)
   1061 {
   1062      if (!indexParams)
   1063          indexParams = makePtr<flann::IndexParams>();
   1064 
   1065      FileNode ip = fn["indexParams"];
   1066      CV_Assert(ip.type() == FileNode::SEQ);
   1067 
   1068      for(int i = 0; i < (int)ip.size(); ++i)
   1069      {
   1070         CV_Assert(ip[i].type() == FileNode::MAP);
   1071         String _name =  (String)ip[i]["name"];
   1072         int type =  (int)ip[i]["type"];
   1073 
   1074         switch(type)
   1075         {
   1076         case CV_8U:
   1077         case CV_8S:
   1078         case CV_16U:
   1079         case CV_16S:
   1080         case CV_32S:
   1081             indexParams->setInt(_name, (int) ip[i]["value"]);
   1082             break;
   1083         case CV_32F:
   1084             indexParams->setFloat(_name, (float) ip[i]["value"]);
   1085             break;
   1086         case CV_64F:
   1087             indexParams->setDouble(_name, (double) ip[i]["value"]);
   1088             break;
   1089         case CV_USRTYPE1:
   1090             indexParams->setString(_name, (String) ip[i]["value"]);
   1091             break;
   1092         case CV_MAKETYPE(CV_USRTYPE1,2):
   1093             indexParams->setBool(_name, (int) ip[i]["value"] != 0);
   1094             break;
   1095         case CV_MAKETYPE(CV_USRTYPE1,3):
   1096             indexParams->setAlgorithm((int) ip[i]["value"]);
   1097             break;
   1098         };
   1099      }
   1100 
   1101      if (!searchParams)
   1102          searchParams = makePtr<flann::SearchParams>();
   1103 
   1104      FileNode sp = fn["searchParams"];
   1105      CV_Assert(sp.type() == FileNode::SEQ);
   1106 
   1107      for(int i = 0; i < (int)sp.size(); ++i)
   1108      {
   1109         CV_Assert(sp[i].type() == FileNode::MAP);
   1110         String _name =  (String)sp[i]["name"];
   1111         int type =  (int)sp[i]["type"];
   1112 
   1113         switch(type)
   1114         {
   1115         case CV_8U:
   1116         case CV_8S:
   1117         case CV_16U:
   1118         case CV_16S:
   1119         case CV_32S:
   1120             searchParams->setInt(_name, (int) sp[i]["value"]);
   1121             break;
   1122         case CV_32F:
   1123             searchParams->setFloat(_name, (float) ip[i]["value"]);
   1124             break;
   1125         case CV_64F:
   1126             searchParams->setDouble(_name, (double) ip[i]["value"]);
   1127             break;
   1128         case CV_USRTYPE1:
   1129             searchParams->setString(_name, (String) ip[i]["value"]);
   1130             break;
   1131         case CV_MAKETYPE(CV_USRTYPE1,2):
   1132             searchParams->setBool(_name, (int) ip[i]["value"] != 0);
   1133             break;
   1134         case CV_MAKETYPE(CV_USRTYPE1,3):
   1135             searchParams->setAlgorithm((int) ip[i]["value"]);
   1136             break;
   1137         };
   1138      }
   1139 
   1140     flannIndex.release();
   1141 }
   1142 
   1143 void FlannBasedMatcher::write( FileStorage& fs) const
   1144 {
   1145      fs << "indexParams" << "[";
   1146 
   1147      if (indexParams)
   1148      {
   1149          std::vector<String> names;
   1150          std::vector<int> types;
   1151          std::vector<String> strValues;
   1152          std::vector<double> numValues;
   1153 
   1154          indexParams->getAll(names, types, strValues, numValues);
   1155 
   1156          for(size_t i = 0; i < names.size(); ++i)
   1157          {
   1158              fs << "{" << "name" << names[i] << "type" << types[i] << "value";
   1159              switch(types[i])
   1160              {
   1161              case CV_8U:
   1162                  fs << (uchar)numValues[i];
   1163                  break;
   1164              case CV_8S:
   1165                  fs << (char)numValues[i];
   1166                  break;
   1167              case CV_16U:
   1168                  fs << (ushort)numValues[i];
   1169                  break;
   1170              case CV_16S:
   1171                  fs << (short)numValues[i];
   1172                  break;
   1173              case CV_32S:
   1174              case CV_MAKETYPE(CV_USRTYPE1,2):
   1175              case CV_MAKETYPE(CV_USRTYPE1,3):
   1176                  fs << (int)numValues[i];
   1177                  break;
   1178              case CV_32F:
   1179                  fs << (float)numValues[i];
   1180                  break;
   1181              case CV_64F:
   1182                  fs << (double)numValues[i];
   1183                  break;
   1184              case CV_USRTYPE1:
   1185                  fs << strValues[i];
   1186                  break;
   1187              default:
   1188                  fs << (double)numValues[i];
   1189                  fs << "typename" << strValues[i];
   1190                  break;
   1191              }
   1192              fs << "}";
   1193          }
   1194      }
   1195 
   1196      fs << "]" << "searchParams" << "[";
   1197 
   1198      if (searchParams)
   1199      {
   1200          std::vector<String> names;
   1201          std::vector<int> types;
   1202          std::vector<String> strValues;
   1203          std::vector<double> numValues;
   1204 
   1205          searchParams->getAll(names, types, strValues, numValues);
   1206 
   1207          for(size_t i = 0; i < names.size(); ++i)
   1208          {
   1209              fs << "{" << "name" << names[i] << "type" << types[i] << "value";
   1210              switch(types[i])
   1211              {
   1212              case CV_8U:
   1213                  fs << (uchar)numValues[i];
   1214                  break;
   1215              case CV_8S:
   1216                  fs << (char)numValues[i];
   1217                  break;
   1218              case CV_16U:
   1219                  fs << (ushort)numValues[i];
   1220                  break;
   1221              case CV_16S:
   1222                  fs << (short)numValues[i];
   1223                  break;
   1224              case CV_32S:
   1225              case CV_MAKETYPE(CV_USRTYPE1,2):
   1226              case CV_MAKETYPE(CV_USRTYPE1,3):
   1227                  fs << (int)numValues[i];
   1228                  break;
   1229              case CV_32F:
   1230                  fs << (float)numValues[i];
   1231                  break;
   1232              case CV_64F:
   1233                  fs << (double)numValues[i];
   1234                  break;
   1235              case CV_USRTYPE1:
   1236                  fs << strValues[i];
   1237                  break;
   1238              default:
   1239                  fs << (double)numValues[i];
   1240                  fs << "typename" << strValues[i];
   1241                  break;
   1242              }
   1243              fs << "}";
   1244          }
   1245      }
   1246      fs << "]";
   1247 }
   1248 
   1249 bool FlannBasedMatcher::isMaskSupported() const
   1250 {
   1251     return false;
   1252 }
   1253 
   1254 Ptr<DescriptorMatcher> FlannBasedMatcher::clone( bool emptyTrainData ) const
   1255 {
   1256     Ptr<FlannBasedMatcher> matcher = makePtr<FlannBasedMatcher>(indexParams, searchParams);
   1257     if( !emptyTrainData )
   1258     {
   1259         CV_Error( Error::StsNotImplemented, "deep clone functionality is not implemented, because "
   1260                   "Flann::Index has not copy constructor or clone method ");
   1261         //matcher->flannIndex;
   1262         matcher->addedDescCount = addedDescCount;
   1263         matcher->mergedDescriptors = DescriptorCollection( mergedDescriptors );
   1264         std::transform( trainDescCollection.begin(), trainDescCollection.end(),
   1265                         matcher->trainDescCollection.begin(), clone_op );
   1266     }
   1267     return matcher;
   1268 }
   1269 
   1270 void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collection, const Mat& indices, const Mat& dists,
   1271                                            std::vector<std::vector<DMatch> >& matches )
   1272 {
   1273     matches.resize( indices.rows );
   1274     for( int i = 0; i < indices.rows; i++ )
   1275     {
   1276         for( int j = 0; j < indices.cols; j++ )
   1277         {
   1278             int idx = indices.at<int>(i, j);
   1279             if( idx >= 0 )
   1280             {
   1281                 int imgIdx, trainIdx;
   1282                 collection.getLocalIdx( idx, imgIdx, trainIdx );
   1283                 float dist = 0;
   1284                 if (dists.type() == CV_32S)
   1285                     dist = static_cast<float>( dists.at<int>(i,j) );
   1286                 else
   1287                     dist = std::sqrt(dists.at<float>(i,j));
   1288                 matches[i].push_back( DMatch( i, trainIdx, imgIdx, dist ) );
   1289             }
   1290         }
   1291     }
   1292 }
   1293 
   1294 void FlannBasedMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
   1295                                      InputArrayOfArrays /*masks*/, bool /*compactResult*/ )
   1296 {
   1297     Mat queryDescriptors = _queryDescriptors.getMat();
   1298     Mat indices( queryDescriptors.rows, knn, CV_32SC1 );
   1299     Mat dists( queryDescriptors.rows, knn, CV_32FC1);
   1300     flannIndex->knnSearch( queryDescriptors, indices, dists, knn, *searchParams );
   1301 
   1302     convertToDMatches( mergedDescriptors, indices, dists, matches );
   1303 }
   1304 
   1305 void FlannBasedMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
   1306                                          InputArrayOfArrays /*masks*/, bool /*compactResult*/ )
   1307 {
   1308     Mat queryDescriptors = _queryDescriptors.getMat();
   1309     const int count = mergedDescriptors.size(); // TODO do count as param?
   1310     Mat indices( queryDescriptors.rows, count, CV_32SC1, Scalar::all(-1) );
   1311     Mat dists( queryDescriptors.rows, count, CV_32FC1, Scalar::all(-1) );
   1312     for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
   1313     {
   1314         Mat queryDescriptorsRow = queryDescriptors.row(qIdx);
   1315         Mat indicesRow = indices.row(qIdx);
   1316         Mat distsRow = dists.row(qIdx);
   1317         flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, count, *searchParams );
   1318     }
   1319 
   1320     convertToDMatches( mergedDescriptors, indices, dists, matches );
   1321 }
   1322 
   1323 }
   1324