modified features2d interface; added algorithmic test for DescriptorMatcher; added sample on matching to many images
This commit is contained in:
parent
0d3809d0b1
commit
69e329c9fd
File diff suppressed because it is too large
Load Diff
@ -108,11 +108,11 @@ void BOWImgDescriptorExtractor::setVocabulary( const Mat& _vocabulary )
|
||||
{
|
||||
dmatcher->clear();
|
||||
vocabulary = _vocabulary;
|
||||
dmatcher->add( vocabulary );
|
||||
dmatcher->add( vector<Mat>(1, vocabulary) );
|
||||
}
|
||||
|
||||
void BOWImgDescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& imgDescriptor,
|
||||
vector<vector<int> >* pointIdxsOfClusters ) const
|
||||
vector<vector<int> >* pointIdxsOfClusters )
|
||||
{
|
||||
imgDescriptor.release();
|
||||
|
||||
@ -140,8 +140,8 @@ void BOWImgDescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& key
|
||||
float *dptr = (float*)imgDescriptor.data;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
int queryIdx = matches[i].indexQuery;
|
||||
int trainIdx = matches[i].indexTrain; // cluster index
|
||||
int queryIdx = matches[i].queryIdx;
|
||||
int trainIdx = matches[i].trainIdx; // cluster index
|
||||
CV_Assert( queryIdx == (int)i );
|
||||
|
||||
dptr[trainIdx] = dptr[trainIdx] + 1.f;
|
||||
|
@ -67,6 +67,13 @@ struct RoiPredicate
|
||||
float minX, minY, maxX, maxY;
|
||||
};
|
||||
|
||||
void DescriptorExtractor::compute( const vector<Mat>& imageCollection, vector<vector<KeyPoint> >& pointCollection, vector<Mat>& descCollection ) const
|
||||
{
|
||||
descCollection.resize( imageCollection.size() );
|
||||
for( size_t i = 0; i < imageCollection.size(); i++ )
|
||||
compute( imageCollection[i], pointCollection[i], descCollection[i] );
|
||||
}
|
||||
|
||||
void DescriptorExtractor::removeBorderKeypoints( vector<KeyPoint>& keypoints,
|
||||
Size imageSize, int borderPixels )
|
||||
{
|
||||
|
@ -61,6 +61,13 @@ struct MaskPredicate
|
||||
const Mat& mask;
|
||||
};
|
||||
|
||||
void FeatureDetector::detect(const vector<Mat>& imageCollection, vector<vector<KeyPoint> >& pointCollection, const vector<Mat>& masks ) const
|
||||
{
|
||||
pointCollection.resize( imageCollection.size() );
|
||||
for( size_t i = 0; i < imageCollection.size(); i++ )
|
||||
detect( imageCollection[i], pointCollection[i], masks.empty() ? Mat() : masks[i] );
|
||||
}
|
||||
|
||||
void FeatureDetector::removeInvalidPoints( const Mat& mask, vector<KeyPoint>& keypoints )
|
||||
{
|
||||
if( mask.empty() )
|
||||
@ -88,7 +95,7 @@ void FastFeatureDetector::write (FileStorage& fs) const
|
||||
fs << "nonmaxSuppression" << nonmaxSuppression;
|
||||
}
|
||||
|
||||
void FastFeatureDetector::detectImpl( const Mat& image, const Mat& mask, vector<KeyPoint>& keypoints) const
|
||||
void FastFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
Mat grayImage = image;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -126,8 +133,7 @@ void GoodFeaturesToTrackDetector::write (FileStorage& fs) const
|
||||
fs << "k" << k;
|
||||
}
|
||||
|
||||
void GoodFeaturesToTrackDetector::detectImpl( const Mat& image, const Mat& mask,
|
||||
vector<KeyPoint>& keypoints ) const
|
||||
void GoodFeaturesToTrackDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const
|
||||
{
|
||||
Mat grayImage = image;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -192,7 +198,7 @@ void MserFeatureDetector::write (FileStorage& fs) const
|
||||
}
|
||||
|
||||
|
||||
void MserFeatureDetector::detectImpl( const Mat& image, const Mat& mask, vector<KeyPoint>& keypoints ) const
|
||||
void MserFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
vector<vector<Point> > msers;
|
||||
|
||||
@ -246,7 +252,7 @@ void StarFeatureDetector::write (FileStorage& fs) const
|
||||
fs << "suppressNonmaxSize" << star.suppressNonmaxSize;
|
||||
}
|
||||
|
||||
void StarFeatureDetector::detectImpl( const Mat& image, const Mat& mask, vector<KeyPoint>& keypoints) const
|
||||
void StarFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
Mat grayImage = image;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -291,8 +297,7 @@ void SiftFeatureDetector::write (FileStorage& fs) const
|
||||
}
|
||||
|
||||
|
||||
void SiftFeatureDetector::detectImpl( const Mat& image, const Mat& mask,
|
||||
vector<KeyPoint>& keypoints) const
|
||||
void SiftFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
Mat grayImage = image;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -325,8 +330,7 @@ void SurfFeatureDetector::write (FileStorage& fs) const
|
||||
fs << "octaveLayers" << surf.nOctaveLayers;
|
||||
}
|
||||
|
||||
void SurfFeatureDetector::detectImpl( const Mat& image, const Mat& mask,
|
||||
vector<KeyPoint>& keypoints) const
|
||||
void SurfFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
Mat grayImage = image;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -337,7 +341,7 @@ void SurfFeatureDetector::detectImpl( const Mat& image, const Mat& mask,
|
||||
/*
|
||||
* DenseFeatureDetector
|
||||
*/
|
||||
void DenseFeatureDetector::detectImpl( const Mat& image, const Mat& mask, vector<KeyPoint>& keypoints ) const
|
||||
void DenseFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
keypoints.clear();
|
||||
|
||||
@ -388,8 +392,7 @@ void keepStrongest( int N, vector<KeyPoint>& keypoints )
|
||||
}
|
||||
}
|
||||
|
||||
void GridAdaptedFeatureDetector::detectImpl( const Mat &image, const Mat &mask,
|
||||
vector<KeyPoint> &keypoints ) const
|
||||
void GridAdaptedFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
keypoints.clear();
|
||||
keypoints.reserve(maxTotalKeypoints);
|
||||
@ -428,7 +431,7 @@ PyramidAdaptedFeatureDetector::PyramidAdaptedFeatureDetector( const Ptr<FeatureD
|
||||
: detector(_detector), levels(_levels)
|
||||
{}
|
||||
|
||||
void PyramidAdaptedFeatureDetector::detectImpl( const Mat& image, const Mat& mask, vector<KeyPoint>& keypoints ) const
|
||||
void PyramidAdaptedFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
Mat src = image;
|
||||
for( int l = 0, multiplier = 1; l <= levels; ++l, multiplier *= 2 )
|
||||
|
@ -165,33 +165,6 @@ static inline void _drawMatch( Mat& outImg, Mat& outImg1, Mat& outImg2 ,
|
||||
color, 1, CV_AA, draw_shift_bits );
|
||||
}
|
||||
|
||||
void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
|
||||
const Mat& img2,const vector<KeyPoint>& keypoints2,
|
||||
const vector<int>& matches1to2, Mat& outImg,
|
||||
const Scalar& matchColor, const Scalar& singlePointColor,
|
||||
const vector<char>& matchesMask, int flags )
|
||||
{
|
||||
if( matches1to2.size() != keypoints1.size() )
|
||||
CV_Error( CV_StsBadSize, "matches1to2 must have the same size as keypoints1" );
|
||||
if( !matchesMask.empty() && matchesMask.size() != matches1to2.size() )
|
||||
CV_Error( CV_StsBadSize, "matchesMask must have the same size as matches1to2" );
|
||||
|
||||
Mat outImg1, outImg2;
|
||||
_prepareImgAndDrawKeypoints( img1, keypoints1, img2, keypoints2,
|
||||
outImg, outImg1, outImg2, singlePointColor, flags );
|
||||
|
||||
// draw matches
|
||||
for( size_t i1 = 0; i1 < keypoints1.size(); i1++ )
|
||||
{
|
||||
int i2 = matches1to2[i1];
|
||||
if( (matchesMask.empty() || matchesMask[i1] ) && i2 >= 0 )
|
||||
{
|
||||
const KeyPoint &kp1 = keypoints1[i1], &kp2 = keypoints2[i2];
|
||||
_drawMatch( outImg, outImg1, outImg2, kp1, kp2, matchColor, flags );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
|
||||
const Mat& img2, const vector<KeyPoint>& keypoints2,
|
||||
const vector<DMatch>& matches1to2, Mat& outImg,
|
||||
@ -208,8 +181,8 @@ void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
|
||||
// draw matches
|
||||
for( size_t m = 0; m < matches1to2.size(); m++ )
|
||||
{
|
||||
int i1 = matches1to2[m].indexQuery;
|
||||
int i2 = matches1to2[m].indexTrain;
|
||||
int i1 = matches1to2[m].queryIdx;
|
||||
int i2 = matches1to2[m].trainIdx;
|
||||
if( matchesMask.empty() || matchesMask[m] )
|
||||
{
|
||||
const KeyPoint &kp1 = keypoints1[i1], &kp2 = keypoints2[i2];
|
||||
@ -236,8 +209,8 @@ void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
|
||||
{
|
||||
for( size_t j = 0; j < matches1to2[i].size(); j++ )
|
||||
{
|
||||
int i1 = matches1to2[i][j].indexQuery;
|
||||
int i2 = matches1to2[i][j].indexTrain;
|
||||
int i1 = matches1to2[i][j].queryIdx;
|
||||
int i2 = matches1to2[i][j].trainIdx;
|
||||
if( matchesMask.empty() || matchesMask[i][j] )
|
||||
{
|
||||
const KeyPoint &kp1 = keypoints1[i1], &kp2 = keypoints2[i2];
|
||||
|
@ -517,10 +517,10 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
|
||||
vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2,
|
||||
vector<vector<DMatch> >* _matches1to2, vector<vector<uchar> >* _correctMatches1to2Mask,
|
||||
vector<Point2f>& recallPrecisionCurve,
|
||||
const Ptr<GenericDescriptorMatch>& _dmatch )
|
||||
const Ptr<GenericDescriptorMatcher>& _dmatcher )
|
||||
{
|
||||
Ptr<GenericDescriptorMatch> dmatch = _dmatch;
|
||||
dmatch->clear();
|
||||
Ptr<GenericDescriptorMatcher> dmatcher = _dmatcher;
|
||||
dmatcher->clear();
|
||||
|
||||
vector<vector<DMatch> > *matches1to2, buf1;
|
||||
matches1to2 = _matches1to2 != 0 ? _matches1to2 : &buf1;
|
||||
@ -531,7 +531,7 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
|
||||
if( keypoints1.empty() )
|
||||
CV_Error( CV_StsBadArg, "keypoints1 must be no empty" );
|
||||
|
||||
if( matches1to2->empty() && dmatch.empty() )
|
||||
if( matches1to2->empty() && dmatcher.empty() )
|
||||
CV_Error( CV_StsBadArg, "dmatch must be no empty when matches1to2 is empty" );
|
||||
|
||||
bool computeKeypoints2ByPrj = keypoints2.empty();
|
||||
@ -543,10 +543,8 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
|
||||
|
||||
if( matches1to2->empty() || computeKeypoints2ByPrj )
|
||||
{
|
||||
dmatch->clear();
|
||||
dmatch->add( img2, keypoints2 );
|
||||
// TODO: use more sophisticated strategy to choose threshold
|
||||
dmatch->match( img1, keypoints1, *matches1to2, std::numeric_limits<float>::max() );
|
||||
dmatcher->clear();
|
||||
dmatcher->radiusMatch( img1, keypoints1, img2, keypoints2, *matches1to2, std::numeric_limits<float>::max() );
|
||||
}
|
||||
float repeatability;
|
||||
int correspCount;
|
||||
@ -559,8 +557,8 @@ void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, con
|
||||
(*correctMatches1to2Mask)[i].resize((*matches1to2)[i].size());
|
||||
for( size_t j = 0;j < (*matches1to2)[i].size(); j++ )
|
||||
{
|
||||
int indexQuery = (*matches1to2)[i][j].indexQuery;
|
||||
int indexTrain = (*matches1to2)[i][j].indexTrain;
|
||||
int indexQuery = (*matches1to2)[i][j].queryIdx;
|
||||
int indexTrain = (*matches1to2)[i][j].trainIdx;
|
||||
(*correctMatches1to2Mask)[i][j] = thresholdedOverlapMask.at<uchar>( indexQuery, indexTrain );
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -109,19 +109,17 @@ void testCalonderClassifier( const string& classifierFilename, const string& img
|
||||
|
||||
// Match descriptors
|
||||
BruteForceMatcher<L1<float> > matcher;
|
||||
matcher.add( descriptors2 );
|
||||
vector<int> matches;
|
||||
matcher.match( descriptors1, matches );
|
||||
vector<DMatch> matches;
|
||||
matcher.match( descriptors1, descriptors2, matches );
|
||||
|
||||
// Prepare inlier mask
|
||||
vector<char> matchesMask( matches.size(), 0 );
|
||||
vector<Point2f> points1; KeyPoint::convert( keypoints1, points1 );
|
||||
vector<Point2f> points2; KeyPoint::convert( keypoints2, points2 );
|
||||
Mat points1t; perspectiveTransform(Mat(points1), points1t, H12);
|
||||
vector<int>::const_iterator mit = matches.begin();
|
||||
for( size_t mi = 0; mi < matches.size(); mi++ )
|
||||
{
|
||||
if( norm(points2[matches[mi]] - points1t.at<Point2f>(mi,0)) < 4 ) // inlier
|
||||
if( norm(points2[matches[mi].trainIdx] - points1t.at<Point2f>(mi,0)) < 4 ) // inlier
|
||||
matchesMask[mi] = 1;
|
||||
}
|
||||
|
||||
|
@ -948,7 +948,7 @@ void VocData::calcClassifierConfMatRow(const string& obj_class, const vector<Obd
|
||||
|
||||
/* prepare variables related to calculating recall if using the recall threshold */
|
||||
int retrieved_hits = 0;
|
||||
int total_relevant;
|
||||
int total_relevant = 0;
|
||||
if (cond == CV_VOC_CCOND_RECALL)
|
||||
{
|
||||
vector<char> ground_truth;
|
||||
@ -2200,7 +2200,7 @@ bool writeBowImageDescriptor( const string& file, const Mat& bowImageDescriptor
|
||||
|
||||
// Load in the bag of words vectors for a set of images, from file if possible
|
||||
void calculateImageDescriptors( const vector<ObdImage>& images, vector<Mat>& imageDescriptors,
|
||||
const Ptr<BOWImgDescriptorExtractor>& bowExtractor, const Ptr<FeatureDetector>& fdetector,
|
||||
Ptr<BOWImgDescriptorExtractor>& bowExtractor, const Ptr<FeatureDetector>& fdetector,
|
||||
const string& resPath )
|
||||
{
|
||||
CV_Assert( !bowExtractor->getVocabulary().empty() );
|
||||
@ -2343,7 +2343,7 @@ void setSVMTrainAutoParams( CvParamGrid& c_grid, CvParamGrid& gamma_grid,
|
||||
}
|
||||
|
||||
void trainSVMClassifier( CvSVM& svm, const SVMTrainParamsExt& svmParamsExt, const string& objClassName, VocData& vocData,
|
||||
const Ptr<BOWImgDescriptorExtractor>& bowExtractor, const Ptr<FeatureDetector>& fdetector,
|
||||
Ptr<BOWImgDescriptorExtractor>& bowExtractor, const Ptr<FeatureDetector>& fdetector,
|
||||
const string& resPath )
|
||||
{
|
||||
/* first check if a previously trained svm for the current class has been saved to file */
|
||||
@ -2418,7 +2418,7 @@ void trainSVMClassifier( CvSVM& svm, const SVMTrainParamsExt& svmParamsExt, cons
|
||||
}
|
||||
|
||||
void computeConfidences( CvSVM& svm, const string& objClassName, VocData& vocData,
|
||||
const Ptr<BOWImgDescriptorExtractor>& bowExtractor, const Ptr<FeatureDetector>& fdetector,
|
||||
Ptr<BOWImgDescriptorExtractor>& bowExtractor, const Ptr<FeatureDetector>& fdetector,
|
||||
const string& resPath )
|
||||
{
|
||||
cout << "*** CALCULATING CONFIDENCES FOR CLASS " << objClassName << " ***" << endl;
|
||||
@ -2437,7 +2437,7 @@ void computeConfidences( CvSVM& svm, const string& objClassName, VocData& vocDat
|
||||
// Use the bag of words vectors to calculate classifier output for each image in test set
|
||||
cout << "CALCULATING CONFIDENCE SCORES FOR CLASS " << objClassName << "..." << endl;
|
||||
vector<float> confidences( images.size() );
|
||||
float signMul;
|
||||
float signMul = 1.f;
|
||||
for( size_t imageIdx = 0; imageIdx < images.size(); imageIdx++ )
|
||||
{
|
||||
if( imageIdx == 0 )
|
||||
|
@ -72,7 +72,7 @@ void doIteration( const Mat& img1, Mat& img2, bool isWarpPerspective,
|
||||
{
|
||||
cout << "< Evaluate descriptor match..." << endl;
|
||||
vector<Point2f> curve;
|
||||
Ptr<GenericDescriptorMatch> gdm = new VectorDescriptorMatch( descriptorExtractor, descriptorMatcher );
|
||||
Ptr<GenericDescriptorMatcher> gdm = new VectorDescriptorMatcher( descriptorExtractor, descriptorMatcher );
|
||||
evaluateGenericDescriptorMatcher( img1, img2, H12, keypoints1, keypoints2, 0, 0, curve, gdm );
|
||||
for( float l_p = 0; l_p < 1 - FLT_EPSILON; l_p+=0.1 )
|
||||
cout << "1-precision = " << l_p << "; recall = " << getRecall( curve, l_p ) << endl;
|
||||
@ -81,7 +81,7 @@ void doIteration( const Mat& img1, Mat& img2, bool isWarpPerspective,
|
||||
|
||||
vector<int> trainIdxs( matches.size() );
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
trainIdxs[i] = matches[i].indexTrain;
|
||||
trainIdxs[i] = matches[i].trainIdx;
|
||||
|
||||
if( !isWarpPerspective && ransacReprojThreshold >= 0 )
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
using namespace cv;
|
||||
|
||||
IplImage* DrawCorrespondences(IplImage* img1, const vector<KeyPoint>& features1, IplImage* img2,
|
||||
const vector<KeyPoint>& features2, const vector<int>& desc_idx);
|
||||
const vector<KeyPoint>& features2, const vector<DMatch>& desc_idx);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@ -24,7 +24,7 @@ int main(int argc, char** argv)
|
||||
std::string alg_name = std::string(argv[3]);
|
||||
std::string params_filename = std::string(argv[4]);
|
||||
|
||||
GenericDescriptorMatch *descriptorMatcher = createGenericDescriptorMatcher(alg_name, params_filename);
|
||||
Ptr<GenericDescriptorMatcher> descriptorMatcher = createGenericDescriptorMatcher(alg_name, params_filename);
|
||||
if( descriptorMatcher == 0 )
|
||||
{
|
||||
printf ("Cannot create descriptor\n");
|
||||
@ -50,10 +50,8 @@ int main(int argc, char** argv)
|
||||
|
||||
printf("Finding nearest neighbors... \n");
|
||||
// find NN for each of keypoints2 in keypoints1
|
||||
descriptorMatcher->add( img1, keypoints1 );
|
||||
vector<int> matches2to1;
|
||||
matches2to1.resize(keypoints2.size());
|
||||
descriptorMatcher->match( img2, keypoints2, matches2to1 );
|
||||
vector<DMatch> matches2to1;
|
||||
descriptorMatcher->match( img2, keypoints2, img1, keypoints1, matches2to1 );
|
||||
printf("Done\n");
|
||||
|
||||
IplImage* img_corr = DrawCorrespondences(img1, keypoints1, img2, keypoints2, matches2to1);
|
||||
@ -65,11 +63,10 @@ int main(int argc, char** argv)
|
||||
cvReleaseImage(&img1);
|
||||
cvReleaseImage(&img2);
|
||||
cvReleaseImage(&img_corr);
|
||||
delete descriptorMatcher;
|
||||
}
|
||||
|
||||
IplImage* DrawCorrespondences(IplImage* img1, const vector<KeyPoint>& features1, IplImage* img2,
|
||||
const vector<KeyPoint>& features2, const vector<int>& desc_idx)
|
||||
const vector<KeyPoint>& features2, const vector<DMatch>& desc_idx)
|
||||
{
|
||||
IplImage* img_corr = cvCreateImage(cvSize(img1->width + img2->width, MAX(img1->height, img2->height)),
|
||||
IPL_DEPTH_8U, 3);
|
||||
@ -88,7 +85,7 @@ IplImage* DrawCorrespondences(IplImage* img1, const vector<KeyPoint>& features1,
|
||||
{
|
||||
CvPoint pt = cvPoint(cvRound(features2[i].pt.x + img1->width), cvRound(features2[i].pt.y));
|
||||
cvCircle(img_corr, pt, 3, CV_RGB(255, 0, 0));
|
||||
cvLine(img_corr, features1[desc_idx[i]].pt, pt, CV_RGB(0, 255, 0));
|
||||
cvLine(img_corr, features1[desc_idx[i].trainIdx].pt, pt, CV_RGB(0, 255, 0));
|
||||
}
|
||||
|
||||
return img_corr;
|
||||
|
@ -35,9 +35,8 @@ int main(int argc, char** argv)
|
||||
|
||||
// matching descriptors
|
||||
BruteForceMatcher<L2<float> > matcher;
|
||||
vector<int> matches;
|
||||
matcher.add(descriptors2);
|
||||
matcher.match(descriptors1, matches);
|
||||
vector<DMatch> matches;
|
||||
matcher.match(descriptors1, descriptors2, matches);
|
||||
|
||||
// drawing the results
|
||||
namedWindow("matches", 1);
|
||||
|
134
samples/cpp/matching_to_many_images.cpp
Normal file
134
samples/cpp/matching_to_many_images.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include <highgui.h>
|
||||
#include "opencv2/features2d/features2d.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
const char dlmtr = '/';
|
||||
|
||||
void maskMatchesByTrainImgIdx( const vector<DMatch>& matches, int trainImgIdx, vector<char>& mask );
|
||||
void readTrainFilenames( const string& filename, string& dirName, vector<string>& trainFilenames );
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Mat queryImg;
|
||||
vector<KeyPoint> queryPoints;
|
||||
Mat queryDescs;
|
||||
|
||||
vector<Mat> trainImgCollection;
|
||||
vector<vector<KeyPoint> > trainPointCollection;
|
||||
vector<Mat> trainDescCollection;
|
||||
|
||||
vector<DMatch> matches;
|
||||
|
||||
if( argc != 7 )
|
||||
{
|
||||
cout << "Format:" << endl;
|
||||
cout << argv[0] << "[detectorType] [descriptorType] [matcherType] [queryImage] [fileWithTrainImages] [dirToSaveResImages]" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cout << "< 1.) Creating feature detector, descriptor extractor and descriptor matcher ..." << endl;
|
||||
Ptr<FeatureDetector> detector = createFeatureDetector( argv[1] );
|
||||
Ptr<DescriptorExtractor> descriptorExtractor = createDescriptorExtractor( argv[2] );
|
||||
Ptr<DescriptorMatcher> descriptorMatcher = createDescriptorMatcher( argv[3] );
|
||||
cout << ">" << endl;
|
||||
if( detector.empty() || descriptorExtractor.empty() || descriptorMatcher.empty() )
|
||||
{
|
||||
cout << "Can not create feature detector or descriptor exstractor or descriptor matcher of given types." << endl << ">" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cout << "< 2.) Reading the images..." << endl;
|
||||
queryImg = imread( argv[4], CV_LOAD_IMAGE_GRAYSCALE);
|
||||
if( queryImg.empty() )
|
||||
{
|
||||
cout << "Query image can not be read." << endl << ">" << endl;
|
||||
return -1;
|
||||
}
|
||||
string trainDirName;
|
||||
vector<string> trainFilenames;
|
||||
vector<int> usedTrainImgIdxs;
|
||||
readTrainFilenames( argv[5], trainDirName, trainFilenames );
|
||||
if( trainFilenames.empty() )
|
||||
{
|
||||
cout << "Train image filenames can not be read." << endl << ">" << endl;
|
||||
return -1;
|
||||
}
|
||||
for( size_t i = 0; i < trainFilenames.size(); i++ )
|
||||
{
|
||||
Mat img = imread( trainDirName + trainFilenames[i], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
if( img.empty() ) cout << "Train image " << trainDirName + trainFilenames[i] << " can not be read." << endl;
|
||||
trainImgCollection.push_back( img );
|
||||
usedTrainImgIdxs.push_back( i );
|
||||
}
|
||||
if( trainImgCollection.empty() )
|
||||
{
|
||||
cout << "All train images can not be read." << endl << ">" << endl;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
cout << trainImgCollection.size() << " train images were read." << endl;
|
||||
cout << ">" << endl;
|
||||
|
||||
cout << endl << "< 3.) Extracting keypoints from images..." << endl;
|
||||
detector->detect( queryImg, queryPoints );
|
||||
detector->detect( trainImgCollection, trainPointCollection );
|
||||
cout << ">" << endl;
|
||||
|
||||
cout << "< 4.) Computing descriptors for keypoints..." << endl;
|
||||
descriptorExtractor->compute( queryImg, queryPoints, queryDescs );
|
||||
descriptorExtractor->compute( trainImgCollection, trainPointCollection, trainDescCollection );
|
||||
cout << ">" << endl;
|
||||
|
||||
cout << "< 5.) Set train descriptors collection in the matcher and match query descriptors to them..." << endl;
|
||||
descriptorMatcher->add( trainDescCollection );
|
||||
descriptorMatcher->match( queryDescs, matches );
|
||||
CV_Assert( queryPoints.size() == matches.size() );
|
||||
cout << ">" << endl;
|
||||
|
||||
Mat drawImg;
|
||||
vector<char> mask;
|
||||
for( size_t i = 0; i < trainImgCollection.size(); i++ )
|
||||
{
|
||||
maskMatchesByTrainImgIdx( matches, i, mask );
|
||||
drawMatches( queryImg, queryPoints, trainImgCollection[i], trainPointCollection[i],
|
||||
matches, drawImg, Scalar::all(-1), Scalar::all(-1), mask );
|
||||
|
||||
imwrite( string(argv[6]) + "/res_" + trainFilenames[usedTrainImgIdxs[i]] + ".png", drawImg );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void maskMatchesByTrainImgIdx( const vector<DMatch>& matches, int trainImgIdx, vector<char>& mask )
|
||||
{
|
||||
mask.resize( matches.size() );
|
||||
fill( mask.begin(), mask.end(), 0 );
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( matches[i].imgIdx == trainImgIdx )
|
||||
mask[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void readTrainFilenames( const string& filename, string& dirName, vector<string>& trainFilenames )
|
||||
{
|
||||
trainFilenames.clear();
|
||||
|
||||
ifstream file( filename.c_str() );
|
||||
if ( !file.is_open() )
|
||||
return;
|
||||
|
||||
size_t pos = filename.rfind(dlmtr);
|
||||
dirName = pos == string::npos ? "" : filename.substr(0, pos) + dlmtr;
|
||||
while( !file.eof() )
|
||||
{
|
||||
string str; getline( file, str );
|
||||
if( str.empty() ) break;
|
||||
trainFilenames.push_back(str);
|
||||
}
|
||||
file.close();
|
||||
}
|
@ -1028,7 +1028,7 @@ void DescriptorQualityTest::runDatasetTest (const vector<Mat> &imgs, const vecto
|
||||
return;
|
||||
}
|
||||
|
||||
Ptr<GenericDescriptorMatch> descMatch = commRunParams[di].isActiveParams ? specificDescMatcher : defaultDescMatcher;
|
||||
Ptr<GenericDescriptorMatcher> descMatch = commRunParams[di].isActiveParams ? specificDescMatcher : defaultDescMatcher;
|
||||
calcQuality[di].resize(TEST_CASE_COUNT);
|
||||
|
||||
vector<KeyPoint> keypoints1;
|
||||
@ -1165,7 +1165,7 @@ void OneWayDescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int da
|
||||
//DetectorQualityTest siftDetectorQuality = DetectorQualityTest( "SIFT", "quality-detector-sift" );
|
||||
//DetectorQualityTest surfDetectorQuality = DetectorQualityTest( "SURF", "quality-detector-surf" );
|
||||
|
||||
// Detectors
|
||||
// Descriptors
|
||||
//DescriptorQualityTest siftDescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift", "BruteForce" );
|
||||
//DescriptorQualityTest surfDescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf", "BruteForce" );
|
||||
//DescriptorQualityTest fernDescriptorQualityTest( "FERN", "quality-descriptor-fern");
|
||||
@ -1173,7 +1173,7 @@ void OneWayDescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int da
|
||||
|
||||
|
||||
|
||||
// Don't run them because of bug in OneWayDescriptorBase many to many matching. TODO: fix this bug.
|
||||
// Don't run it because of bug in OneWayDescriptorBase many to many matching. TODO: fix this bug.
|
||||
//OneWayDescriptorQualityTest oneWayDescriptorQuality;
|
||||
|
||||
// Don't run them (will validate and save results as "quality-descriptor-sift" and "quality-descriptor-surf" test data).
|
||||
|
@ -166,14 +166,6 @@ protected:
|
||||
Ptr<FeatureDetector> fdetector;
|
||||
};
|
||||
|
||||
CV_FeatureDetectorTest fastTest( "detector-fast", createFeatureDetector("FAST") );
|
||||
CV_FeatureDetectorTest gfttTest( "detector-gftt", createFeatureDetector("GFTT") );
|
||||
CV_FeatureDetectorTest harrisTest( "detector-harris", createFeatureDetector("HARRIS") );
|
||||
CV_FeatureDetectorTest mserTest( "detector-mser", createFeatureDetector("MSER") );
|
||||
CV_FeatureDetectorTest siftTest( "detector-sift", createFeatureDetector("SIFT") );
|
||||
CV_FeatureDetectorTest starTest( "detector-star", createFeatureDetector("STAR") );
|
||||
CV_FeatureDetectorTest surfTest( "detector-surf", createFeatureDetector("SURF") );
|
||||
|
||||
/****************************************************************************************\
|
||||
* Regression tests for descriptor extractors. *
|
||||
\****************************************************************************************/
|
||||
@ -320,6 +312,413 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/****************************************************************************************\
|
||||
* Algorithmic tests for descriptor matchers *
|
||||
\****************************************************************************************/
|
||||
class CV_DescriptorMatcherTest : public CvTest
|
||||
{
|
||||
public:
|
||||
CV_DescriptorMatcherTest( const char* testName, const Ptr<DescriptorMatcher>& _dmatcher, float _badPart ) :
|
||||
CvTest( testName, "cv::DescritorMatcher::[,knn,radius]match()"), badPart(_badPart), dmatcher(_dmatcher)
|
||||
{ CV_Assert( queryDescCount % 2 == 0 ); // because we split train data in same cases in two
|
||||
CV_Assert( countFactor == 4); }
|
||||
protected:
|
||||
static const int dim = 500;
|
||||
static const int queryDescCount = 300;
|
||||
static const int countFactor = 4;
|
||||
const float badPart;
|
||||
|
||||
virtual void run( int );
|
||||
void generateData( Mat& query, Mat& train );
|
||||
|
||||
int testMatch( const Mat& query, const Mat& train );
|
||||
int testKnnMatch( const Mat& query, const Mat& train );
|
||||
int testRadiusMatch( const Mat& query, const Mat& train );
|
||||
|
||||
Ptr<DescriptorMatcher> dmatcher;
|
||||
};
|
||||
|
||||
void CV_DescriptorMatcherTest::generateData( Mat& query, Mat& train )
|
||||
{
|
||||
RNG& rng = theRNG();
|
||||
|
||||
// Generate query descriptors randomly.
|
||||
// Descriptor vector elements are integer values.
|
||||
Mat buf( queryDescCount, dim, CV_32SC1 );
|
||||
rng.fill( buf, RNG::UNIFORM, Scalar::all(0), Scalar(3) );
|
||||
buf.convertTo( query, CV_32FC1 );
|
||||
|
||||
// Generate train decriptors as follows:
|
||||
// copy each query descriptor to train set countFactor times
|
||||
// and perturb some one element of the copied descriptors in
|
||||
// in ascending order. General boundaries of the perturbation
|
||||
// are (0.f, 1.f).
|
||||
train.create( query.rows*countFactor, query.cols, CV_32FC1 );
|
||||
float step = 1.f / countFactor;
|
||||
for( int qIdx = 0; qIdx < query.rows; qIdx++ )
|
||||
{
|
||||
Mat queryDescriptor = query.row(qIdx);
|
||||
for( int c = 0; c < countFactor; c++ )
|
||||
{
|
||||
int tIdx = qIdx * countFactor + c;
|
||||
Mat trainDescriptor = train.row(tIdx);
|
||||
queryDescriptor.copyTo( trainDescriptor );
|
||||
int elem = rng(dim);
|
||||
float diff = rng.uniform( step*c, step*(c+1) );
|
||||
trainDescriptor.at<float>(0, elem) += diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CV_DescriptorMatcherTest::testMatch( const Mat& query, const Mat& train )
|
||||
{
|
||||
dmatcher->clear();
|
||||
|
||||
// test const version of match()
|
||||
int res = CvTS::OK;
|
||||
{
|
||||
vector<DMatch> matches;
|
||||
dmatcher->match( query, train, matches );
|
||||
|
||||
int curRes = CvTS::OK;
|
||||
if( (int)matches.size() != queryDescCount )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf(CvTS::LOG, "Incorrect matches count while test match() function (1)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
DMatch match = matches[i];
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor) || (match.imgIdx != 0) )
|
||||
badCount++;
|
||||
}
|
||||
if( (float)badCount > (float)queryDescCount*badPart )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf( CvTS::LOG, "%f - too large bad matches part while test match() function (1)\n",
|
||||
(float)badCount/(float)queryDescCount );
|
||||
}
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
}
|
||||
|
||||
// test version of match() with add()
|
||||
{
|
||||
vector<DMatch> matches;
|
||||
// make add() twice to test such case
|
||||
dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
|
||||
dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
|
||||
// prepare masks (make first nearest match illegal)
|
||||
vector<Mat> masks(2);
|
||||
for(int mi = 0; mi < 2; mi++ )
|
||||
{
|
||||
masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
|
||||
for( int di = 0; di < queryDescCount/2; di++ )
|
||||
masks[mi].col(di*countFactor).setTo(Scalar::all(0));
|
||||
}
|
||||
|
||||
dmatcher->match( query, matches, masks );
|
||||
|
||||
int curRes = CvTS::OK;
|
||||
if( (int)matches.size() != queryDescCount )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf(CvTS::LOG, "Incorrect matches count while test match() function (2)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
DMatch match = matches[i];
|
||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
||||
{
|
||||
if( i < queryDescCount/2 )
|
||||
{
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + shift) || (match.imgIdx != 0) )
|
||||
badCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + shift) || (match.imgIdx != 1) )
|
||||
badCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (float)badCount > (float)queryDescCount*badPart )
|
||||
{
|
||||
ts->printf( CvTS::LOG, "%f - too large bad matches part while test match() function (2)\n",
|
||||
(float)badCount/(float)queryDescCount );
|
||||
}
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int CV_DescriptorMatcherTest::testKnnMatch( const Mat& query, const Mat& train )
|
||||
{
|
||||
dmatcher->clear();
|
||||
|
||||
// test const version of knnMatch()
|
||||
int res = CvTS::OK;
|
||||
{
|
||||
const int knn = 3;
|
||||
|
||||
vector<vector<DMatch> > matches;
|
||||
dmatcher->knnMatch( query, train, matches, knn );
|
||||
|
||||
int curRes = CvTS::OK;
|
||||
if( (int)matches.size() != queryDescCount )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf(CvTS::LOG, "Incorrect matches count while test knnMatch() function (1)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int)matches[i].size() != knn )
|
||||
badCount++;
|
||||
else
|
||||
{
|
||||
int localBadCount = 0;
|
||||
for( int k = 0; k < knn; k++ )
|
||||
{
|
||||
DMatch match = matches[i][k];
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor+k) || (match.imgIdx != 0) )
|
||||
localBadCount++;
|
||||
}
|
||||
badCount += localBadCount > 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
if( (float)badCount > (float)queryDescCount*badPart )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf( CvTS::LOG, "%f - too large bad matches part while test knnMatch() function (1)\n",
|
||||
(float)badCount/(float)queryDescCount );
|
||||
}
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
}
|
||||
|
||||
// test version of knnMatch() with add()
|
||||
{
|
||||
const int knn = 2;
|
||||
vector<vector<DMatch> > matches;
|
||||
// make add() twice to test such case
|
||||
dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
|
||||
dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
|
||||
// prepare masks (make first nearest match illegal)
|
||||
vector<Mat> masks(2);
|
||||
for(int mi = 0; mi < 2; mi++ )
|
||||
{
|
||||
masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
|
||||
for( int di = 0; di < queryDescCount/2; di++ )
|
||||
masks[mi].col(di*countFactor).setTo(Scalar::all(0));
|
||||
}
|
||||
|
||||
dmatcher->knnMatch( query, matches, knn, masks );
|
||||
|
||||
int curRes = CvTS::OK;
|
||||
if( (int)matches.size() != queryDescCount )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf(CvTS::LOG, "Incorrect matches count while test knnMatch() function (2)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int)matches[i].size() != knn )
|
||||
badCount++;
|
||||
else
|
||||
{
|
||||
int localBadCount = 0;
|
||||
for( int k = 0; k < knn; k++ )
|
||||
{
|
||||
DMatch match = matches[i][k];
|
||||
{
|
||||
if( i < queryDescCount/2 )
|
||||
{
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + k + shift) ||
|
||||
(match.imgIdx != 0) )
|
||||
localBadCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + k + shift) ||
|
||||
(match.imgIdx != 1) )
|
||||
localBadCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
badCount += localBadCount > 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
if( (float)badCount > (float)queryDescCount*badPart )
|
||||
{
|
||||
ts->printf( CvTS::LOG, "%f - too large bad matches part while test knnMatch() function (2)\n",
|
||||
(float)badCount/(float)queryDescCount );
|
||||
}
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int CV_DescriptorMatcherTest::testRadiusMatch( const Mat& query, const Mat& train )
|
||||
{
|
||||
dmatcher->clear();
|
||||
// test const version of match()
|
||||
int res = CvTS::OK;
|
||||
{
|
||||
const float radius = 1.f/countFactor;
|
||||
vector<vector<DMatch> > matches;
|
||||
dmatcher->radiusMatch( query, train, matches, radius );
|
||||
|
||||
int curRes = CvTS::OK;
|
||||
if( (int)matches.size() != queryDescCount )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf(CvTS::LOG, "Incorrect matches count while test radiusMatch() function (1)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int)matches[i].size() != 1 )
|
||||
badCount++;
|
||||
else
|
||||
{
|
||||
DMatch match = matches[i][0];
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor) || (match.imgIdx != 0) )
|
||||
badCount++;
|
||||
}
|
||||
}
|
||||
if( (float)badCount > (float)queryDescCount*badPart )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf( CvTS::LOG, "%f - too large bad matches part while test radiusMatch() function (1)\n",
|
||||
(float)badCount/(float)queryDescCount );
|
||||
}
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
}
|
||||
|
||||
// test version of match() with add()
|
||||
{
|
||||
int n = 3;
|
||||
const float radius = 1.f/countFactor * n;
|
||||
vector<vector<DMatch> > matches;
|
||||
// make add() twice to test such case
|
||||
dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
|
||||
dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
|
||||
// prepare masks (make first nearest match illegal)
|
||||
vector<Mat> masks(2);
|
||||
for(int mi = 0; mi < 2; mi++ )
|
||||
{
|
||||
masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
|
||||
for( int di = 0; di < queryDescCount/2; di++ )
|
||||
masks[mi].col(di*countFactor).setTo(Scalar::all(0));
|
||||
}
|
||||
|
||||
dmatcher->radiusMatch( query, matches, radius, masks );
|
||||
|
||||
int curRes = CvTS::OK;
|
||||
if( (int)matches.size() != queryDescCount )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf(CvTS::LOG, "Incorrect matches count while test radiusMatch() function (1)\n");
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
|
||||
int badCount = 0;
|
||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
||||
int needMatchCount = dmatcher->supportMask() ? n-1 : n;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int)matches[i].size() != needMatchCount )
|
||||
badCount++;
|
||||
else
|
||||
{
|
||||
int localBadCount = 0;
|
||||
for( int k = 0; k < needMatchCount; k++ )
|
||||
{
|
||||
DMatch match = matches[i][k];
|
||||
{
|
||||
if( i < queryDescCount/2 )
|
||||
{
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + k + shift) ||
|
||||
(match.imgIdx != 0) )
|
||||
localBadCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + k + shift) ||
|
||||
(match.imgIdx != 1) )
|
||||
localBadCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
badCount += localBadCount > 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
if( (float)badCount > (float)queryDescCount*badPart )
|
||||
{
|
||||
curRes = CvTS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf( CvTS::LOG, "%f - too large bad matches part while test radiusMatch() function (2)\n",
|
||||
(float)badCount/(float)queryDescCount );
|
||||
}
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void CV_DescriptorMatcherTest::run( int )
|
||||
{
|
||||
Mat query, train;
|
||||
generateData( query, train );
|
||||
|
||||
int res = CvTS::OK, curRes;
|
||||
|
||||
curRes = testMatch( query, train );
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
|
||||
curRes = testKnnMatch( query, train );
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
|
||||
curRes = testRadiusMatch( query, train );
|
||||
res = curRes != CvTS::OK ? curRes : res;
|
||||
|
||||
ts->set_failed_test_info( res );
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* Tests registrations *
|
||||
\****************************************************************************************/
|
||||
|
||||
/*
|
||||
* Detectors
|
||||
*/
|
||||
CV_FeatureDetectorTest fastTest( "detector-fast", createFeatureDetector("FAST") );
|
||||
CV_FeatureDetectorTest gfttTest( "detector-gftt", createFeatureDetector("GFTT") );
|
||||
CV_FeatureDetectorTest harrisTest( "detector-harris", createFeatureDetector("HARRIS") );
|
||||
CV_FeatureDetectorTest mserTest( "detector-mser", createFeatureDetector("MSER") );
|
||||
CV_FeatureDetectorTest siftTest( "detector-sift", createFeatureDetector("SIFT") );
|
||||
CV_FeatureDetectorTest starTest( "detector-star", createFeatureDetector("STAR") );
|
||||
CV_FeatureDetectorTest surfTest( "detector-surf", createFeatureDetector("SURF") );
|
||||
|
||||
/*
|
||||
* Descriptors
|
||||
*/
|
||||
CV_DescriptorExtractorTest siftDescriptorTest( "descriptor-sift", 0.03f,
|
||||
createDescriptorExtractor("SIFT"), 8.06652f );
|
||||
CV_DescriptorExtractorTest surfDescriptorTest( "descriptor-surf", 0.035f,
|
||||
@ -337,3 +736,11 @@ CV_CalonderDescriptorExtractorTest<float> floatCalonderTest( "descriptor-calonde
|
||||
std::numeric_limits<float>::epsilon(),
|
||||
0.0221308f );
|
||||
#endif // CV_SSE2
|
||||
|
||||
/*
|
||||
* Matchers
|
||||
*/
|
||||
CV_DescriptorMatcherTest bruteForceMatcherTest( "descriptor-matcher-brute-force",
|
||||
new BruteForceMatcher<L2<float> >, 0.01 );
|
||||
CV_DescriptorMatcherTest flannBasedMatcherTest( "descriptor-matcher-flann-based",
|
||||
new FlannBasedMatcher, 0.02 );
|
||||
|
@ -49,14 +49,11 @@ void BruteForceMatcherTest::run( int )
|
||||
vector<DMatch> specMatches, genericMatches;
|
||||
BruteForceMatcher<L2<float> > specMatcher;
|
||||
BruteForceMatcher<L2Fake > genericMatcher;
|
||||
specMatcher.add( train );
|
||||
genericMatcher.add( train );
|
||||
|
||||
|
||||
int64 time0 = cvGetTickCount();
|
||||
specMatcher.match( query, specMatches );
|
||||
specMatcher.match( query, train, specMatches );
|
||||
int64 time1 = cvGetTickCount();
|
||||
genericMatcher.match( query, genericMatches );
|
||||
genericMatcher.match( query, train, genericMatches );
|
||||
int64 time2 = cvGetTickCount();
|
||||
|
||||
float specMatcherTime = float(time1 - time0)/(float)cvGetTickFrequency();
|
||||
@ -72,8 +69,10 @@ void BruteForceMatcherTest::run( int )
|
||||
for( int i=0;i<descriptorsNumber;i++ )
|
||||
{
|
||||
float epsilon = 1e-2;
|
||||
bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon && specMatches[i].indexQuery == genericMatches[i].indexQuery && specMatches[i].indexTrain == genericMatches[i].indexTrain;
|
||||
if( !isEquiv || specMatches[i].indexTrain != permutation.at<int>( 0, i ) )
|
||||
bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon &&
|
||||
specMatches[i].queryIdx == genericMatches[i].queryIdx &&
|
||||
specMatches[i].trainIdx == genericMatches[i].trainIdx;
|
||||
if( !isEquiv || specMatches[i].trainIdx != permutation.at<int>( 0, i ) )
|
||||
{
|
||||
ts->set_failed_test_info( CvTS::FAIL_MISMATCH );
|
||||
break;
|
||||
@ -87,9 +86,9 @@ void BruteForceMatcherTest::run( int )
|
||||
|
||||
|
||||
time0 = cvGetTickCount();
|
||||
specMatcher.match( query, mask, specMatches );
|
||||
specMatcher.match( query, train, specMatches, mask );
|
||||
time1 = cvGetTickCount();
|
||||
genericMatcher.match( query, mask, genericMatches );
|
||||
genericMatcher.match( query, train, genericMatches, mask );
|
||||
time2 = cvGetTickCount();
|
||||
|
||||
specMatcherTime = float(time1 - time0)/(float)cvGetTickFrequency();
|
||||
@ -103,12 +102,13 @@ void BruteForceMatcherTest::run( int )
|
||||
if( specMatches.size() != genericMatches.size() )
|
||||
ts->set_failed_test_info( CvTS::FAIL_INVALID_OUTPUT );
|
||||
|
||||
|
||||
for( int i=0;i<specMatches.size();i++ )
|
||||
for( size_t i=0;i<specMatches.size();i++ )
|
||||
{
|
||||
//float epsilon = 1e-2;
|
||||
float epsilon = 10000000;
|
||||
bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon && specMatches[i].indexQuery == genericMatches[i].indexQuery && specMatches[i].indexTrain == genericMatches[i].indexTrain;
|
||||
bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon &&
|
||||
specMatches[i].queryIdx == genericMatches[i].queryIdx &&
|
||||
specMatches[i].trainIdx == genericMatches[i].trainIdx;
|
||||
if( !isEquiv )
|
||||
{
|
||||
ts->set_failed_test_info( CvTS::FAIL_MISMATCH );
|
||||
@ -117,4 +117,4 @@ void BruteForceMatcherTest::run( int )
|
||||
}
|
||||
}
|
||||
|
||||
BruteForceMatcherTest bruteForceMatcherTest;
|
||||
BruteForceMatcherTest taBruteForceMatcherTest;
|
||||
|
Loading…
Reference in New Issue
Block a user