diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index f6582c5e80..8c59a604e9 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -1298,7 +1298,8 @@ protected: class CV_EXPORTS SiftDescriptorExtractor : public DescriptorExtractor { public: - SiftDescriptorExtractor( double magnification, bool isNormalize=true, bool recalculateAngles=true, + SiftDescriptorExtractor( double magnification=SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION(), + bool isNormalize=true, bool recalculateAngles=true, int nOctaves=SIFT::CommonParams::DEFAULT_NOCTAVES, int nOctaveLayers=SIFT::CommonParams::DEFAULT_NOCTAVE_LAYERS, int firstOctave=SIFT::CommonParams::DEFAULT_FIRST_OCTAVE, @@ -1534,10 +1535,9 @@ void BruteForceMatcher::matchImpl( const Mat& descriptors_1, const Mat assert( mask.empty() || (mask.rows == descriptors_1.rows && mask.cols == descriptors_2.rows) ); - assert( !descriptors_1.empty() && !descriptors_2.empty() ); assert( descriptors_1.cols == descriptors_2.cols ); - assert( DataType::type == descriptors_1.type() ); - assert( DataType::type == descriptors_2.type() ); + assert( DataType::type == descriptors_1.type() || descriptors_1.empty() ); + assert( DataType::type == descriptors_2.type() || descriptors_2.empty() ); int dimension = descriptors_1.cols; matches.clear(); @@ -1822,7 +1822,7 @@ protected: \****************************************************************************************/ /* - * An abstract class used for matching descriptors that can be described as vectors in a finite-dimensional space + * A class used for matching descriptors that can be described as vectors in a finite-dimensional space */ template class CV_EXPORTS VectorDescriptorMatch : public GenericDescriptorMatch diff --git a/tests/cv/src/adetectordescriptor_evaluation.cpp b/tests/cv/src/adetectordescriptor_evaluation.cpp index 257840d10a..fc3724c879 100644 --- a/tests/cv/src/adetectordescriptor_evaluation.cpp +++ b/tests/cv/src/adetectordescriptor_evaluation.cpp @@ -260,85 +260,91 @@ void EllipticKeyPoint::calcProjection( const Mat_& H, EllipticKeyPoint& void calcEllipticKeyPointProjections( const vector& src, const Mat_& H, vector& dst ) { - assert( !src.empty() && !H.empty() && H.cols == 3 && H.rows == 3); - dst.resize(src.size()); - vector::const_iterator srcIt = src.begin(); - vector::iterator dstIt = dst.begin(); - for( ; srcIt != src.end(); ++srcIt, ++dstIt ) - srcIt->calcProjection(H, *dstIt); + if( !src.empty() ) + { + assert( !H.empty() && H.cols == 3 && H.rows == 3); + dst.resize(src.size()); + vector::const_iterator srcIt = src.begin(); + vector::iterator dstIt = dst.begin(); + for( ; srcIt != src.end(); ++srcIt, ++dstIt ) + srcIt->calcProjection(H, *dstIt); + } } void transformToEllipticKeyPoints( const vector& src, vector& dst ) { - assert( !src.empty() ); - dst.resize(src.size()); - for( size_t i = 0; i < src.size(); i++ ) + if( !src.empty() ) { - float rad = src[i].size; - assert( rad ); - float fac = 1.f/(rad*rad); - dst[i] = EllipticKeyPoint( src[i].pt, Scalar(fac, 0, fac) ); + dst.resize(src.size()); + for( size_t i = 0; i < src.size(); i++ ) + { + float rad = src[i].size; + assert( rad ); + float fac = 1.f/(rad*rad); + dst[i] = EllipticKeyPoint( src[i].pt, Scalar(fac, 0, fac) ); + } } } void transformToKeyPoints( const vector& src, vector& dst ) { - assert( !src.empty() ); - dst.resize(src.size()); - for( size_t i = 0; i < src.size(); i++ ) + if( !src.empty() ) { - Size_ axes = src[i].axes; - float rad = sqrt(axes.height*axes.width); - dst[i] = KeyPoint(src[i].center, rad ); + dst.resize(src.size()); + for( size_t i = 0; i < src.size(); i++ ) + { + Size_ axes = src[i].axes; + float rad = sqrt(axes.height*axes.width); + dst[i] = KeyPoint(src[i].center, rad ); + } } } void calcKeyPointProjections( const vector& src, const Mat_& H, vector& dst ) { - assert( !src.empty() && !H.empty() && H.cols == 3 && H.rows == 3); - dst.resize(src.size()); - vector::const_iterator srcIt = src.begin(); - vector::iterator dstIt = dst.begin(); - for( ; srcIt != src.end(); ++srcIt, ++dstIt ) + if( !src.empty() ) { - Point2f dstPt = applyHomography(H, srcIt->pt); - - Mat_ Aff; linearizeHomographyAt(H, srcIt->pt, Aff); - Mat_ eval; eigen(Aff, eval); - assert( eval.type()==CV_64FC1 && eval.cols==1 && eval.rows==2 ); - float dstSize = srcIt->size * sqrt(eval(0,0) * eval(1,0)) /*scale from linearized homography matrix*/; - assert( dstSize ); - assert( dstSize < 0.5 ); // TODO check for surf - - // calculate new anngle - float srcAngleRad = srcIt->angle*CV_PI/180; - Point2f vec1(cos(srcAngleRad), sin(srcAngleRad)), vec2; - vec2 = applyHomography(H, vec1); - float w = 1.f/norm(vec2); - vec2 = vec2*w; - float dstAngleGrad = acos(vec2.x)*180.f/CV_PI; // 0..180 - if( asin(vec2.y) < 0 ) // -pi/2 .. pi/2 - dstAngleGrad += 180; - *dstIt = KeyPoint( dstPt, dstSize, dstAngleGrad, srcIt->response, srcIt->octave, srcIt->class_id ); + assert( !H.empty() && H.cols == 3 && H.rows == 3); + dst.resize(src.size()); + vector::const_iterator srcIt = src.begin(); + vector::iterator dstIt = dst.begin(); + for( ; srcIt != src.end(); ++srcIt, ++dstIt ) + { + Point2f dstPt = applyHomography(H, srcIt->pt); + + float srcSize2 = srcIt->size * srcIt->size; + Mat_ invM; invert(EllipticKeyPoint::getSecondMomentsMatrix( Scalar(1./srcSize2, 0., 1./srcSize2)), invM); + Mat_ Aff; linearizeHomographyAt(H, srcIt->pt, Aff); + Mat_ dstM; invert(Aff*invM*Aff.t(), dstM); + Mat_ eval; eigen( dstM, eval ); + assert( eval(0,0) && eval(1,0) ); + float dstSize = pow(1./(eval(0,0)*eval(1,0)), 0.25); + + // TODO: check angle projection + float srcAngleRad = srcIt->angle*CV_PI/180; + Point2f vec1(cos(srcAngleRad), sin(srcAngleRad)), vec2; + vec2.x = Aff(0,0)*vec1.x + Aff(0,1)*vec1.y; + vec2.y = Aff(1,0)*vec1.x + Aff(0,1)*vec1.y; + float dstAngleGrad = fastAtan2(vec2.y, vec2.x); + + *dstIt = KeyPoint( dstPt, dstSize, dstAngleGrad, srcIt->response, srcIt->octave, srcIt->class_id ); + } } } -void filterKeyPointsByImageSize( vector& keypoints, const Size& imgSize, vector& origIdxs ) +void filterKeyPointsByImageSize( vector& keypoints, const Size& imgSize ) { - vector filtered; - filtered.reserve(keypoints.size()); - Rect r(0, 0, imgSize.width, imgSize.height); - origIdxs.clear(); - vector::const_iterator it = keypoints.begin(); - for( int i = 0; it != keypoints.end(); ++it, i++ ) + if( !keypoints.empty() ) { - if( r.contains(it->pt) ) - { - filtered.push_back(*it); - origIdxs.push_back(i); - } + vector filtered; + filtered.reserve(keypoints.size()); + Rect r(0, 0, imgSize.width, imgSize.height); + vector::const_iterator it = keypoints.begin(); + for( int i = 0; it != keypoints.end(); ++it, i++ ) + if( r.contains(it->pt) ) + filtered.push_back(*it); + keypoints.assign(filtered.begin(), filtered.end()); } - keypoints.assign(filtered.begin(), filtered.end()); } /* @@ -347,7 +353,10 @@ void filterKeyPointsByImageSize( vector& keypoints, const Size& imgSiz void overlap( const vector& keypoints1, const vector& keypoints2t, bool commonPart, SparseMat_& overlaps ) { - assert( !keypoints1.empty() && !keypoints2t.empty() ); + overlaps.clear(); + if( keypoints1.empty() || keypoints2t.empty() ) + return; + int size[] = { keypoints1.size(), keypoints2t.size() }; overlaps.create( 2, size ); @@ -409,27 +418,27 @@ void overlap( const vector& keypoints1, const vector& keypoints, const Size& imgSize ) { - vector filtered; - filtered.reserve(keypoints.size()); - vector::const_iterator it = keypoints.begin(); - for( int i = 0; it != keypoints.end(); ++it, i++ ) + if( !keypoints.empty() ) { - if( it->center.x + it->boundingBox.width < imgSize.width && - it->center.x - it->boundingBox.width > 0 && - it->center.y + it->boundingBox.height < imgSize.height && - it->center.y - it->boundingBox.height > 0 ) - filtered.push_back(*it); + vector filtered; + filtered.reserve(keypoints.size()); + vector::const_iterator it = keypoints.begin(); + for( int i = 0; it != keypoints.end(); ++it, i++ ) + { + if( it->center.x + it->boundingBox.width < imgSize.width && + it->center.x - it->boundingBox.width > 0 && + it->center.y + it->boundingBox.height < imgSize.height && + it->center.y - it->boundingBox.height > 0 ) + filtered.push_back(*it); + } + keypoints.assign(filtered.begin(), filtered.end()); } - keypoints.assign(filtered.begin(), filtered.end()); } void getEllipticKeyPointsInCommonPart( vector& keypoints1, vector& keypoints2, vector& keypoints1t, vector& keypoints2t, Size& imgSize1, const Size& imgSize2 ) { - assert( !keypoints1.empty() && !keypoints2.empty() ); - assert( keypoints1t.size() == keypoints1.size() && keypoints2t.size() == keypoints2.size() ); - filterEllipticKeyPointsByImageSize( keypoints1, imgSize1 ); filterEllipticKeyPointsByImageSize( keypoints1t, imgSize2 ); filterEllipticKeyPointsByImageSize( keypoints2, imgSize2 ); @@ -502,7 +511,7 @@ void calculateRepeatability( const vector& _keypoints1, const currOverlaps.erase(maxIdx[0], i2); correspondencesCount++; } - repeatability = minCount ? (float)(correspondencesCount*100)/minCount : 0; + repeatability = minCount ? (float)(correspondencesCount*100)/minCount : -1; } else { @@ -531,12 +540,12 @@ void evaluateDetectors( const vector& keypoints1, const vector inline float recall( int correctMatchCount, int correspondenceCount ) { - return correspondenceCount ? (float)correctMatchCount / (float)correspondenceCount : 0; + return correspondenceCount ? (float)correctMatchCount / (float)correspondenceCount : -1; } inline float precision( int correctMatchCount, int falseMatchCount ) { - return correctMatchCount + falseMatchCount ? (float)correctMatchCount / (float)(correctMatchCount + falseMatchCount) : 0; + return correctMatchCount + falseMatchCount ? (float)correctMatchCount / (float)(correctMatchCount + falseMatchCount) : -1; } void evaluateDescriptors( const vector& keypoints1, const vector& keypoints2, @@ -816,6 +825,7 @@ public: { validQuality.resize(DATASETS_COUNT); calcQuality.resize(DATASETS_COUNT); + isSaveKeypoints.resize(DATASETS_COUNT); } protected: @@ -834,9 +844,9 @@ protected: virtual void readResults( FileNode& fn, int datasetIdx, int caseIdx ); virtual void writeResults( FileStorage& fs, int datasetIdx, int caseIdx ) const; - virtual void readDatasetRunParams( FileNode& fn, int datasetIdx ) = 0; - virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const = 0; - virtual void setDefaultDatasetRunParams( int datasetIdx ) = 0; + virtual void readDatasetRunParams( FileNode& fn, int datasetIdx ); + virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const; + virtual void setDefaultDatasetRunParams( int datasetIdx ); virtual FeatureDetector* createDetector( int datasetIdx ) = 0; void openToWriteKeypointsFile( FileStorage& fs, int datasetIdx ); @@ -858,6 +868,7 @@ protected: }; vector > validQuality; vector > calcQuality; + vector isSaveKeypoints; }; string DetectorQualityTest::getRunParamsFilename() const @@ -916,22 +927,30 @@ void DetectorQualityTest::writeResults( FileStorage& fs, int datasetIdx, int cas #endif } +void DetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) +{ + isSaveKeypoints[datasetIdx] = (int)fn["isSaveKeypoints"] != 0; +} + +void DetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const +{ + fs << "isSaveKeypoints" << isSaveKeypoints[datasetIdx]; +} + +void DetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) +{ + isSaveKeypoints[datasetIdx] = false; +} + void DetectorQualityTest::openToWriteKeypointsFile( FileStorage& fs, int datasetIdx ) { string filename = string(ts->get_data_path()) + KEYPOINTS_DIR + algName + "_"+ - DATASET_NAMES[datasetIdx] + ".xml" ; + DATASET_NAMES[datasetIdx] + ".xml.gz" ; - // open file to write keypoints if there is not yet - fs.open(filename, FileStorage::READ); - if( fs.isOpened() ) - fs.release(); - else - { - fs.open(filename, FileStorage::WRITE); - if( !fs.isOpened() ) - ts->printf( CvTS::LOG, "keypoints can not be written in file %s because this file can not be opened\n", - filename.c_str()); - } + fs.open(filename, FileStorage::WRITE); + if( !fs.isOpened() ) + ts->printf( CvTS::LOG, "keypoints can not be written in file %s because this file can not be opened\n", + filename.c_str()); } inline void writeKeypoints( FileStorage& fs, const vector& keypoints, int imgIdx ) @@ -960,7 +979,8 @@ void DetectorQualityTest::run( int ) for(int di = 0; di < DATASETS_COUNT; di++ ) { FileStorage keypontsFS; - openToWriteKeypointsFile( keypontsFS, di ); + if( isSaveKeypoints[di] ) + openToWriteKeypointsFile( keypontsFS, di ); vector imgs, Hs; if( !readDataset( DATASET_NAMES[di], Hs, imgs ) ) @@ -1062,7 +1082,7 @@ int DetectorQualityTest::processResults( int datasetIdx, int caseIdx ) class FastDetectorQualityTest : public DetectorQualityTest { public: - FastDetectorQualityTest() : DetectorQualityTest( "fast", "quality-fast-detector" ) + FastDetectorQualityTest() : DetectorQualityTest( "fast", "quality-detector-fast" ) { runParams.resize(DATASETS_COUNT); } protected: @@ -1086,17 +1106,21 @@ FeatureDetector* FastDetectorQualityTest::createDetector( int datasetIdx ) void FastDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { + DetectorQualityTest::readDatasetRunParams(fn, datasetIdx); runParams[datasetIdx].threshold = fn["threshold"]; - runParams[datasetIdx].nonmaxSuppression = (int)fn["nonmaxSuppression"] ? true : false;} + runParams[datasetIdx].nonmaxSuppression = (int)fn["nonmaxSuppression"] ? true : false; +} void FastDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { + DetectorQualityTest::writeDatasetRunParams(fs, datasetIdx); fs << "threshold" << runParams[datasetIdx].threshold; fs << "nonmaxSuppression" << runParams[datasetIdx].nonmaxSuppression; } void FastDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { + DetectorQualityTest::setDefaultDatasetRunParams(datasetIdx); runParams[datasetIdx].threshold = 1; runParams[datasetIdx].nonmaxSuppression = true; } @@ -1144,6 +1168,7 @@ FeatureDetector* BaseGfttDetectorQualityTest::createDetector( int datasetIdx ) void BaseGfttDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { + DetectorQualityTest::readDatasetRunParams(fn, datasetIdx); runParams[datasetIdx].maxCorners = fn["maxCorners"]; runParams[datasetIdx].qualityLevel = fn["qualityLevel"]; runParams[datasetIdx].minDistance = fn["minDistance"]; @@ -1153,6 +1178,7 @@ void BaseGfttDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datase void BaseGfttDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { + DetectorQualityTest::writeDatasetRunParams(fs, datasetIdx); fs << "maxCorners" << runParams[datasetIdx].maxCorners; fs << "qualityLevel" << runParams[datasetIdx].qualityLevel; fs << "minDistance" << runParams[datasetIdx].minDistance; @@ -1162,6 +1188,7 @@ void BaseGfttDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int da void BaseGfttDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { + DetectorQualityTest::setDefaultDatasetRunParams(datasetIdx); runParams[datasetIdx].maxCorners = 1500; runParams[datasetIdx].qualityLevel = 0.01; runParams[datasetIdx].minDistance = 2.0; @@ -1172,7 +1199,7 @@ void BaseGfttDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) class GfttDetectorQualityTest : public BaseGfttDetectorQualityTest { public: - GfttDetectorQualityTest() : BaseGfttDetectorQualityTest( "gftt", "quality-gftt-detector" ) {} + GfttDetectorQualityTest() : BaseGfttDetectorQualityTest( "gftt", "quality-detector-gftt" ) {} }; GfttDetectorQualityTest gfttDetectorQuality; @@ -1180,7 +1207,7 @@ GfttDetectorQualityTest gfttDetectorQuality; class HarrisDetectorQualityTest : public BaseGfttDetectorQualityTest { public: - HarrisDetectorQualityTest() : BaseGfttDetectorQualityTest( "harris", "quality-harris-detector" ) + HarrisDetectorQualityTest() : BaseGfttDetectorQualityTest( "harris", "quality-detector-harris" ) { useHarrisDetector = true; } }; @@ -1190,7 +1217,7 @@ HarrisDetectorQualityTest harrisDetectorQuality; class MserDetectorQualityTest : public DetectorQualityTest { public: - MserDetectorQualityTest() : DetectorQualityTest( "mser", "quality-mser-detector" ) + MserDetectorQualityTest() : DetectorQualityTest( "mser", "quality-detector-mser" ) { runParams.resize(DATASETS_COUNT); } protected: @@ -1199,18 +1226,7 @@ protected: virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const; virtual void setDefaultDatasetRunParams( int datasetIdx ); - struct RunParams - { - int delta; - int minArea; - int maxArea; - float maxVariation; - float minDiversity; - int maxEvolution; - double areaThreshold; - double minMargin; - int edgeBlurSize; - }; + typedef CvMSERParams RunParams; vector runParams; }; @@ -1229,6 +1245,7 @@ FeatureDetector* MserDetectorQualityTest::createDetector( int datasetIdx ) void MserDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { + DetectorQualityTest::readDatasetRunParams(fn, datasetIdx); runParams[datasetIdx].delta = fn["delta"]; runParams[datasetIdx].minArea = fn["minArea"]; runParams[datasetIdx].maxArea = fn["maxArea"]; @@ -1242,6 +1259,7 @@ void MserDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx void MserDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { + DetectorQualityTest::writeDatasetRunParams(fs, datasetIdx); fs << "delta" << runParams[datasetIdx].delta; fs << "minArea" << runParams[datasetIdx].minArea; fs << "maxArea" << runParams[datasetIdx].maxArea; @@ -1255,6 +1273,7 @@ void MserDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datase void MserDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { + DetectorQualityTest::setDefaultDatasetRunParams(datasetIdx); runParams[datasetIdx].delta = 5; runParams[datasetIdx].minArea = 60; runParams[datasetIdx].maxArea = 14400; @@ -1272,7 +1291,7 @@ MserDetectorQualityTest mserDetectorQuality; class StarDetectorQualityTest : public DetectorQualityTest { public: - StarDetectorQualityTest() : DetectorQualityTest( "star", "quality-star-detector" ) + StarDetectorQualityTest() : DetectorQualityTest( "star", "quality-detector-star" ) { runParams.resize(DATASETS_COUNT); } protected: @@ -1303,6 +1322,7 @@ FeatureDetector* StarDetectorQualityTest::createDetector( int datasetIdx ) void StarDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { + DetectorQualityTest::readDatasetRunParams(fn, datasetIdx); runParams[datasetIdx].maxSize = fn["maxSize"]; runParams[datasetIdx].responseThreshold = fn["responseThreshold"]; runParams[datasetIdx].lineThresholdProjected = fn["lineThresholdProjected"]; @@ -1312,6 +1332,7 @@ void StarDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx void StarDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { + DetectorQualityTest::writeDatasetRunParams(fs, datasetIdx); fs << "maxSize" << runParams[datasetIdx].maxSize; fs << "responseThreshold" << runParams[datasetIdx].responseThreshold; fs << "lineThresholdProjected" << runParams[datasetIdx].lineThresholdProjected; @@ -1321,6 +1342,7 @@ void StarDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datase void StarDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { + DetectorQualityTest::setDefaultDatasetRunParams(datasetIdx); runParams[datasetIdx].maxSize = 16; runParams[datasetIdx].responseThreshold = 30; runParams[datasetIdx].lineThresholdProjected = 10; @@ -1334,7 +1356,7 @@ StarDetectorQualityTest starDetectorQuality; class SiftDetectorQualityTest : public DetectorQualityTest { public: - SiftDetectorQualityTest() : DetectorQualityTest( "sift", "quality-sift-detector" ) + SiftDetectorQualityTest() : DetectorQualityTest( "sift", "quality-detector-sift" ) { runParams.resize(DATASETS_COUNT); } protected: @@ -1356,34 +1378,37 @@ FeatureDetector* SiftDetectorQualityTest::createDetector( int datasetIdx ) { return new SiftFeatureDetector( runParams[datasetIdx].detect.threshold, runParams[datasetIdx].detect.edgeThreshold, - runParams[datasetIdx].detect.angleMode, runParams[datasetIdx].comm.nOctaves, runParams[datasetIdx].comm.nOctaveLayers, - runParams[datasetIdx].comm.firstOctave ); + runParams[datasetIdx].comm.firstOctave, + runParams[datasetIdx].comm.angleMode ); } void SiftDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { + DetectorQualityTest::readDatasetRunParams(fn, datasetIdx); runParams[datasetIdx].detect.threshold = fn["threshold"]; runParams[datasetIdx].detect.edgeThreshold = fn["edgeThreshold"]; - runParams[datasetIdx].detect.angleMode = fn["angleMode"]; runParams[datasetIdx].comm.nOctaves = fn["nOctaves"]; runParams[datasetIdx].comm.nOctaveLayers = fn["nOctaveLayers"]; runParams[datasetIdx].comm.firstOctave = fn["firstOctave"]; + runParams[datasetIdx].comm.angleMode = fn["angleMode"]; } void SiftDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { + DetectorQualityTest::writeDatasetRunParams(fs, datasetIdx); fs << "threshold" << runParams[datasetIdx].detect.threshold; fs << "edgeThreshold" << runParams[datasetIdx].detect.edgeThreshold; - fs << "angleMode" << runParams[datasetIdx].detect.angleMode; fs << "nOctaves" << runParams[datasetIdx].comm.nOctaves; fs << "nOctaveLayers" << runParams[datasetIdx].comm.nOctaveLayers; fs << "firstOctave" << runParams[datasetIdx].comm.firstOctave; + fs << "angleMode" << runParams[datasetIdx].comm.angleMode; } void SiftDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { + DetectorQualityTest::setDefaultDatasetRunParams(datasetIdx); runParams[datasetIdx].detect = SIFT::DetectorParams(); runParams[datasetIdx].comm = SIFT::CommonParams(); } @@ -1394,7 +1419,7 @@ SiftDetectorQualityTest siftDetectorQuality; class SurfDetectorQualityTest : public DetectorQualityTest { public: - SurfDetectorQualityTest() : DetectorQualityTest( "surf", "quality-surf-detector" ) + SurfDetectorQualityTest() : DetectorQualityTest( "surf", "quality-detector-surf" ) { runParams.resize(DATASETS_COUNT); } protected: @@ -1421,6 +1446,7 @@ FeatureDetector* SurfDetectorQualityTest::createDetector( int datasetIdx ) void SurfDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { + DetectorQualityTest::readDatasetRunParams(fn, datasetIdx); runParams[datasetIdx].hessianThreshold = fn["hessianThreshold"]; runParams[datasetIdx].octaves = fn["octaves"]; runParams[datasetIdx].octaveLayers = fn["octaveLayers"]; @@ -1428,6 +1454,7 @@ void SurfDetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx void SurfDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { + DetectorQualityTest::writeDatasetRunParams(fs, datasetIdx); fs << "hessianThreshold" << runParams[datasetIdx].hessianThreshold; fs << "octaves" << runParams[datasetIdx].octaves; fs << "octaveLayers" << runParams[datasetIdx].octaveLayers; @@ -1435,6 +1462,7 @@ void SurfDetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datase void SurfDetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { + DetectorQualityTest::setDefaultDatasetRunParams(datasetIdx); runParams[datasetIdx].hessianThreshold = 400.; runParams[datasetIdx].octaves = 3; runParams[datasetIdx].octaveLayers = 4; @@ -1564,33 +1592,11 @@ void DescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetI void DescriptorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { - commRunParams[datasetIdx].keypontsFilename = "surf_" + DATASET_NAMES[datasetIdx] + ".xml"; - commRunParams[datasetIdx].projectKeypointsFrom1Image = false; + commRunParams[datasetIdx].keypontsFilename = "surf_" + DATASET_NAMES[datasetIdx] + ".xml.gz"; + commRunParams[datasetIdx].projectKeypointsFrom1Image = true; commRunParams[datasetIdx].matchFilter = NO_MATCH_FILTER; } -// if keyponts from first image are projected on second image using homography matrix -void evaluateDescriptors( const vector& origIdxs2, - const vector& matches1to2, - int& correctMatchCount, int& falseMatchCount, int& correspondenceCount ) -{ - assert( !origIdxs2.empty() > 0 && !matches1to2.empty() ); - correspondenceCount = origIdxs2.size(); - correctMatchCount = falseMatchCount = 0; - for( size_t i1 = 0; i1 < matches1to2.size(); i1++ ) - { - size_t i2 = matches1to2[i1]; - if( i2 > 0 ) - { - if( origIdxs2[i2] == (int)i1 ) - correctMatchCount++; - else - falseMatchCount++; - } - } -} - - void DescriptorQualityTest::run( int ) { readAllDatasetsRunParams(); @@ -1617,42 +1623,32 @@ void DescriptorQualityTest::run( int ) vector keypoints1; vector ekeypoints1; readKeypoints( keypontsFS, keypoints1, 0); - if( !commRunParams[di].projectKeypointsFrom1Image ) - transformToEllipticKeyPoints( keypoints1, ekeypoints1 ); - else - { - assert(0); - // TODO debug! - } + transformToEllipticKeyPoints( keypoints1, ekeypoints1 ); for( int ci = 0; ci < TEST_CASE_COUNT; ci++ ) { progress = update_progress( progress, di*TEST_CASE_COUNT + ci, progressCount, 0 ); - vector keypoints2; vector ekeypoints2; - vector origIdxs2; + vector keypoints2; + vector ekeypoints2; if( commRunParams[di].projectKeypointsFrom1Image ) { + // TODO need to test function calcKeyPointProjections calcKeyPointProjections( keypoints1, Hs[ci], keypoints2 ); - filterKeyPointsByImageSize( keypoints2, imgs[ci+1].size(), origIdxs2 ); + filterKeyPointsByImageSize( keypoints2, imgs[ci+1].size() ); } else - { readKeypoints( keypontsFS, keypoints2, ci+1 ); - transformToEllipticKeyPoints( keypoints2, ekeypoints2 ); - } + transformToEllipticKeyPoints( keypoints2, ekeypoints2 ); + Ptr descMatch = createDescriptorMatch(di); descMatch->add( imgs[ci+1], keypoints2 ); vector matches1to2; descMatch->match( imgs[0], keypoints1, matches1to2 ); // TODO if( commRunParams[di].matchFilter ) - int correctMatchCount, falseMatchCount, correspCount; - if( commRunParams[di].projectKeypointsFrom1Image ) - evaluateDescriptors( origIdxs2, matches1to2, correctMatchCount, falseMatchCount, correspCount ); - else - evaluateDescriptors( ekeypoints1, ekeypoints2, matches1to2, imgs[0], imgs[ci+1], Hs[ci], - correctMatchCount, falseMatchCount, correspCount ); + evaluateDescriptors( ekeypoints1, ekeypoints2, matches1to2, imgs[0], imgs[ci+1], Hs[ci], + correctMatchCount, falseMatchCount, correspCount ); calcQuality[di][ci].recall = recall( correctMatchCount, correspCount ); calcQuality[di][ci].precision = precision( correctMatchCount, falseMatchCount ); } @@ -1691,7 +1687,7 @@ int DescriptorQualityTest::processResults( int datasetIdx, int caseIdx ) class SiftDescriptorQualityTest : public DescriptorQualityTest { public: - SiftDescriptorQualityTest() : DescriptorQualityTest( "sift", "quality-sift-descriptor" ) + SiftDescriptorQualityTest() : DescriptorQualityTest( "sift", "quality-descriptor-sift" ) { runParams.resize(DATASETS_COUNT); } protected: @@ -1702,22 +1698,21 @@ protected: struct RunParams { - double magnification; - bool isNormalize; - int nOctaves; - int nOctaveLayers; - int firstOctave; + SIFT::CommonParams comm; + SIFT::DescriptorParams desc; }; vector runParams; }; GenericDescriptorMatch* SiftDescriptorQualityTest::createDescriptorMatch( int datasetIdx ) { - SiftDescriptorExtractor extractor( runParams[datasetIdx].magnification, - runParams[datasetIdx].isNormalize, - runParams[datasetIdx].nOctaves, - runParams[datasetIdx].nOctaveLayers, - runParams[datasetIdx].firstOctave ); + SiftDescriptorExtractor extractor( runParams[datasetIdx].desc.magnification, + runParams[datasetIdx].desc.isNormalize, + runParams[datasetIdx].desc.recalculateAngles, + runParams[datasetIdx].comm.nOctaves, + runParams[datasetIdx].comm.nOctaveLayers, + runParams[datasetIdx].comm.firstOctave, + runParams[datasetIdx].comm.angleMode ); BruteForceMatcher > matcher; return new VectorDescriptorMatch > >(extractor, matcher); } @@ -1725,31 +1720,32 @@ GenericDescriptorMatch* SiftDescriptorQualityTest::createDescriptorMatch( int da void SiftDescriptorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx ) { DescriptorQualityTest::readDatasetRunParams( fn, datasetIdx); - runParams[datasetIdx].magnification = fn["magnification"]; - runParams[datasetIdx].isNormalize = (int)fn["isNormalize"] != 0; - runParams[datasetIdx].nOctaves = fn["nOctaves"]; - runParams[datasetIdx].nOctaveLayers = fn["nOctaveLayers"]; - runParams[datasetIdx].firstOctave = fn["firstOctave"]; + runParams[datasetIdx].desc.magnification = fn["magnification"]; + runParams[datasetIdx].desc.isNormalize = (int)fn["isNormalize"] != 0; + runParams[datasetIdx].desc.recalculateAngles = (int)fn["recalculateAngles"] != 0; + runParams[datasetIdx].comm.nOctaves = fn["nOctaves"]; + runParams[datasetIdx].comm.nOctaveLayers = fn["nOctaveLayers"]; + runParams[datasetIdx].comm.firstOctave = fn["firstOctave"]; + runParams[datasetIdx].comm.angleMode = fn["angleMode"]; } void SiftDescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const { DescriptorQualityTest::writeDatasetRunParams( fs, datasetIdx ); - fs << "magnification" << runParams[datasetIdx].magnification; - fs << "isNormalize" << runParams[datasetIdx].isNormalize; - fs << "nOctaves" << runParams[datasetIdx].nOctaves; - fs << "nOctaveLayers" << runParams[datasetIdx].nOctaveLayers; - fs << "firstOctave" << runParams[datasetIdx].firstOctave; + fs << "magnification" << runParams[datasetIdx].desc.magnification; + fs << "isNormalize" << runParams[datasetIdx].desc.isNormalize; + fs << "recalculateAngles" << runParams[datasetIdx].desc.recalculateAngles; + fs << "nOctaves" << runParams[datasetIdx].comm.nOctaves; + fs << "nOctaveLayers" << runParams[datasetIdx].comm.nOctaveLayers; + fs << "firstOctave" << runParams[datasetIdx].comm.firstOctave; + fs << "angleMode" << runParams[datasetIdx].comm.angleMode; } void SiftDescriptorQualityTest::setDefaultDatasetRunParams( int datasetIdx ) { DescriptorQualityTest::setDefaultDatasetRunParams( datasetIdx ); - runParams[datasetIdx].magnification = SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION(); - runParams[datasetIdx].isNormalize = SIFT::DescriptorParams::DEFAULT_IS_NORMALIZE; - runParams[datasetIdx].nOctaves = SIFT::CommonParams::DEFAULT_NOCTAVES; - runParams[datasetIdx].nOctaveLayers = SIFT::CommonParams::DEFAULT_NOCTAVE_LAYERS; - runParams[datasetIdx].firstOctave = SIFT::CommonParams::DEFAULT_FIRST_OCTAVE; + runParams[datasetIdx].desc = SIFT::DescriptorParams(); + runParams[datasetIdx].comm = SIFT::CommonParams(); } SiftDescriptorQualityTest siftDescriptorQuality; @@ -1758,7 +1754,7 @@ SiftDescriptorQualityTest siftDescriptorQuality; class SurfDescriptorQualityTest : public DescriptorQualityTest { public: - SurfDescriptorQualityTest() : DescriptorQualityTest( "surf", "quality-surf-descriptor" ) + SurfDescriptorQualityTest() : DescriptorQualityTest( "surf", "quality-descriptor-surf" ) { runParams.resize(DATASETS_COUNT); } protected: