Merge pull request #3238 from vpisarev:bfmatcher_fix
This commit is contained in:
commit
197b2e75e1
@ -2463,14 +2463,14 @@ struct BatchDistInvoker : public ParallelLoopBody
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cv::batchDistance( InputArray _src1, InputArray _src2,
|
void cv::batchDistance( InputArray _src1, InputArray _src2,
|
||||||
OutputArray _dist, int dtype, OutputArray _nidx,
|
OutputArray _dist, int dtype, OutputArray _nidx,
|
||||||
int normType, int K, InputArray _mask,
|
int normType, int K, InputArray _mask,
|
||||||
int update, bool crosscheck )
|
int update, bool crosscheck )
|
||||||
{
|
{
|
||||||
Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
|
Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
|
||||||
int type = src1.type();
|
int type = src1.type();
|
||||||
CV_Assert( type == src2.type() && src1.cols == src2.cols &&
|
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) );
|
CV_Assert( _nidx.needed() == (K > 0) );
|
||||||
|
|
||||||
if( dtype == -1 )
|
if( dtype == -1 )
|
||||||
|
@ -352,18 +352,27 @@ void BFMatcher::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch>
|
|||||||
|
|
||||||
matches.reserve(queryDescriptors.rows);
|
matches.reserve(queryDescriptors.rows);
|
||||||
|
|
||||||
Mat dist, nidx;
|
|
||||||
|
|
||||||
int iIdx, imgCount = (int)trainDescCollection.size(), update = 0;
|
int iIdx, imgCount = (int)trainDescCollection.size(), update = 0;
|
||||||
int dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ||
|
int dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ||
|
||||||
(normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;
|
(normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;
|
||||||
|
int maxRows = 0;
|
||||||
|
|
||||||
CV_Assert( (int64)imgCount*IMGIDX_ONE < INT_MAX );
|
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++ )
|
for( iIdx = 0; iIdx < imgCount; iIdx++ )
|
||||||
{
|
{
|
||||||
CV_Assert( trainDescCollection[iIdx].rows < IMGIDX_ONE );
|
CV_Assert( trainDescCollection[iIdx].rows < IMGIDX_ONE );
|
||||||
batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, nidx,
|
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);
|
normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck);
|
||||||
update += IMGIDX_ONE;
|
update += IMGIDX_ONE;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,9 @@ public:
|
|||||||
CV_DescriptorMatcherTest( const string& _name, const Ptr<DescriptorMatcher>& _dmatcher, float _badPart ) :
|
CV_DescriptorMatcherTest( const string& _name, const Ptr<DescriptorMatcher>& _dmatcher, float _badPart ) :
|
||||||
badPart(_badPart), name(_name), dmatcher(_dmatcher)
|
badPart(_badPart), name(_name), dmatcher(_dmatcher)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
static void generateData( Mat& query, Mat& train );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const int dim = 500;
|
static const int dim = 500;
|
||||||
static const int queryDescCount = 300; // must be even number because we split train data in some cases in two
|
static const int queryDescCount = 300; // must be even number because we split train data in some cases in two
|
||||||
@ -64,7 +67,6 @@ protected:
|
|||||||
const float badPart;
|
const float badPart;
|
||||||
|
|
||||||
virtual void run( int );
|
virtual void run( int );
|
||||||
void generateData( Mat& query, Mat& train );
|
|
||||||
|
|
||||||
void emptyDataTest();
|
void emptyDataTest();
|
||||||
void matchTest( const Mat& query, const Mat& train );
|
void matchTest( const Mat& query, const Mat& train );
|
||||||
@ -526,6 +528,81 @@ void CV_DescriptorMatcherTest::run( int )
|
|||||||
radiusMatchTest( query, train );
|
radiusMatchTest( query, train );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bug #3172: test that knnMatch() can handle images with fewer than knn keypoints
|
||||||
|
class CV_DescriptorMatcherLowKeypointTest : public cvtest::BaseTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CV_DescriptorMatcherLowKeypointTest( const string& _name, const Ptr<DescriptorMatcher>& _dmatcher ) :
|
||||||
|
name(_name), dmatcher(_dmatcher)
|
||||||
|
{}
|
||||||
|
protected:
|
||||||
|
virtual void run(int);
|
||||||
|
|
||||||
|
void knnMatchTest( const Mat& query, const Mat& train );
|
||||||
|
|
||||||
|
private:
|
||||||
|
string name;
|
||||||
|
Ptr<DescriptorMatcher> dmatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CV_DescriptorMatcherLowKeypointTest::knnMatchTest( const Mat& query, const Mat& train )
|
||||||
|
{
|
||||||
|
const int knn = 6;
|
||||||
|
const int queryDescCount = query.rows;
|
||||||
|
vector<vector<DMatch> > matches;
|
||||||
|
|
||||||
|
// three train images, the third one with only one keypoint
|
||||||
|
dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
|
||||||
|
dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows-1)) );
|
||||||
|
dmatcher->add( vector<Mat>(1,train.rowRange(train.rows-1, train.rows)) );
|
||||||
|
const int trainImgCount = (int)dmatcher->getTrainDescriptors().size();
|
||||||
|
|
||||||
|
dmatcher->knnMatch( query, matches, knn, std::vector<Mat>(), true );
|
||||||
|
|
||||||
|
if( matches.empty() )
|
||||||
|
{
|
||||||
|
ts->printf(cvtest::TS::LOG, "No matches while testing knnMatch() function (3).\n");
|
||||||
|
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int badImgIdxCount = 0, badQueryIdxCount = 0, badTrainIdxCount = 0;
|
||||||
|
for( size_t i = 0; i < matches.size(); i++ )
|
||||||
|
{
|
||||||
|
for( size_t j = 0; j < matches[i].size(); j++ )
|
||||||
|
{
|
||||||
|
const DMatch& match = matches[i][j];
|
||||||
|
if( match.imgIdx < 0 || match.imgIdx >= trainImgCount )
|
||||||
|
{
|
||||||
|
++badImgIdxCount;
|
||||||
|
}
|
||||||
|
if( match.queryIdx < 0 || match.queryIdx >= queryDescCount )
|
||||||
|
{
|
||||||
|
++badQueryIdxCount;
|
||||||
|
}
|
||||||
|
if( match.trainIdx < 0 )
|
||||||
|
{
|
||||||
|
++badTrainIdxCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( badImgIdxCount > 0 || badQueryIdxCount > 0 || badTrainIdxCount > 0 )
|
||||||
|
{
|
||||||
|
ts->printf( cvtest::TS::LOG, "%d/%d/%d - wrong image/query/train indices while testing knnMatch() function (3).\n",
|
||||||
|
badImgIdxCount, badQueryIdxCount, badTrainIdxCount );
|
||||||
|
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CV_DescriptorMatcherLowKeypointTest::run( int )
|
||||||
|
{
|
||||||
|
Mat query, train;
|
||||||
|
CV_DescriptorMatcherTest::generateData( query, train );
|
||||||
|
|
||||||
|
knnMatchTest( query, train );
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* Tests registrations *
|
* Tests registrations *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
@ -541,3 +618,15 @@ TEST( Features2d_DescriptorMatcher_FlannBased, regression )
|
|||||||
CV_DescriptorMatcherTest test( "descriptor-matcher-flann-based", Algorithm::create<DescriptorMatcher>("DescriptorMatcher.FlannBasedMatcher"), 0.04f );
|
CV_DescriptorMatcherTest test( "descriptor-matcher-flann-based", Algorithm::create<DescriptorMatcher>("DescriptorMatcher.FlannBasedMatcher"), 0.04f );
|
||||||
test.safe_run();
|
test.safe_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST( Features2d_DescriptorMatcher_LowKeypoint_BruteForce, regression )
|
||||||
|
{
|
||||||
|
CV_DescriptorMatcherLowKeypointTest test( "descriptor-matcher-low-keypoint-brute-force", Algorithm::create<DescriptorMatcher>("DescriptorMatcher.BFMatcher") );
|
||||||
|
test.safe_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Features2d_DescriptorMatcher_LowKeypoint_FlannBased, regression)
|
||||||
|
{
|
||||||
|
CV_DescriptorMatcherLowKeypointTest test( "descriptor-matcher-low-keypoint-flann-based", Algorithm::create<DescriptorMatcher>("DescriptorMatcher.FlannBasedMatcher") );
|
||||||
|
test.safe_run();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user