modified features2d interface; added algorithmic test for DescriptorMatcher; added sample on matching to many images
This commit is contained in:
@@ -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
Reference in New Issue
Block a user