diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 141e58ee8c..a0a7392799 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -2192,13 +2192,6 @@ CV_EXPORTS_W void batchDistance(InputArray src1, InputArray src2, InputArray mask=noArray(), int update=0, bool crosscheck=false); -//! naive nearest neighbor finder which incrementally updates dist and nidx when called repeatedly with the same K and src1, but varying src2 -CV_EXPORTS_W void batchDistanceForBFMatcher(InputArray src1, InputArray src2, - InputOutputArray dist, int dtype, InputOutputArray nidx, - int normType=NORM_L2, int K=1, - InputArray mask=noArray(), int update=0, - bool crosscheck=false); - //! scales and shifts array elements so that either the specified norm (alpha) or the minimum (alpha) and maximum (beta) array values get the specified values CV_EXPORTS_W void normalize( InputArray src, OutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray()); diff --git a/modules/core/src/stat.cpp b/modules/core/src/stat.cpp index 193eaf61a9..8564134d2a 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -2460,21 +2460,32 @@ struct BatchDistInvoker : public ParallelLoopBody BatchDistFunc func; }; -static void batchDistanceImpl( InputArray _src1, InputArray _src2, - InputOutputArray _dist, int dtype, InputOutputArray _nidx, - int normType, int K, InputArray _mask, - int update, bool crosscheck ) +} + +void cv::batchDistance( InputArray _src1, InputArray _src2, + OutputArray _dist, int dtype, OutputArray _nidx, + int normType, int K, InputArray _mask, + int update, bool crosscheck ) { Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); int type = src1.type(); CV_Assert( type == src2.type() && src1.cols == src2.cols && - (type == CV_32F || type == CV_8U)); + (type == CV_32F || type == CV_8U)); + CV_Assert( _nidx.needed() == (K > 0) ); + if( dtype == -1 ) + { + dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F; + } CV_Assert( (type == CV_8U && dtype == CV_32S) || dtype == CV_32F); + K = std::min(K, src2.rows); + + _dist.create(src1.rows, (K > 0 ? K : src2.rows), dtype); Mat dist = _dist.getMat(), nidx; if( _nidx.needed() ) { + _nidx.create(dist.size(), CV_32S); nidx = _nidx.getMat(); } @@ -2562,55 +2573,6 @@ static void batchDistanceImpl( InputArray _src1, InputArray _src2, BatchDistInvoker(src1, src2, dist, nidx, K, mask, update, func)); } -} - - -void cv::batchDistance( InputArray _src1, InputArray _src2, - OutputArray _dist, int dtype, OutputArray _nidx, - int normType, int K, InputArray _mask, - int update, bool crosscheck ) -{ - if( dtype == -1 ) - { - dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F; - } - - // K == 0: return all matches; K > 0: return K best matches, but never more than the number of candidates in _src2 - CV_Assert( _nidx.needed() == (K > 0) ); - int candidates = _src2.size().height; - K = std::min( K, candidates ); - _dist.create( _src1.size().height, (K > 0 ? K : candidates), dtype ); - if( _nidx.needed() ) - { - _nidx.create( _dist.size(), CV_32S ); - } - - batchDistanceImpl( _src1, _src2, _dist, dtype, _nidx, normType, K, _mask, update, crosscheck ); -} - - -void cv::batchDistanceForBFMatcher( InputArray _src1, InputArray _src2, - InputOutputArray _dist, int dtype, InputOutputArray _nidx, - int normType, int K, InputArray _mask, - int update, bool crosscheck ) -{ - if( dtype == -1 ) - { - dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F; - } - - // always work with K matches (unlike cv::batchDistance), even if _src2 has fewer candidates - // if this function is called in a loop, then the other loop iterations may require all K - CV_Assert( K > 0 && _nidx.needed() ); - cv::Size size( K, _src1.size().height ); - CV_Assert( update == 0 || (_dist.size() == size && _nidx.size() == size) ); - _dist.create( size, dtype ); - _nidx.create( size, CV_32S ); - - batchDistanceImpl( _src1, _src2, _dist, dtype, _nidx, normType, K, _mask, update, crosscheck ); - CV_Assert( _dist.size() == size && _nidx.size() == size ); -} - void cv::findNonZero( InputArray _src, OutputArray _idx ) { diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index 9b73eb4f3c..893ad7743a 100644 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -352,19 +352,28 @@ void BFMatcher::knnMatchImpl( const Mat& queryDescriptors, vector 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; + int maxRows = 0; CV_Assert( (int64)imgCount*IMGIDX_ONE < INT_MAX ); + for( iIdx = 0; iIdx < imgCount; iIdx++ ) + maxRows = std::max(maxRows, trainDescCollection[iIdx].rows); + + int m = queryDescriptors.rows; + Mat dist(m, knn, dtype), nidx(m, knn, CV_32S); + dist = Scalar::all(dtype == CV_32S ? (double)INT_MAX : (double)FLT_MAX); + nidx = Scalar::all(-1); + for( iIdx = 0; iIdx < imgCount; iIdx++ ) { CV_Assert( trainDescCollection[iIdx].rows < IMGIDX_ONE ); - batchDistanceForBFMatcher(queryDescriptors, trainDescCollection[iIdx], dist, dtype, nidx, - normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck); + int n = std::min(knn, trainDescCollection[iIdx].rows); + Mat dist_i = dist.colRange(0, n), nidx_i = nidx.colRange(0, n); + batchDistance(queryDescriptors, trainDescCollection[iIdx], dist_i, dtype, nidx_i, + normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck); update += IMGIDX_ONE; }