From bdb82d181f4396e91a8404606b59a9f09f910f46 Mon Sep 17 00:00:00 2001 From: E Braun Date: Tue, 2 Sep 2014 18:05:23 +0200 Subject: [PATCH] fix for bug 3172 --- modules/core/include/opencv2/core/core.hpp | 7 +++ modules/core/src/stat.cpp | 68 +++++++++++++++++++++++------- modules/features2d/src/matchers.cpp | 4 +- 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index a0a7392..141e58e 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -2192,6 +2192,13 @@ 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 8ad2aab..193eaf6 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -2460,32 +2460,21 @@ struct BatchDistInvoker : public ParallelLoopBody BatchDistFunc func; }; -} - -void cv::batchDistance( InputArray _src1, InputArray _src2, - OutputArray _dist, int dtype, OutputArray _nidx, - int normType, int K, InputArray _mask, - int update, bool crosscheck ) +static void batchDistanceImpl( InputArray _src1, InputArray _src2, + InputOutputArray _dist, int dtype, InputOutputArray _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)); - 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(); } @@ -2573,6 +2562,55 @@ void cv::batchDistance( 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 40612f8..9b73eb4 100644 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -363,8 +363,8 @@ void BFMatcher::knnMatchImpl( const Mat& queryDescriptors, vector 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); + batchDistanceForBFMatcher(queryDescriptors, trainDescCollection[iIdx], dist, dtype, nidx, + normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck); update += IMGIDX_ONE; } -- 2.7.4