fix for bug 3172
authorE Braun <elmar.braun@sh-p.de>
Tue, 2 Sep 2014 16:05:23 +0000 (18:05 +0200)
committerVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Fri, 19 Sep 2014 10:47:43 +0000 (14:47 +0400)
modules/core/include/opencv2/core/core.hpp
modules/core/src/stat.cpp
modules/features2d/src/matchers.cpp

index a0a7392..141e58e 100644 (file)
@@ -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());
index 8ad2aab..193eaf6 100644 (file)
@@ -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 )
 {
index 40612f8..9b73eb4 100644 (file)
@@ -363,8 +363,8 @@ void BFMatcher::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch>
     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;
     }