/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
# include "precomp.hpp"
# include <limits>
# include "opencl_kernels.hpp"
# if defined(HAVE_EIGEN) && EIGEN_WORLD_VERSION == 2
# include <Eigen/Array>
# endif
namespace cv
{
Mat windowedMatchingMask ( const std : : vector < KeyPoint > & keypoints1 , const std : : vector < KeyPoint > & keypoints2 ,
float maxDeltaX , float maxDeltaY )
{
if ( keypoints1 . empty ( ) | | keypoints2 . empty ( ) )
return Mat ( ) ;
int n1 = ( int ) keypoints1 . size ( ) , n2 = ( int ) keypoints2 . size ( ) ;
Mat mask ( n1 , n2 , CV_8UC1 ) ;
for ( int i = 0 ; i < n1 ; i + + )
{
for ( int j = 0 ; j < n2 ; j + + )
{
Point2f diff = keypoints2 [ j ] . pt - keypoints1 [ i ] . pt ;
mask . at < uchar > ( i , j ) = std : : abs ( diff . x ) < maxDeltaX & & std : : abs ( diff . y ) < maxDeltaY ;
}
}
return mask ;
}
//////////////////////////////////////////////////////////////////ocl functions for BFMatcher ///////////////////////////////////////////////////////////////
static void ensureSizeIsEnough ( int rows , int cols , int type , UMat & m )
{
if ( m . type ( ) = = type & & m . rows > = rows & & m . cols > = cols )
m = m ( Rect ( 0 , 0 , cols , rows ) ) ;
else
m . create ( rows , cols , type ) ;
}
template < int BLOCK_SIZE , int MAX_DESC_LEN /*, typename Mask*/ >
static bool ocl_matchUnrolledCached ( InputArray _query , InputArray _train ,
const UMat & trainIdx , const UMat & distance , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = cv : : format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE , ( int ) MAX_DESC_LEN ) ;
ocl : : Kernel k ( " BruteForceMatch_UnrollMatch " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _query . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( BLOCK_SIZE * ( MAX_DESC_LEN > = BLOCK_SIZE ? MAX_DESC_LEN : BLOCK_SIZE ) + BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
return k . run ( 2 , globalSize , localSize , false ) ;
}
return true ;
}
template < int BLOCK_SIZE /*, typename Mask*/ >
static bool ocl_match ( InputArray _query , InputArray _train ,
const UMat & trainIdx , const UMat & distance , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = cv : : format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE ) ;
ocl : : Kernel k ( " BruteForceMatch_Match " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _query . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( 2 * BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
return k . run ( 2 , globalSize , localSize , false ) ;
}
return true ;
}
static bool ocl_matchDispatcher ( InputArray query , InputArray train ,
const UMat & trainIdx , const UMat & distance , int distType )
{
int query_cols = query . size ( ) . width ;
bool is_cpu = ocl : : Device : : getDefault ( ) . type ( ) = = ocl : : Device : : TYPE_CPU ;
if ( query_cols < = 64 )
{
if ( ! ocl_matchUnrolledCached < 16 , 64 > ( query , train , trainIdx , distance , distType ) ) return false ;
}
else if ( query_cols < = 128 & & ! is_cpu )
{
if ( ! ocl_matchUnrolledCached < 16 , 128 > ( query , train , trainIdx , distance , distType ) ) return false ;
}
else
{
if ( ! ocl_match < 16 > ( query , train , trainIdx , distance , distType ) ) return false ;
}
return true ;
}
static bool ocl_matchSingle ( InputArray query , InputArray train ,
UMat & trainIdx , UMat & distance , int dstType )
{
if ( query . empty ( ) | | train . empty ( ) )
return false ;
int query_rows = query . size ( ) . height ;
ensureSizeIsEnough ( 1 , query_rows , CV_32S , trainIdx ) ;
ensureSizeIsEnough ( 1 , query_rows , CV_32F , distance ) ;
return ocl_matchDispatcher ( query , train , trainIdx , distance , dstType ) ;
}
static bool ocl_matchConvert ( const Mat & trainIdx , const Mat & distance , std : : vector < std : : vector < DMatch > > & matches )
{
if ( trainIdx . empty ( ) | | distance . empty ( ) )
return false ;
if ( ( trainIdx . type ( ) ! = CV_32SC1 ) | | ( distance . type ( ) ! = CV_32FC1 | | distance . cols ! = trainIdx . cols ) )
return false ;
const int nQuery = trainIdx . cols ;
matches . clear ( ) ;
matches . reserve ( nQuery ) ;
const int * trainIdx_ptr = trainIdx . ptr < int > ( ) ;
const float * distance_ptr = distance . ptr < float > ( ) ;
for ( int queryIdx = 0 ; queryIdx < nQuery ; + + queryIdx , + + trainIdx_ptr , + + distance_ptr )
{
int trainIndex = * trainIdx_ptr ;
if ( trainIndex = = - 1 )
continue ;
float dst = * distance_ptr ;
DMatch m ( queryIdx , trainIndex , 0 , dst ) ;
std : : vector < DMatch > temp ;
temp . push_back ( m ) ;
matches . push_back ( temp ) ;
}
return true ;
}
static bool ocl_matchDownload ( const UMat & trainIdx , const UMat & distance , std : : vector < std : : vector < DMatch > > & matches )
{
if ( trainIdx . empty ( ) | | distance . empty ( ) )
return false ;
Mat trainIdxCPU = trainIdx . getMat ( ACCESS_READ ) ;
Mat distanceCPU = distance . getMat ( ACCESS_READ ) ;
return ocl_matchConvert ( trainIdxCPU , distanceCPU , matches ) ;
}
template < int BLOCK_SIZE , int MAX_DESC_LEN /*, typename Mask*/ >
static bool ocl_knn_matchUnrolledCached ( InputArray _query , InputArray _train ,
const UMat & trainIdx , const UMat & distance , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = cv : : format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE , ( int ) MAX_DESC_LEN ) ;
ocl : : Kernel k ( " BruteForceMatch_knnUnrollMatch " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _query . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( BLOCK_SIZE * ( MAX_DESC_LEN > = BLOCK_SIZE ? MAX_DESC_LEN : BLOCK_SIZE ) + BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
return k . run ( 2 , globalSize , localSize , false ) ;
}
return true ;
}
template < int BLOCK_SIZE /*, typename Mask*/ >
static bool ocl_knn_match ( InputArray _query , InputArray _train ,
const UMat & trainIdx , const UMat & distance , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE ) ;
ocl : : Kernel k ( " BruteForceMatch_knnMatch " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _query . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( 2 * BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
return k . run ( 2 , globalSize , localSize , false ) ;
}
return true ;
}
static bool ocl_match2Dispatcher ( InputArray query , InputArray train , const UMat & trainIdx , const UMat & distance , int distType )
{
bool is_cpu = ocl : : Device : : getDefault ( ) . type ( ) = = ocl : : Device : : TYPE_CPU ;
if ( query . size ( ) . width < = 64 )
{
if ( ! ocl_knn_matchUnrolledCached < 16 , 64 > ( query , train , trainIdx , distance , distType ) )
return false ;
}
else if ( query . size ( ) . width < = 128 & & ! is_cpu )
{
if ( ! ocl_knn_matchUnrolledCached < 16 , 128 > ( query , train , trainIdx , distance , distType ) )
return false ;
}
else
{
if ( ! ocl_knn_match < 16 > ( query , train , trainIdx , distance , distType ) )
return false ;
}
return true ;
}
template < int BLOCK_SIZE , int MAX_DESC_LEN /*, typename Mask*/ >
static bool ocl_calcDistanceUnrolled ( InputArray _query , InputArray _train , const UMat & allDist , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE , ( int ) MAX_DESC_LEN ) ;
ocl : : Kernel k ( " BruteForceMatch_calcDistanceUnrolled " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _query . size ( ) . width + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( 2 * BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( allDist ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
k . run ( 2 , globalSize , localSize , false ) ;
}
return false ; // TODO in KERNEL
}
template < int BLOCK_SIZE /*, typename Mask*/ >
static bool ocl_calcDistance ( InputArray _query , InputArray _train , const UMat & allDist , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE ) ;
ocl : : Kernel k ( " BruteForceMatch_calcDistance " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _query . size ( ) . width + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( 2 * BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( allDist ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
k . run ( 2 , globalSize , localSize , false ) ;
}
return false ; // TODO in KERNEL
}
static bool ocl_calcDistanceDispatcher ( InputArray query , InputArray train , const UMat & allDist , int distType )
{
if ( query . size ( ) . width < = 64 )
{
if ( ! ocl_calcDistanceUnrolled < 16 , 64 > ( query , train , allDist , distType ) ) return false ;
}
else if ( query . size ( ) . width < = 128 )
{
if ( ! ocl_calcDistanceUnrolled < 16 , 128 > ( query , train , allDist , distType ) ) return false ;
}
else
{
if ( ! ocl_calcDistance < 16 > ( query , train , allDist , distType ) ) return false ;
}
return true ;
}
template < int BLOCK_SIZE >
static bool ocl_findKnnMatch ( int k , const UMat & trainIdx , const UMat & distance , const UMat & allDist , int /*distType*/ )
{
return false ; // TODO in KERNEL
std : : vector < ocl : : Kernel > kernels ;
for ( int i = 0 ; i < k ; + + i )
{
ocl : : Kernel kernel ( " BruteForceMatch_findBestMatch " , ocl : : features2d : : brute_force_match_oclsrc ) ;
if ( kernel . empty ( ) )
return false ;
kernels . push_back ( kernel ) ;
}
size_t globalSize [ ] = { trainIdx . rows * BLOCK_SIZE , 1 , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , 1 , 1 } ;
int block_size = BLOCK_SIZE ;
for ( int i = 0 ; i < k ; + + i )
{
int idx = 0 ;
idx = kernels [ i ] . set ( idx , ocl : : KernelArg : : PtrReadOnly ( allDist ) ) ;
idx = kernels [ i ] . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = kernels [ i ] . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = kernels [ i ] . set ( idx , i ) ;
idx = kernels [ i ] . set ( idx , block_size ) ;
// idx = kernels[i].set(idx, train.rows);
// idx = kernels[i].set(idx, train.cols);
// idx = kernels[i].set(idx, query.step);
if ( ! kernels [ i ] . run ( 2 , globalSize , localSize , false ) )
return false ;
}
return true ;
}
static bool ocl_findKnnMatchDispatcher ( int k , const UMat & trainIdx , const UMat & distance , const UMat & allDist , int distType )
{
return ocl_findKnnMatch < 256 > ( k , trainIdx , distance , allDist , distType ) ;
}
static bool ocl_kmatchDispatcher ( InputArray query , InputArray train , int k , const UMat & trainIdx ,
const UMat & distance , const UMat & allDist , int distType )
{
if ( k = = 2 )
{
if ( ! ocl_match2Dispatcher ( query , train , trainIdx , distance , distType ) ) return false ;
}
else
{
if ( ! ocl_calcDistanceDispatcher ( query , train , allDist , distType ) ) return false ;
if ( ! ocl_findKnnMatchDispatcher ( k , trainIdx , distance , allDist , distType ) ) return false ;
}
return true ;
}
static bool ocl_knnMatchSingle ( InputArray query , InputArray train , UMat & trainIdx ,
UMat & distance , UMat & allDist , int k , int dstType )
{
if ( query . empty ( ) | | train . empty ( ) )
return false ;
const int nQuery = query . size ( ) . height ;
const int nTrain = train . size ( ) . height ;
if ( k = = 2 )
{
ensureSizeIsEnough ( 1 , nQuery , CV_32SC2 , trainIdx ) ;
ensureSizeIsEnough ( 1 , nQuery , CV_32FC2 , distance ) ;
}
else
{
ensureSizeIsEnough ( nQuery , k , CV_32S , trainIdx ) ;
ensureSizeIsEnough ( nQuery , k , CV_32F , distance ) ;
ensureSizeIsEnough ( nQuery , nTrain , CV_32FC1 , allDist ) ;
}
trainIdx . setTo ( Scalar : : all ( - 1 ) ) ;
return ocl_kmatchDispatcher ( query , train , k , trainIdx , distance , allDist , dstType ) ;
}
static bool ocl_knnMatchConvert ( const Mat & trainIdx , const Mat & distance , std : : vector < std : : vector < DMatch > > & matches , bool compactResult )
{
if ( trainIdx . empty ( ) | | distance . empty ( ) )
return false ;
if ( trainIdx . type ( ) ! = CV_32SC2 & & trainIdx . type ( ) ! = CV_32SC1 ) return false ;
if ( distance . type ( ) ! = CV_32FC2 & & distance . type ( ) ! = CV_32FC1 ) return false ;
if ( distance . size ( ) ! = trainIdx . size ( ) ) return false ;
if ( ! trainIdx . isContinuous ( ) | | ! distance . isContinuous ( ) ) return false ;
const int nQuery = trainIdx . type ( ) = = CV_32SC2 ? trainIdx . cols : trainIdx . rows ;
const int k = trainIdx . type ( ) = = CV_32SC2 ? 2 : trainIdx . cols ;
matches . clear ( ) ;
matches . reserve ( nQuery ) ;
const int * trainIdx_ptr = trainIdx . ptr < int > ( ) ;
const float * distance_ptr = distance . ptr < float > ( ) ;
for ( int queryIdx = 0 ; queryIdx < nQuery ; + + queryIdx )
{
matches . push_back ( std : : vector < DMatch > ( ) ) ;
std : : vector < DMatch > & curMatches = matches . back ( ) ;
curMatches . reserve ( k ) ;
for ( int i = 0 ; i < k ; + + i , + + trainIdx_ptr , + + distance_ptr )
{
int trainIndex = * trainIdx_ptr ;
if ( trainIndex ! = - 1 )
{
float dst = * distance_ptr ;
DMatch m ( queryIdx , trainIndex , 0 , dst ) ;
curMatches . push_back ( m ) ;
}
}
if ( compactResult & & curMatches . empty ( ) )
matches . pop_back ( ) ;
}
return true ;
}
static bool ocl_knnMatchDownload ( const UMat & trainIdx , const UMat & distance , std : : vector < std : : vector < DMatch > > & matches , bool compactResult )
{
if ( trainIdx . empty ( ) | | distance . empty ( ) )
return false ;
Mat trainIdxCPU = trainIdx . getMat ( ACCESS_READ ) ;
Mat distanceCPU = distance . getMat ( ACCESS_READ ) ;
if ( ocl_knnMatchConvert ( trainIdxCPU , distanceCPU , matches , compactResult ) )
return true ;
return false ;
}
template < int BLOCK_SIZE , int MAX_DESC_LEN /*, typename Mask*/ >
static bool ocl_matchUnrolledCached ( InputArray _query , InputArray _train , float maxDistance ,
const UMat & trainIdx , const UMat & distance , const UMat & nMatches , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d " ,
ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE , ( int ) MAX_DESC_LEN ) ;
ocl : : Kernel k ( " BruteForceMatch_RadiusUnrollMatch " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _train . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , ( _query . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( 2 * BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , maxDistance ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( nMatches ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , trainIdx . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
idx = k . set ( idx , ( int ) trainIdx . step ) ;
return k . run ( 2 , globalSize , localSize , false ) ;
}
return true ;
}
//radius_match
template < int BLOCK_SIZE /*, typename Mask*/ >
static bool ocl_radius_match ( InputArray _query , InputArray _train , float maxDistance ,
const UMat & trainIdx , const UMat & distance , const UMat & nMatches , int distType )
{
int depth = _query . depth ( ) ;
cv : : String opts ;
opts = format ( " -D T=%s %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d " , ocl : : typeToStr ( depth ) , depth = = CV_32F ? " -D T_FLOAT " : " " , distType , ( int ) BLOCK_SIZE ) ;
ocl : : Kernel k ( " BruteForceMatch_RadiusMatch " , ocl : : features2d : : brute_force_match_oclsrc , opts ) ;
if ( k . empty ( ) )
return false ;
size_t globalSize [ ] = { ( _train . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , ( _query . size ( ) . height + BLOCK_SIZE - 1 ) / BLOCK_SIZE * BLOCK_SIZE , 1 } ;
size_t localSize [ ] = { BLOCK_SIZE , BLOCK_SIZE , 1 } ;
const size_t smemSize = ( 2 * BLOCK_SIZE * BLOCK_SIZE ) * sizeof ( int ) ;
if ( globalSize [ 0 ] ! = 0 )
{
UMat query = _query . getUMat ( ) , train = _train . getUMat ( ) ;
int idx = 0 ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( query ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrReadOnly ( train ) ) ;
idx = k . set ( idx , maxDistance ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( trainIdx ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( distance ) ) ;
idx = k . set ( idx , ocl : : KernelArg : : PtrWriteOnly ( nMatches ) ) ;
idx = k . set ( idx , ( void * ) NULL , smemSize ) ;
idx = k . set ( idx , query . rows ) ;
idx = k . set ( idx , query . cols ) ;
idx = k . set ( idx , train . rows ) ;
idx = k . set ( idx , train . cols ) ;
idx = k . set ( idx , trainIdx . cols ) ;
idx = k . set ( idx , ( int ) query . step ) ;
idx = k . set ( idx , ( int ) trainIdx . step ) ;
return k . run ( 2 , globalSize , localSize , false ) ;
}
return true ;
}
static bool ocl_rmatchDispatcher ( InputArray query , InputArray train ,
UMat & trainIdx , UMat & distance , UMat & nMatches , float maxDistance , int distType )
{
bool is_cpu = ocl : : Device : : getDefault ( ) . type ( ) = = ocl : : Device : : TYPE_CPU ;
int query_cols = query . size ( ) . width ;
if ( query_cols < = 64 )
{
if ( ! ocl_matchUnrolledCached < 16 , 64 > ( query , train , maxDistance , trainIdx , distance , nMatches , distType ) ) return false ;
}
else if ( query_cols < = 128 & & ! is_cpu )
{
if ( ! ocl_matchUnrolledCached < 16 , 128 > ( query , train , maxDistance , trainIdx , distance , nMatches , distType ) ) return false ;
}
else
{
if ( ! ocl_radius_match < 16 > ( query , train , maxDistance , trainIdx , distance , nMatches , distType ) ) return false ;
}
return true ;
}
static bool ocl_radiusMatchSingle ( InputArray query , InputArray train ,
UMat & trainIdx , UMat & distance , UMat & nMatches , float maxDistance , int distType )
{
if ( query . empty ( ) | | train . empty ( ) )
return false ;
const int nQuery = query . size ( ) . height ;
const int nTrain = train . size ( ) . height ;
ensureSizeIsEnough ( 1 , nQuery , CV_32SC1 , nMatches ) ;
if ( trainIdx . empty ( ) )
{
ensureSizeIsEnough ( nQuery , std : : max ( ( nTrain / 100 ) , 10 ) , CV_32SC1 , trainIdx ) ;
ensureSizeIsEnough ( nQuery , std : : max ( ( nTrain / 100 ) , 10 ) , CV_32FC1 , distance ) ;
}
nMatches . setTo ( Scalar : : all ( 0 ) ) ;
return ocl_rmatchDispatcher ( query , train , trainIdx , distance , nMatches , maxDistance , distType ) ;
}
static bool ocl_radiusMatchConvert ( const Mat & trainIdx , const Mat & distance , const Mat & _nMatches ,
std : : vector < std : : vector < DMatch > > & matches , bool compactResult )
{
if ( trainIdx . empty ( ) | | distance . empty ( ) | | _nMatches . empty ( ) )
return false ;
if ( ( trainIdx . type ( ) ! = CV_32SC1 ) | |
( distance . type ( ) ! = CV_32FC1 | | distance . size ( ) ! = trainIdx . size ( ) ) | |
( _nMatches . type ( ) ! = CV_32SC1 | | _nMatches . cols ! = trainIdx . rows ) )
return false ;
const int nQuery = trainIdx . rows ;
matches . clear ( ) ;
matches . reserve ( nQuery ) ;
const int * nMatches_ptr = _nMatches . ptr < int > ( ) ;
for ( int queryIdx = 0 ; queryIdx < nQuery ; + + queryIdx )
{
const int * trainIdx_ptr = trainIdx . ptr < int > ( queryIdx ) ;
const float * distance_ptr = distance . ptr < float > ( queryIdx ) ;
const int nMatches = std : : min ( nMatches_ptr [ queryIdx ] , trainIdx . cols ) ;
if ( nMatches = = 0 )
{
if ( ! compactResult )
matches . push_back ( std : : vector < DMatch > ( ) ) ;
continue ;
}
matches . push_back ( std : : vector < DMatch > ( nMatches ) ) ;
std : : vector < DMatch > & curMatches = matches . back ( ) ;
for ( int i = 0 ; i < nMatches ; + + i , + + trainIdx_ptr , + + distance_ptr )
{
int trainIndex = * trainIdx_ptr ;
float dst = * distance_ptr ;
DMatch m ( queryIdx , trainIndex , 0 , dst ) ;
curMatches [ i ] = m ;
}
std : : sort ( curMatches . begin ( ) , curMatches . end ( ) ) ;
}
return true ;
}
static bool ocl_radiusMatchDownload ( const UMat & trainIdx , const UMat & distance , const UMat & nMatches ,
std : : vector < std : : vector < DMatch > > & matches , bool compactResult )
{
if ( trainIdx . empty ( ) | | distance . empty ( ) | | nMatches . empty ( ) )
return false ;
Mat trainIdxCPU = trainIdx . getMat ( ACCESS_READ ) ;
Mat distanceCPU = distance . getMat ( ACCESS_READ ) ;
Mat nMatchesCPU = nMatches . getMat ( ACCESS_READ ) ;
return ocl_radiusMatchConvert ( trainIdxCPU , distanceCPU , nMatchesCPU , matches , compactResult ) ;
}
/****************************************************************************************\
* DescriptorMatcher *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DescriptorMatcher : : DescriptorCollection : : DescriptorCollection ( )
{ }
DescriptorMatcher : : DescriptorCollection : : DescriptorCollection ( const DescriptorCollection & collection )
{
mergedDescriptors = collection . mergedDescriptors . clone ( ) ;
std : : copy ( collection . startIdxs . begin ( ) , collection . startIdxs . begin ( ) , startIdxs . begin ( ) ) ;
}
DescriptorMatcher : : DescriptorCollection : : ~ DescriptorCollection ( )
{ }
void DescriptorMatcher : : DescriptorCollection : : set ( const std : : vector < Mat > & descriptors )
{
clear ( ) ;
size_t imageCount = descriptors . size ( ) ;
CV_Assert ( imageCount > 0 ) ;
startIdxs . resize ( imageCount ) ;
int dim = - 1 ;
int type = - 1 ;
startIdxs [ 0 ] = 0 ;
for ( size_t i = 1 ; i < imageCount ; i + + )
{
int s = 0 ;
if ( ! descriptors [ i - 1 ] . empty ( ) )
{
dim = descriptors [ i - 1 ] . cols ;
type = descriptors [ i - 1 ] . type ( ) ;
s = descriptors [ i - 1 ] . rows ;
}
startIdxs [ i ] = startIdxs [ i - 1 ] + s ;
}
if ( imageCount = = 1 )
{
if ( descriptors [ 0 ] . empty ( ) ) return ;
dim = descriptors [ 0 ] . cols ;
type = descriptors [ 0 ] . type ( ) ;
}
CV_Assert ( dim > 0 ) ;
int count = startIdxs [ imageCount - 1 ] + descriptors [ imageCount - 1 ] . rows ;
if ( count > 0 )
{
mergedDescriptors . create ( count , dim , type ) ;
for ( size_t i = 0 ; i < imageCount ; i + + )
{
if ( ! descriptors [ i ] . empty ( ) )
{
CV_Assert ( descriptors [ i ] . cols = = dim & & descriptors [ i ] . type ( ) = = type ) ;
Mat m = mergedDescriptors . rowRange ( startIdxs [ i ] , startIdxs [ i ] + descriptors [ i ] . rows ) ;
descriptors [ i ] . copyTo ( m ) ;
}
}
}
}
void DescriptorMatcher : : DescriptorCollection : : clear ( )
{
startIdxs . clear ( ) ;
mergedDescriptors . release ( ) ;
}
const Mat DescriptorMatcher : : DescriptorCollection : : getDescriptor ( int imgIdx , int localDescIdx ) const
{
CV_Assert ( imgIdx < ( int ) startIdxs . size ( ) ) ;
int globalIdx = startIdxs [ imgIdx ] + localDescIdx ;
CV_Assert ( globalIdx < ( int ) size ( ) ) ;
return getDescriptor ( globalIdx ) ;
}
const Mat & DescriptorMatcher : : DescriptorCollection : : getDescriptors ( ) const
{
return mergedDescriptors ;
}
const Mat DescriptorMatcher : : DescriptorCollection : : getDescriptor ( int globalDescIdx ) const
{
CV_Assert ( globalDescIdx < size ( ) ) ;
return mergedDescriptors . row ( globalDescIdx ) ;
}
void DescriptorMatcher : : DescriptorCollection : : getLocalIdx ( int globalDescIdx , int & imgIdx , int & localDescIdx ) const
{
CV_Assert ( ( globalDescIdx > = 0 ) & & ( globalDescIdx < size ( ) ) ) ;
std : : vector < int > : : const_iterator img_it = std : : upper_bound ( startIdxs . begin ( ) , startIdxs . end ( ) , globalDescIdx ) ;
- - img_it ;
imgIdx = ( int ) ( img_it - startIdxs . begin ( ) ) ;
localDescIdx = globalDescIdx - ( * img_it ) ;
}
int DescriptorMatcher : : DescriptorCollection : : size ( ) const
{
return mergedDescriptors . rows ;
}
/*
* DescriptorMatcher
*/
static void convertMatches ( const std : : vector < std : : vector < DMatch > > & knnMatches , std : : vector < DMatch > & matches )
{
matches . clear ( ) ;
matches . reserve ( knnMatches . size ( ) ) ;
for ( size_t i = 0 ; i < knnMatches . size ( ) ; i + + )
{
CV_Assert ( knnMatches [ i ] . size ( ) < = 1 ) ;
if ( ! knnMatches [ i ] . empty ( ) )
matches . push_back ( knnMatches [ i ] [ 0 ] ) ;
}
}
DescriptorMatcher : : ~ DescriptorMatcher ( )
{ }
void DescriptorMatcher : : add ( InputArrayOfArrays _descriptors )
{
if ( _descriptors . isUMatVector ( ) )
{
std : : vector < UMat > descriptors ;
_descriptors . getUMatVector ( descriptors ) ;
utrainDescCollection . insert ( utrainDescCollection . end ( ) , descriptors . begin ( ) , descriptors . end ( ) ) ;
}
else if ( _descriptors . isUMat ( ) )
{
std : : vector < UMat > descriptors = std : : vector < UMat > ( 1 , _descriptors . getUMat ( ) ) ;
utrainDescCollection . insert ( utrainDescCollection . end ( ) , descriptors . begin ( ) , descriptors . end ( ) ) ;
}
else if ( _descriptors . isMatVector ( ) )
{
std : : vector < Mat > descriptors ;
_descriptors . getMatVector ( descriptors ) ;
trainDescCollection . insert ( trainDescCollection . end ( ) , descriptors . begin ( ) , descriptors . end ( ) ) ;
}
else if ( _descriptors . isMat ( ) )
{
std : : vector < Mat > descriptors = std : : vector < Mat > ( 1 , _descriptors . getMat ( ) ) ;
trainDescCollection . insert ( trainDescCollection . end ( ) , descriptors . begin ( ) , descriptors . end ( ) ) ;
}
else
CV_Assert ( _descriptors . isUMat ( ) | | _descriptors . isUMatVector ( ) | | _descriptors . isMat ( ) | | _descriptors . isMatVector ( ) ) ;
}
const std : : vector < Mat > & DescriptorMatcher : : getTrainDescriptors ( ) const
{
return trainDescCollection ;
}
void DescriptorMatcher : : clear ( )
{
utrainDescCollection . clear ( ) ;
trainDescCollection . clear ( ) ;
}
bool DescriptorMatcher : : empty ( ) const
{
return trainDescCollection . empty ( ) & & utrainDescCollection . empty ( ) ;
}
void DescriptorMatcher : : train ( )
{ }
void DescriptorMatcher : : match ( InputArray queryDescriptors , InputArray trainDescriptors ,
std : : vector < DMatch > & matches , InputArray mask ) const
{
Ptr < DescriptorMatcher > tempMatcher = clone ( true ) ;
tempMatcher - > add ( trainDescriptors ) ;
tempMatcher - > match ( queryDescriptors , matches , std : : vector < Mat > ( 1 , mask . getMat ( ) ) ) ;
}
void DescriptorMatcher : : knnMatch ( InputArray queryDescriptors , InputArray trainDescriptors ,
std : : vector < std : : vector < DMatch > > & matches , int knn ,
InputArray mask , bool compactResult ) const
{
Ptr < DescriptorMatcher > tempMatcher = clone ( true ) ;
tempMatcher - > add ( trainDescriptors ) ;
tempMatcher - > knnMatch ( queryDescriptors , matches , knn , std : : vector < Mat > ( 1 , mask . getMat ( ) ) , compactResult ) ;
}
void DescriptorMatcher : : radiusMatch ( InputArray queryDescriptors , InputArray trainDescriptors ,
std : : vector < std : : vector < DMatch > > & matches , float maxDistance , InputArray mask ,
bool compactResult ) const
{
Ptr < DescriptorMatcher > tempMatcher = clone ( true ) ;
tempMatcher - > add ( trainDescriptors ) ;
tempMatcher - > radiusMatch ( queryDescriptors , matches , maxDistance , std : : vector < Mat > ( 1 , mask . getMat ( ) ) , compactResult ) ;
}
void DescriptorMatcher : : match ( InputArray queryDescriptors , std : : vector < DMatch > & matches , const std : : vector < Mat > & masks )
{
std : : vector < std : : vector < DMatch > > knnMatches ;
knnMatch ( queryDescriptors , knnMatches , 1 , masks , true /*compactResult*/ ) ;
convertMatches ( knnMatches , matches ) ;
}
void DescriptorMatcher : : checkMasks ( const std : : vector < Mat > & masks , int queryDescriptorsCount ) const
{
if ( isMaskSupported ( ) & & ! masks . empty ( ) )
{
// Check masks
size_t imageCount = std : : max ( trainDescCollection . size ( ) , utrainDescCollection . size ( ) ) ;
CV_Assert ( masks . size ( ) = = imageCount ) ;
for ( size_t i = 0 ; i < imageCount ; i + + )
{
if ( ! masks [ i ] . empty ( ) & & ( ! trainDescCollection [ i ] . empty ( ) | | ! utrainDescCollection [ i ] . empty ( ) ) )
{
int rows = trainDescCollection [ i ] . empty ( ) ? utrainDescCollection [ i ] . rows : trainDescCollection [ i ] . rows ;
CV_Assert ( masks [ i ] . rows = = queryDescriptorsCount & &
( masks [ i ] . cols = = rows | | masks [ i ] . cols = = rows ) & &
masks [ i ] . type ( ) = = CV_8UC1 ) ;
}
}
}
}
void DescriptorMatcher : : knnMatch ( InputArray queryDescriptors , std : : vector < std : : vector < DMatch > > & matches , int knn ,
const std : : vector < Mat > & masks , bool compactResult )
{
if ( empty ( ) | | queryDescriptors . empty ( ) )
return ;
CV_Assert ( knn > 0 ) ;
checkMasks ( masks , queryDescriptors . size ( ) . height ) ;
train ( ) ;
knnMatchImpl ( queryDescriptors , matches , knn , masks , compactResult ) ;
}
void DescriptorMatcher : : radiusMatch ( InputArray queryDescriptors , std : : vector < std : : vector < DMatch > > & matches , float maxDistance ,
const std : : vector < Mat > & masks , bool compactResult )
{
matches . clear ( ) ;
if ( empty ( ) | | queryDescriptors . empty ( ) )
return ;
CV_Assert ( maxDistance > std : : numeric_limits < float > : : epsilon ( ) ) ;
checkMasks ( masks , queryDescriptors . size ( ) . height ) ;
train ( ) ;
radiusMatchImpl ( queryDescriptors , matches , maxDistance , masks , compactResult ) ;
}
void DescriptorMatcher : : read ( const FileNode & )
{ }
void DescriptorMatcher : : write ( FileStorage & ) const
{ }
bool DescriptorMatcher : : isPossibleMatch ( const Mat & mask , int queryIdx , int trainIdx )
{
return mask . empty ( ) | | mask . at < uchar > ( queryIdx , trainIdx ) ;
}
bool DescriptorMatcher : : isMaskedOut ( const std : : vector < Mat > & masks , int queryIdx )
{
size_t outCount = 0 ;
for ( size_t i = 0 ; i < masks . size ( ) ; i + + )
{
if ( ! masks [ i ] . empty ( ) & & ( countNonZero ( masks [ i ] . row ( queryIdx ) ) = = 0 ) )
outCount + + ;
}
return ! masks . empty ( ) & & outCount = = masks . size ( ) ;
}
////////////////////////////////////////////////////// BruteForceMatcher /////////////////////////////////////////////////
BFMatcher : : BFMatcher ( int _normType , bool _crossCheck )
{
normType = _normType ;
crossCheck = _crossCheck ;
}
Ptr < DescriptorMatcher > BFMatcher : : clone ( bool emptyTrainData ) const
{
Ptr < BFMatcher > matcher = makePtr < BFMatcher > ( normType , crossCheck ) ;
if ( ! emptyTrainData )
{
matcher - > trainDescCollection . resize ( trainDescCollection . size ( ) ) ;
std : : transform ( trainDescCollection . begin ( ) , trainDescCollection . end ( ) ,
matcher - > trainDescCollection . begin ( ) , clone_op ) ;
}
return matcher ;
}
bool BFMatcher : : ocl_match ( InputArray query , InputArray _train , std : : vector < std : : vector < DMatch > > & matches , int dstType )
{
UMat trainIdx , distance ;
if ( ! ocl_matchSingle ( query , _train , trainIdx , distance , dstType ) ) return false ;
if ( ! ocl_matchDownload ( trainIdx , distance , matches ) ) return false ;
return true ;
}
bool BFMatcher : : ocl_knnMatch ( InputArray query , InputArray _train , std : : vector < std : : vector < DMatch > > & matches , int k , int dstType , bool compactResult )
{
UMat trainIdx , distance , allDist ;
if ( ! ocl_knnMatchSingle ( query , _train , trainIdx , distance , allDist , k , dstType ) ) return false ;
if ( ! ocl_knnMatchDownload ( trainIdx , distance , matches , compactResult ) ) return false ;
return true ;
}
void BFMatcher : : knnMatchImpl ( InputArray _queryDescriptors , std : : vector < std : : vector < DMatch > > & matches , int knn ,
InputArrayOfArrays _masks , bool compactResult )
{
int trainDescType = trainDescCollection . empty ( ) ? utrainDescCollection [ 0 ] . type ( ) : trainDescCollection [ 0 ] . type ( ) ;
CV_Assert ( _queryDescriptors . type ( ) = = trainDescType ) ;
const int IMGIDX_SHIFT = 18 ;
const int IMGIDX_ONE = ( 1 < < IMGIDX_SHIFT ) ;
if ( _queryDescriptors . empty ( ) | | ( trainDescCollection . empty ( ) & & utrainDescCollection . empty ( ) ) )
{
matches . clear ( ) ;
return ;
}
std : : vector < Mat > masks ;
_masks . getMatVector ( masks ) ;
if ( ! trainDescCollection . empty ( ) & & ! utrainDescCollection . empty ( ) )
{
for ( int i = 0 ; i < ( int ) utrainDescCollection . size ( ) ; i + + )
{
Mat tempMat ;
utrainDescCollection [ i ] . copyTo ( tempMat ) ;
trainDescCollection . push_back ( tempMat ) ;
}
utrainDescCollection . clear ( ) ;
}
int trainDescVectorSize = trainDescCollection . empty ( ) ? ( int ) utrainDescCollection . size ( ) : ( int ) trainDescCollection . size ( ) ;
Size trainDescSize = trainDescCollection . empty ( ) ? utrainDescCollection [ 0 ] . size ( ) : trainDescCollection [ 0 ] . size ( ) ;
int trainDescOffset = trainDescCollection . empty ( ) ? ( int ) utrainDescCollection [ 0 ] . offset : 0 ;
if ( ocl : : useOpenCL ( ) & & _queryDescriptors . isUMat ( ) & & _queryDescriptors . dims ( ) < = 2 & & trainDescVectorSize = = 1 & &
_queryDescriptors . type ( ) = = CV_32FC1 & & _queryDescriptors . offset ( ) = = 0 & & trainDescOffset = = 0 & &
trainDescSize . width = = _queryDescriptors . size ( ) . width & & masks . size ( ) = = 1 & & masks [ 0 ] . total ( ) = = 0 )
{
if ( knn = = 1 )
{
if ( trainDescCollection . empty ( ) )
{
if ( ocl_match ( _queryDescriptors , utrainDescCollection [ 0 ] , matches , normType ) )
return ;
}
else
{
if ( ocl_match ( _queryDescriptors , trainDescCollection [ 0 ] , matches , normType ) )
return ;
}
}
else
{
if ( trainDescCollection . empty ( ) )
{
if ( ocl_knnMatch ( _queryDescriptors , utrainDescCollection [ 0 ] , matches , knn , normType , compactResult ) )
return ;
}
else
{
if ( ocl_knnMatch ( _queryDescriptors , trainDescCollection [ 0 ] , matches , knn , normType , compactResult ) )
return ;
}
}
}
Mat queryDescriptors = _queryDescriptors . getMat ( ) ;
if ( trainDescCollection . empty ( ) & & ! utrainDescCollection . empty ( ) )
{
for ( int i = 0 ; i < ( int ) utrainDescCollection . size ( ) ; i + + )
{
Mat tempMat ;
utrainDescCollection [ i ] . copyTo ( tempMat ) ;
trainDescCollection . push_back ( tempMat ) ;
}
utrainDescCollection . clear ( ) ;
}
matches . reserve ( queryDescriptors . rows ) ;
Mat dist , nidx ;
int iIdx , imgCount = ( int ) trainDescCollection . size ( ) , update = 0 ;
int dtype = normType = = NORM_HAMMING | | normType = = NORM_HAMMING2 | |
( normType = = NORM_L1 & & queryDescriptors . type ( ) = = CV_8U ) ? CV_32S : CV_32F ;
CV_Assert ( ( int64 ) imgCount * IMGIDX_ONE < INT_MAX ) ;
for ( iIdx = 0 ; iIdx < imgCount ; iIdx + + )
{
CV_Assert ( trainDescCollection [ iIdx ] . rows < IMGIDX_ONE ) ;
batchDistance ( queryDescriptors , trainDescCollection [ iIdx ] , dist , dtype , nidx ,
normType , knn , masks . empty ( ) ? Mat ( ) : masks [ iIdx ] , update , crossCheck ) ;
update + = IMGIDX_ONE ;
}
if ( dtype = = CV_32S )
{
Mat temp ;
dist . convertTo ( temp , CV_32F ) ;
dist = temp ;
}
for ( int qIdx = 0 ; qIdx < queryDescriptors . rows ; qIdx + + )
{
const float * distptr = dist . ptr < float > ( qIdx ) ;
const int * nidxptr = nidx . ptr < int > ( qIdx ) ;
matches . push_back ( std : : vector < DMatch > ( ) ) ;
std : : vector < DMatch > & mq = matches . back ( ) ;
mq . reserve ( knn ) ;
for ( int k = 0 ; k < nidx . cols ; k + + )
{
if ( nidxptr [ k ] < 0 )
break ;
mq . push_back ( DMatch ( qIdx , nidxptr [ k ] & ( IMGIDX_ONE - 1 ) ,
nidxptr [ k ] > > IMGIDX_SHIFT , distptr [ k ] ) ) ;
}
if ( mq . empty ( ) & & compactResult )
matches . pop_back ( ) ;
}
}
bool BFMatcher : : ocl_radiusMatch ( InputArray query , InputArray _train , std : : vector < std : : vector < DMatch > > & matches ,
float maxDistance , int dstType , bool compactResult )
{
UMat trainIdx , distance , nMatches ;
if ( ! ocl_radiusMatchSingle ( query , _train , trainIdx , distance , nMatches , maxDistance , dstType ) ) return false ;
if ( ! ocl_radiusMatchDownload ( trainIdx , distance , nMatches , matches , compactResult ) ) return false ;
return true ;
}
void BFMatcher : : radiusMatchImpl ( InputArray _queryDescriptors , std : : vector < std : : vector < DMatch > > & matches ,
float maxDistance , InputArrayOfArrays _masks , bool compactResult )
{
int trainDescType = trainDescCollection . empty ( ) ? utrainDescCollection [ 0 ] . type ( ) : trainDescCollection [ 0 ] . type ( ) ;
CV_Assert ( _queryDescriptors . type ( ) = = trainDescType ) ;
if ( _queryDescriptors . empty ( ) | | ( trainDescCollection . empty ( ) & & utrainDescCollection . empty ( ) ) )
{
matches . clear ( ) ;
return ;
}
std : : vector < Mat > masks ;
_masks . getMatVector ( masks ) ;
if ( ! trainDescCollection . empty ( ) & & ! utrainDescCollection . empty ( ) )
{
for ( int i = 0 ; i < ( int ) utrainDescCollection . size ( ) ; i + + )
{
Mat tempMat ;
utrainDescCollection [ i ] . copyTo ( tempMat ) ;
trainDescCollection . push_back ( tempMat ) ;
}
utrainDescCollection . clear ( ) ;
}
int trainDescVectorSize = trainDescCollection . empty ( ) ? ( int ) utrainDescCollection . size ( ) : ( int ) trainDescCollection . size ( ) ;
Size trainDescSize = trainDescCollection . empty ( ) ? utrainDescCollection [ 0 ] . size ( ) : trainDescCollection [ 0 ] . size ( ) ;
int trainDescOffset = trainDescCollection . empty ( ) ? ( int ) utrainDescCollection [ 0 ] . offset : 0 ;
if ( ocl : : useOpenCL ( ) & & _queryDescriptors . isUMat ( ) & & _queryDescriptors . dims ( ) < = 2 & & trainDescVectorSize = = 1 & &
_queryDescriptors . type ( ) = = CV_32FC1 & & _queryDescriptors . offset ( ) = = 0 & & trainDescOffset = = 0 & &
trainDescSize . width = = _queryDescriptors . size ( ) . width & & masks . size ( ) = = 1 & & masks [ 0 ] . total ( ) = = 0 )
{
if ( trainDescCollection . empty ( ) )
{
if ( ocl_radiusMatch ( _queryDescriptors , utrainDescCollection [ 0 ] , matches , maxDistance , normType , compactResult ) )
return ;
}
else
{
if ( ocl_radiusMatch ( _queryDescriptors , trainDescCollection [ 0 ] , matches , maxDistance , normType , compactResult ) )
return ;
}
}
Mat queryDescriptors = _queryDescriptors . getMat ( ) ;
if ( trainDescCollection . empty ( ) & & ! utrainDescCollection . empty ( ) )
{
for ( int i = 0 ; i < ( int ) utrainDescCollection . size ( ) ; i + + )
{
Mat tempMat ;
utrainDescCollection [ i ] . copyTo ( tempMat ) ;
trainDescCollection . push_back ( tempMat ) ;
}
utrainDescCollection . clear ( ) ;
}
matches . resize ( queryDescriptors . rows ) ;
Mat dist , distf ;
int iIdx , imgCount = ( int ) trainDescCollection . size ( ) ;
int dtype = normType = = NORM_HAMMING | |
( normType = = NORM_L1 & & queryDescriptors . type ( ) = = CV_8U ) ? CV_32S : CV_32F ;
for ( iIdx = 0 ; iIdx < imgCount ; iIdx + + )
{
batchDistance ( queryDescriptors , trainDescCollection [ iIdx ] , dist , dtype , noArray ( ) ,
normType , 0 , masks . empty ( ) ? Mat ( ) : masks [ iIdx ] , 0 , false ) ;
if ( dtype = = CV_32S )
dist . convertTo ( distf , CV_32F ) ;
else
distf = dist ;
for ( int qIdx = 0 ; qIdx < queryDescriptors . rows ; qIdx + + )
{
const float * distptr = distf . ptr < float > ( qIdx ) ;
std : : vector < DMatch > & mq = matches [ qIdx ] ;
for ( int k = 0 ; k < distf . cols ; k + + )
{
if ( distptr [ k ] < = maxDistance )
mq . push_back ( DMatch ( qIdx , k , iIdx , distptr [ k ] ) ) ;
}
}
}
int qIdx0 = 0 ;
for ( int qIdx = 0 ; qIdx < queryDescriptors . rows ; qIdx + + )
{
if ( matches [ qIdx ] . empty ( ) & & compactResult )
continue ;
if ( qIdx0 < qIdx )
std : : swap ( matches [ qIdx ] , matches [ qIdx0 ] ) ;
std : : sort ( matches [ qIdx0 ] . begin ( ) , matches [ qIdx0 ] . end ( ) ) ;
qIdx0 + + ;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* Factory function for DescriptorMatcher creating
*/
Ptr < DescriptorMatcher > DescriptorMatcher : : create ( const String & descriptorMatcherType )
{
Ptr < DescriptorMatcher > dm ;
if ( ! descriptorMatcherType . compare ( " FlannBased " ) )
{
dm = makePtr < FlannBasedMatcher > ( ) ;
}
else if ( ! descriptorMatcherType . compare ( " BruteForce " ) ) // L2
{
dm = makePtr < BFMatcher > ( int ( NORM_L2 ) ) ; // anonymous enums can't be template parameters
}
else if ( ! descriptorMatcherType . compare ( " BruteForce-SL2 " ) ) // Squared L2
{
dm = makePtr < BFMatcher > ( int ( NORM_L2SQR ) ) ;
}
else if ( ! descriptorMatcherType . compare ( " BruteForce-L1 " ) )
{
dm = makePtr < BFMatcher > ( int ( NORM_L1 ) ) ;
}
else if ( ! descriptorMatcherType . compare ( " BruteForce-Hamming " ) | |
! descriptorMatcherType . compare ( " BruteForce-HammingLUT " ) )
{
dm = makePtr < BFMatcher > ( int ( NORM_HAMMING ) ) ;
}
else if ( ! descriptorMatcherType . compare ( " BruteForce-Hamming(2) " ) )
{
dm = makePtr < BFMatcher > ( int ( NORM_HAMMING2 ) ) ;
}
else
CV_Error ( Error : : StsBadArg , " Unknown matcher name " ) ;
return dm ;
}
/*
* Flann based matcher
*/
FlannBasedMatcher : : FlannBasedMatcher ( const Ptr < flann : : IndexParams > & _indexParams , const Ptr < flann : : SearchParams > & _searchParams )
: indexParams ( _indexParams ) , searchParams ( _searchParams ) , addedDescCount ( 0 )
{
CV_Assert ( _indexParams ) ;
CV_Assert ( _searchParams ) ;
}
void FlannBasedMatcher : : add ( const std : : vector < Mat > & descriptors )
{
DescriptorMatcher : : add ( descriptors ) ;
for ( size_t i = 0 ; i < descriptors . size ( ) ; i + + )
{
addedDescCount + = descriptors [ i ] . rows ;
}
}
void FlannBasedMatcher : : clear ( )
{
DescriptorMatcher : : clear ( ) ;
mergedDescriptors . clear ( ) ;
flannIndex . release ( ) ;
addedDescCount = 0 ;
}
void FlannBasedMatcher : : train ( )
{
if ( ! flannIndex | | mergedDescriptors . size ( ) < addedDescCount )
{
mergedDescriptors . set ( trainDescCollection ) ;
flannIndex = makePtr < flann : : Index > ( mergedDescriptors . getDescriptors ( ) , * indexParams ) ;
}
}
void FlannBasedMatcher : : read ( const FileNode & fn )
{
if ( ! indexParams )
indexParams = makePtr < flann : : IndexParams > ( ) ;
FileNode ip = fn [ " indexParams " ] ;
CV_Assert ( ip . type ( ) = = FileNode : : SEQ ) ;
for ( int i = 0 ; i < ( int ) ip . size ( ) ; + + i )
{
CV_Assert ( ip [ i ] . type ( ) = = FileNode : : MAP ) ;
String _name = ( String ) ip [ i ] [ " name " ] ;
int type = ( int ) ip [ i ] [ " type " ] ;
switch ( type )
{
case CV_8U :
case CV_8S :
case CV_16U :
case CV_16S :
case CV_32S :
indexParams - > setInt ( _name , ( int ) ip [ i ] [ " value " ] ) ;
break ;
case CV_32F :
indexParams - > setFloat ( _name , ( float ) ip [ i ] [ " value " ] ) ;
break ;
case CV_64F :
indexParams - > setDouble ( _name , ( double ) ip [ i ] [ " value " ] ) ;
break ;
case CV_USRTYPE1 :
indexParams - > setString ( _name , ( String ) ip [ i ] [ " value " ] ) ;
break ;
case CV_MAKETYPE ( CV_USRTYPE1 , 2 ) :
indexParams - > setBool ( _name , ( int ) ip [ i ] [ " value " ] ! = 0 ) ;
break ;
case CV_MAKETYPE ( CV_USRTYPE1 , 3 ) :
indexParams - > setAlgorithm ( ( int ) ip [ i ] [ " value " ] ) ;
break ;
} ;
}
if ( ! searchParams )
searchParams = makePtr < flann : : SearchParams > ( ) ;
FileNode sp = fn [ " searchParams " ] ;
CV_Assert ( sp . type ( ) = = FileNode : : SEQ ) ;
for ( int i = 0 ; i < ( int ) sp . size ( ) ; + + i )
{
CV_Assert ( sp [ i ] . type ( ) = = FileNode : : MAP ) ;
String _name = ( String ) sp [ i ] [ " name " ] ;
int type = ( int ) sp [ i ] [ " type " ] ;
switch ( type )
{
case CV_8U :
case CV_8S :
case CV_16U :
case CV_16S :
case CV_32S :
searchParams - > setInt ( _name , ( int ) sp [ i ] [ " value " ] ) ;
break ;
case CV_32F :
searchParams - > setFloat ( _name , ( float ) ip [ i ] [ " value " ] ) ;
break ;
case CV_64F :
searchParams - > setDouble ( _name , ( double ) ip [ i ] [ " value " ] ) ;
break ;
case CV_USRTYPE1 :
searchParams - > setString ( _name , ( String ) ip [ i ] [ " value " ] ) ;
break ;
case CV_MAKETYPE ( CV_USRTYPE1 , 2 ) :
searchParams - > setBool ( _name , ( int ) ip [ i ] [ " value " ] ! = 0 ) ;
break ;
case CV_MAKETYPE ( CV_USRTYPE1 , 3 ) :
searchParams - > setAlgorithm ( ( int ) ip [ i ] [ " value " ] ) ;
break ;
} ;
}
flannIndex . release ( ) ;
}
void FlannBasedMatcher : : write ( FileStorage & fs ) const
{
fs < < " indexParams " < < " [ " ;
if ( indexParams )
{
std : : vector < String > names ;
std : : vector < int > types ;
std : : vector < String > strValues ;
std : : vector < double > numValues ;
indexParams - > getAll ( names , types , strValues , numValues ) ;
for ( size_t i = 0 ; i < names . size ( ) ; + + i )
{
fs < < " { " < < " name " < < names [ i ] < < " type " < < types [ i ] < < " value " ;
switch ( types [ i ] )
{
case CV_8U :
fs < < ( uchar ) numValues [ i ] ;
break ;
case CV_8S :
fs < < ( char ) numValues [ i ] ;
break ;
case CV_16U :
fs < < ( ushort ) numValues [ i ] ;
break ;
case CV_16S :
fs < < ( short ) numValues [ i ] ;
break ;
case CV_32S :
case CV_MAKETYPE ( CV_USRTYPE1 , 2 ) :
case CV_MAKETYPE ( CV_USRTYPE1 , 3 ) :
fs < < ( int ) numValues [ i ] ;
break ;
case CV_32F :
fs < < ( float ) numValues [ i ] ;
break ;
case CV_64F :
fs < < ( double ) numValues [ i ] ;
break ;
case CV_USRTYPE1 :
fs < < strValues [ i ] ;
break ;
default :
fs < < ( double ) numValues [ i ] ;
fs < < " typename " < < strValues [ i ] ;
break ;
}
fs < < " } " ;
}
}
fs < < " ] " < < " searchParams " < < " [ " ;
if ( searchParams )
{
std : : vector < String > names ;
std : : vector < int > types ;
std : : vector < String > strValues ;
std : : vector < double > numValues ;
searchParams - > getAll ( names , types , strValues , numValues ) ;
for ( size_t i = 0 ; i < names . size ( ) ; + + i )
{
fs < < " { " < < " name " < < names [ i ] < < " type " < < types [ i ] < < " value " ;
switch ( types [ i ] )
{
case CV_8U :
fs < < ( uchar ) numValues [ i ] ;
break ;
case CV_8S :
fs < < ( char ) numValues [ i ] ;
break ;
case CV_16U :
fs < < ( ushort ) numValues [ i ] ;
break ;
case CV_16S :
fs < < ( short ) numValues [ i ] ;
break ;
case CV_32S :
case CV_MAKETYPE ( CV_USRTYPE1 , 2 ) :
case CV_MAKETYPE ( CV_USRTYPE1 , 3 ) :
fs < < ( int ) numValues [ i ] ;
break ;
case CV_32F :
fs < < ( float ) numValues [ i ] ;
break ;
case CV_64F :
fs < < ( double ) numValues [ i ] ;
break ;
case CV_USRTYPE1 :
fs < < strValues [ i ] ;
break ;
default :
fs < < ( double ) numValues [ i ] ;
fs < < " typename " < < strValues [ i ] ;
break ;
}
fs < < " } " ;
}
}
fs < < " ] " ;
}
bool FlannBasedMatcher : : isMaskSupported ( ) const
{
return false ;
}
Ptr < DescriptorMatcher > FlannBasedMatcher : : clone ( bool emptyTrainData ) const
{
Ptr < FlannBasedMatcher > matcher = makePtr < FlannBasedMatcher > ( indexParams , searchParams ) ;
if ( ! emptyTrainData )
{
CV_Error ( Error : : StsNotImplemented , " deep clone functionality is not implemented, because "
" Flann::Index has not copy constructor or clone method " ) ;
//matcher->flannIndex;
matcher - > addedDescCount = addedDescCount ;
matcher - > mergedDescriptors = DescriptorCollection ( mergedDescriptors ) ;
std : : transform ( trainDescCollection . begin ( ) , trainDescCollection . end ( ) ,
matcher - > trainDescCollection . begin ( ) , clone_op ) ;
}
return matcher ;
}
void FlannBasedMatcher : : convertToDMatches ( const DescriptorCollection & collection , const Mat & indices , const Mat & dists ,
std : : vector < std : : vector < DMatch > > & matches )
{
matches . resize ( indices . rows ) ;
for ( int i = 0 ; i < indices . rows ; i + + )
{
for ( int j = 0 ; j < indices . cols ; j + + )
{
int idx = indices . at < int > ( i , j ) ;
if ( idx > = 0 )
{
int imgIdx , trainIdx ;
collection . getLocalIdx ( idx , imgIdx , trainIdx ) ;
float dist = 0 ;
if ( dists . type ( ) = = CV_32S )
dist = static_cast < float > ( dists . at < int > ( i , j ) ) ;
else
dist = std : : sqrt ( dists . at < float > ( i , j ) ) ;
matches [ i ] . push_back ( DMatch ( i , trainIdx , imgIdx , dist ) ) ;
}
}
}
}
void FlannBasedMatcher : : knnMatchImpl ( InputArray _queryDescriptors , std : : vector < std : : vector < DMatch > > & matches , int knn ,
InputArrayOfArrays /*masks*/ , bool /*compactResult*/ )
{
Mat queryDescriptors = _queryDescriptors . getMat ( ) ;
Mat indices ( queryDescriptors . rows , knn , CV_32SC1 ) ;
Mat dists ( queryDescriptors . rows , knn , CV_32FC1 ) ;
flannIndex - > knnSearch ( queryDescriptors , indices , dists , knn , * searchParams ) ;
convertToDMatches ( mergedDescriptors , indices , dists , matches ) ;
}
void FlannBasedMatcher : : radiusMatchImpl ( InputArray _queryDescriptors , std : : vector < std : : vector < DMatch > > & matches , float maxDistance ,
InputArrayOfArrays /*masks*/ , bool /*compactResult*/ )
{
Mat queryDescriptors = _queryDescriptors . getMat ( ) ;
const int count = mergedDescriptors . size ( ) ; // TODO do count as param?
Mat indices ( queryDescriptors . rows , count , CV_32SC1 , Scalar : : all ( - 1 ) ) ;
Mat dists ( queryDescriptors . rows , count , CV_32FC1 , Scalar : : all ( - 1 ) ) ;
for ( int qIdx = 0 ; qIdx < queryDescriptors . rows ; qIdx + + )
{
Mat queryDescriptorsRow = queryDescriptors . row ( qIdx ) ;
Mat indicesRow = indices . row ( qIdx ) ;
Mat distsRow = dists . row ( qIdx ) ;
flannIndex - > radiusSearch ( queryDescriptorsRow , indicesRow , distsRow , maxDistance * maxDistance , count , * searchParams ) ;
}
convertToDMatches ( mergedDescriptors , indices , dists , matches ) ;
}
/****************************************************************************************\
* GenericDescriptorMatcher *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* KeyPointCollection
*/
GenericDescriptorMatcher : : KeyPointCollection : : KeyPointCollection ( ) : pointCount ( 0 )
{ }
GenericDescriptorMatcher : : KeyPointCollection : : KeyPointCollection ( const KeyPointCollection & collection )
{
pointCount = collection . pointCount ;
std : : transform ( collection . images . begin ( ) , collection . images . end ( ) , images . begin ( ) , clone_op ) ;
keypoints . resize ( collection . keypoints . size ( ) ) ;
for ( size_t i = 0 ; i < keypoints . size ( ) ; i + + )
std : : copy ( collection . keypoints [ i ] . begin ( ) , collection . keypoints [ i ] . end ( ) , keypoints [ i ] . begin ( ) ) ;
std : : copy ( collection . startIndices . begin ( ) , collection . startIndices . end ( ) , startIndices . begin ( ) ) ;
}
void GenericDescriptorMatcher : : KeyPointCollection : : add ( const std : : vector < Mat > & _images ,
const std : : vector < std : : vector < KeyPoint > > & _points )
{
CV_Assert ( ! _images . empty ( ) ) ;
CV_Assert ( _images . size ( ) = = _points . size ( ) ) ;
images . insert ( images . end ( ) , _images . begin ( ) , _images . end ( ) ) ;
keypoints . insert ( keypoints . end ( ) , _points . begin ( ) , _points . end ( ) ) ;
for ( size_t i = 0 ; i < _points . size ( ) ; i + + )
pointCount + = ( int ) _points [ i ] . size ( ) ;
size_t prevSize = startIndices . size ( ) , addSize = _images . size ( ) ;
startIndices . resize ( prevSize + addSize ) ;
if ( prevSize = = 0 )
startIndices [ prevSize ] = 0 ; //first
else
startIndices [ prevSize ] = ( int ) ( startIndices [ prevSize - 1 ] + keypoints [ prevSize - 1 ] . size ( ) ) ;
for ( size_t i = prevSize + 1 ; i < prevSize + addSize ; i + + )
{
startIndices [ i ] = ( int ) ( startIndices [ i - 1 ] + keypoints [ i - 1 ] . size ( ) ) ;
}
}
void GenericDescriptorMatcher : : KeyPointCollection : : clear ( )
{
pointCount = 0 ;
images . clear ( ) ;
keypoints . clear ( ) ;
startIndices . clear ( ) ;
}
size_t GenericDescriptorMatcher : : KeyPointCollection : : keypointCount ( ) const
{
return pointCount ;
}
size_t GenericDescriptorMatcher : : KeyPointCollection : : imageCount ( ) const
{
return images . size ( ) ;
}
const std : : vector < std : : vector < KeyPoint > > & GenericDescriptorMatcher : : KeyPointCollection : : getKeypoints ( ) const
{
return keypoints ;
}
const std : : vector < KeyPoint > & GenericDescriptorMatcher : : KeyPointCollection : : getKeypoints ( int imgIdx ) const
{
CV_Assert ( imgIdx < ( int ) imageCount ( ) ) ;
return keypoints [ imgIdx ] ;
}
const KeyPoint & GenericDescriptorMatcher : : KeyPointCollection : : getKeyPoint ( int imgIdx , int localPointIdx ) const
{
CV_Assert ( imgIdx < ( int ) images . size ( ) ) ;
CV_Assert ( localPointIdx < ( int ) keypoints [ imgIdx ] . size ( ) ) ;
return keypoints [ imgIdx ] [ localPointIdx ] ;
}
const KeyPoint & GenericDescriptorMatcher : : KeyPointCollection : : getKeyPoint ( int globalPointIdx ) const
{
int imgIdx , localPointIdx ;
getLocalIdx ( globalPointIdx , imgIdx , localPointIdx ) ;
return keypoints [ imgIdx ] [ localPointIdx ] ;
}
void GenericDescriptorMatcher : : KeyPointCollection : : getLocalIdx ( int globalPointIdx , int & imgIdx , int & localPointIdx ) const
{
imgIdx = - 1 ;
CV_Assert ( globalPointIdx < ( int ) keypointCount ( ) ) ;
for ( size_t i = 1 ; i < startIndices . size ( ) ; i + + )
{
if ( globalPointIdx < startIndices [ i ] )
{
imgIdx = ( int ) ( i - 1 ) ;
break ;
}
}
imgIdx = imgIdx = = - 1 ? ( int ) ( startIndices . size ( ) - 1 ) : imgIdx ;
localPointIdx = globalPointIdx - startIndices [ imgIdx ] ;
}
const std : : vector < Mat > & GenericDescriptorMatcher : : KeyPointCollection : : getImages ( ) const
{
return images ;
}
const Mat & GenericDescriptorMatcher : : KeyPointCollection : : getImage ( int imgIdx ) const
{
CV_Assert ( imgIdx < ( int ) imageCount ( ) ) ;
return images [ imgIdx ] ;
}
/*
* GenericDescriptorMatcher
*/
GenericDescriptorMatcher : : GenericDescriptorMatcher ( )
{ }
GenericDescriptorMatcher : : ~ GenericDescriptorMatcher ( )
{ }
void GenericDescriptorMatcher : : add ( const std : : vector < Mat > & images ,
std : : vector < std : : vector < KeyPoint > > & keypoints )
{
CV_Assert ( ! images . empty ( ) ) ;
CV_Assert ( images . size ( ) = = keypoints . size ( ) ) ;
for ( size_t i = 0 ; i < images . size ( ) ; i + + )
{
CV_Assert ( ! images [ i ] . empty ( ) ) ;
KeyPointsFilter : : runByImageBorder ( keypoints [ i ] , images [ i ] . size ( ) , 0 ) ;
KeyPointsFilter : : runByKeypointSize ( keypoints [ i ] , std : : numeric_limits < float > : : epsilon ( ) ) ;
}
trainPointCollection . add ( images , keypoints ) ;
}
const std : : vector < Mat > & GenericDescriptorMatcher : : getTrainImages ( ) const
{
return trainPointCollection . getImages ( ) ;
}
const std : : vector < std : : vector < KeyPoint > > & GenericDescriptorMatcher : : getTrainKeypoints ( ) const
{
return trainPointCollection . getKeypoints ( ) ;
}
void GenericDescriptorMatcher : : clear ( )
{
trainPointCollection . clear ( ) ;
}
void GenericDescriptorMatcher : : train ( )
{ }
void GenericDescriptorMatcher : : classify ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
const Mat & trainImage , std : : vector < KeyPoint > & trainKeypoints ) const
{
std : : vector < DMatch > matches ;
match ( queryImage , queryKeypoints , trainImage , trainKeypoints , matches ) ;
// remap keypoint indices to descriptors
for ( size_t i = 0 ; i < matches . size ( ) ; i + + )
queryKeypoints [ matches [ i ] . queryIdx ] . class_id = trainKeypoints [ matches [ i ] . trainIdx ] . class_id ;
}
void GenericDescriptorMatcher : : classify ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints )
{
std : : vector < DMatch > matches ;
match ( queryImage , queryKeypoints , matches ) ;
// remap keypoint indices to descriptors
for ( size_t i = 0 ; i < matches . size ( ) ; i + + )
queryKeypoints [ matches [ i ] . queryIdx ] . class_id = trainPointCollection . getKeyPoint ( matches [ i ] . trainIdx , matches [ i ] . trainIdx ) . class_id ;
}
void GenericDescriptorMatcher : : match ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
const Mat & trainImage , std : : vector < KeyPoint > & trainKeypoints ,
std : : vector < DMatch > & matches , const Mat & mask ) const
{
Ptr < GenericDescriptorMatcher > tempMatcher = clone ( true ) ;
std : : vector < std : : vector < KeyPoint > > vecTrainPoints ( 1 , trainKeypoints ) ;
tempMatcher - > add ( std : : vector < Mat > ( 1 , trainImage ) , vecTrainPoints ) ;
tempMatcher - > match ( queryImage , queryKeypoints , matches , std : : vector < Mat > ( 1 , mask ) ) ;
vecTrainPoints [ 0 ] . swap ( trainKeypoints ) ;
}
void GenericDescriptorMatcher : : knnMatch ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
const Mat & trainImage , std : : vector < KeyPoint > & trainKeypoints ,
std : : vector < std : : vector < DMatch > > & matches , int knn , const Mat & mask , bool compactResult ) const
{
Ptr < GenericDescriptorMatcher > tempMatcher = clone ( true ) ;
std : : vector < std : : vector < KeyPoint > > vecTrainPoints ( 1 , trainKeypoints ) ;
tempMatcher - > add ( std : : vector < Mat > ( 1 , trainImage ) , vecTrainPoints ) ;
tempMatcher - > knnMatch ( queryImage , queryKeypoints , matches , knn , std : : vector < Mat > ( 1 , mask ) , compactResult ) ;
vecTrainPoints [ 0 ] . swap ( trainKeypoints ) ;
}
void GenericDescriptorMatcher : : radiusMatch ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
const Mat & trainImage , std : : vector < KeyPoint > & trainKeypoints ,
std : : vector < std : : vector < DMatch > > & matches , float maxDistance ,
const Mat & mask , bool compactResult ) const
{
Ptr < GenericDescriptorMatcher > tempMatcher = clone ( true ) ;
std : : vector < std : : vector < KeyPoint > > vecTrainPoints ( 1 , trainKeypoints ) ;
tempMatcher - > add ( std : : vector < Mat > ( 1 , trainImage ) , vecTrainPoints ) ;
tempMatcher - > radiusMatch ( queryImage , queryKeypoints , matches , maxDistance , std : : vector < Mat > ( 1 , mask ) , compactResult ) ;
vecTrainPoints [ 0 ] . swap ( trainKeypoints ) ;
}
void GenericDescriptorMatcher : : match ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
std : : vector < DMatch > & matches , const std : : vector < Mat > & masks )
{
std : : vector < std : : vector < DMatch > > knnMatches ;
knnMatch ( queryImage , queryKeypoints , knnMatches , 1 , masks , false ) ;
convertMatches ( knnMatches , matches ) ;
}
void GenericDescriptorMatcher : : knnMatch ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
std : : vector < std : : vector < DMatch > > & matches , int knn ,
const std : : vector < Mat > & masks , bool compactResult )
{
matches . clear ( ) ;
if ( queryImage . empty ( ) | | queryKeypoints . empty ( ) )
return ;
KeyPointsFilter : : runByImageBorder ( queryKeypoints , queryImage . size ( ) , 0 ) ;
KeyPointsFilter : : runByKeypointSize ( queryKeypoints , std : : numeric_limits < float > : : epsilon ( ) ) ;
train ( ) ;
knnMatchImpl ( queryImage , queryKeypoints , matches , knn , masks , compactResult ) ;
}
void GenericDescriptorMatcher : : radiusMatch ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
std : : vector < std : : vector < DMatch > > & matches , float maxDistance ,
const std : : vector < Mat > & masks , bool compactResult )
{
matches . clear ( ) ;
if ( queryImage . empty ( ) | | queryKeypoints . empty ( ) )
return ;
KeyPointsFilter : : runByImageBorder ( queryKeypoints , queryImage . size ( ) , 0 ) ;
KeyPointsFilter : : runByKeypointSize ( queryKeypoints , std : : numeric_limits < float > : : epsilon ( ) ) ;
train ( ) ;
radiusMatchImpl ( queryImage , queryKeypoints , matches , maxDistance , masks , compactResult ) ;
}
void GenericDescriptorMatcher : : read ( const FileNode & )
{ }
void GenericDescriptorMatcher : : write ( FileStorage & ) const
{ }
bool GenericDescriptorMatcher : : empty ( ) const
{
return true ;
}
/*
* Factory function for GenericDescriptorMatch creating
*/
Ptr < GenericDescriptorMatcher > GenericDescriptorMatcher : : create ( const String & genericDescritptorMatcherType ,
const String & paramsFilename )
{
Ptr < GenericDescriptorMatcher > descriptorMatcher =
Algorithm : : create < GenericDescriptorMatcher > ( " DescriptorMatcher. " + genericDescritptorMatcherType ) ;
if ( ! paramsFilename . empty ( ) & & descriptorMatcher )
{
FileStorage fs = FileStorage ( paramsFilename , FileStorage : : READ ) ;
if ( fs . isOpened ( ) )
{
descriptorMatcher - > read ( fs . root ( ) ) ;
fs . release ( ) ;
}
}
return descriptorMatcher ;
}
/****************************************************************************************\
* VectorDescriptorMatcher *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
VectorDescriptorMatcher : : VectorDescriptorMatcher ( const Ptr < DescriptorExtractor > & _extractor ,
const Ptr < DescriptorMatcher > & _matcher )
: extractor ( _extractor ) , matcher ( _matcher )
{
CV_Assert ( extractor & & matcher ) ;
}
VectorDescriptorMatcher : : ~ VectorDescriptorMatcher ( )
{ }
void VectorDescriptorMatcher : : add ( const std : : vector < Mat > & imgCollection ,
std : : vector < std : : vector < KeyPoint > > & pointCollection )
{
std : : vector < Mat > descriptors ;
extractor - > compute ( imgCollection , pointCollection , descriptors ) ;
matcher - > add ( descriptors ) ;
trainPointCollection . add ( imgCollection , pointCollection ) ;
}
void VectorDescriptorMatcher : : clear ( )
{
//extractor->clear();
matcher - > clear ( ) ;
GenericDescriptorMatcher : : clear ( ) ;
}
void VectorDescriptorMatcher : : train ( )
{
matcher - > train ( ) ;
}
bool VectorDescriptorMatcher : : isMaskSupported ( )
{
return matcher - > isMaskSupported ( ) ;
}
void VectorDescriptorMatcher : : knnMatchImpl ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
std : : vector < std : : vector < DMatch > > & matches , int knn ,
const std : : vector < Mat > & masks , bool compactResult )
{
Mat queryDescriptors ;
extractor - > compute ( queryImage , queryKeypoints , queryDescriptors ) ;
matcher - > knnMatch ( queryDescriptors , matches , knn , masks , compactResult ) ;
}
void VectorDescriptorMatcher : : radiusMatchImpl ( const Mat & queryImage , std : : vector < KeyPoint > & queryKeypoints ,
std : : vector < std : : vector < DMatch > > & matches , float maxDistance ,
const std : : vector < Mat > & masks , bool compactResult )
{
Mat queryDescriptors ;
extractor - > compute ( queryImage , queryKeypoints , queryDescriptors ) ;
matcher - > radiusMatch ( queryDescriptors , matches , maxDistance , masks , compactResult ) ;
}
void VectorDescriptorMatcher : : read ( const FileNode & fn )
{
GenericDescriptorMatcher : : read ( fn ) ;
extractor - > read ( fn ) ;
}
void VectorDescriptorMatcher : : write ( FileStorage & fs ) const
{
GenericDescriptorMatcher : : write ( fs ) ;
extractor - > write ( fs ) ;
}
bool VectorDescriptorMatcher : : empty ( ) const
{
return ! extractor | | extractor - > empty ( ) | |
! matcher | | matcher - > empty ( ) ;
}
Ptr < GenericDescriptorMatcher > VectorDescriptorMatcher : : clone ( bool emptyTrainData ) const
{
// TODO clone extractor
return makePtr < VectorDescriptorMatcher > ( extractor , matcher - > clone ( emptyTrainData ) ) ;
}
}