feature2d.diff

Delia Passalacqua, 2011-05-09 12:55 pm

Download (36.3 kB)

 
test/test_detectordescriptor_evaluation.cpp (copia locale)
706 706
    calcQuality[di].resize(TEST_CASE_COUNT);
707 707

  
708 708
    vector<KeyPoint> keypoints1;
709
    detector->detect( imgs[0], keypoints1 );
710
    writeKeypoints( keypontsFS, keypoints1, 0);
711
    int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
712
    for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
713
    {
714
        progress = update_progress( progress, di*TEST_CASE_COUNT + ci, progressCount, 0 );
715
        vector<KeyPoint> keypoints2;
716
        float rep;
717
        evaluateFeatureDetector( imgs[0], imgs[ci+1], Hs[ci], &keypoints1, &keypoints2,
718
                                 rep, calcQuality[di][ci].correspondenceCount,
719
                                 detector );
720
        calcQuality[di][ci].repeatability = rep == -1 ? rep : 100.f*rep;
721
        writeKeypoints( keypontsFS, keypoints2, ci+1);
722
    }
709
    vector<Elliptic_KeyPoint>ekeypoints1;
710
    if(!algName.compare("HarrisAffine")){
711
		Ptr<HarrisAffineFeatureDetector> specDetector = new HarrisAffineFeatureDetector();
712
			specDetector->detect(imgs[0],ekeypoints1);
713
			keypoints1 = vector<KeyPoint>(ekeypoints1.begin(), ekeypoints1.end());
714
			writeKeypoints( keypontsFS, keypoints1, 0);
715
			int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
716
			for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
717
			{
718
				progress = update_progress( progress, di*TEST_CASE_COUNT + ci, progressCount, 0 );
719
				vector<KeyPoint> keypoints2;
720
				vector<Elliptic_KeyPoint> ekeypoints2;
721
				float rep;
722
				evaluateFeatureDetector( imgs[0], imgs[ci+1], Hs[ci], &ekeypoints1, &ekeypoints2,
723
										 rep, calcQuality[di][ci].correspondenceCount,
724
										 specDetector );
725
				calcQuality[di][ci].repeatability = rep == -1 ? rep : 100.f*rep;
726
				keypoints2 = vector<KeyPoint>(ekeypoints2.begin(), ekeypoints2.end());
727
				writeKeypoints( keypontsFS, keypoints2, ci+1);
728
			}
729
		}else
730
		{
731
		detector->detect( imgs[0], keypoints1 );
732
		writeKeypoints( keypontsFS, keypoints1, 0);
733
		int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
734
		for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
735
		{
736
			progress = update_progress( progress, di*TEST_CASE_COUNT + ci, progressCount, 0 );
737
			vector<KeyPoint> keypoints2;
738
			float rep;
739
			evaluateFeatureDetector( imgs[0], imgs[ci+1], Hs[ci], &keypoints1, &keypoints2,
740
									 rep, calcQuality[di][ci].correspondenceCount,
741
									 detector );
742
			calcQuality[di][ci].repeatability = rep == -1 ? rep : 100.f*rep;
743
			writeKeypoints( keypontsFS, keypoints2, ci+1);
744
		}
745
	}
723 746
}
724 747

  
725 748
void testLog( cvtest::TS* ts, bool isBadAccuracy )
......
1160 1183
// Detectors
1161 1184
//DetectorQualityTest fastDetectorQuality = DetectorQualityTest( "FAST", "quality-detector-fast" );
1162 1185
//DetectorQualityTest gfttDetectorQuality = DetectorQualityTest( "GFTT", "quality-detector-gftt" );
1163
//DetectorQualityTest harrisDetectorQuality = DetectorQualityTest( "HARRIS", "quality-detector-harris" );
1186

  
1187
//DetectorQualityTest harrisDetectorQuality = DetectorQualityTest( "HARRIS");
1188
//TEST(Features2d_Harris, quality) { harrisDetectorQuality; harrisDetectorQuality.safe_run(); }
1189

  
1190

  
1191
TEST(Features2d_HarrisLaplace, quality) { 
1192
	DetectorQualityTest harrislaplaceDetectorQuality = DetectorQualityTest( "HarrisLaplace" );
1193
	harrislaplaceDetectorQuality.safe_run(); 
1194
	}
1195
DetectorQualityTest harrisaffineDetectorQuality = DetectorQualityTest( "HarrisAffine");
1196
TEST(Features2d_HarrisAffine, quality) { harrisaffineDetectorQuality; harrisaffineDetectorQuality.safe_run(); }
1164 1197
//DetectorQualityTest mserDetectorQuality = DetectorQualityTest( "MSER", "quality-detector-mser" );
1165 1198
//DetectorQualityTest starDetectorQuality = DetectorQualityTest( "STAR", "quality-detector-star" );
1166 1199
//DetectorQualityTest siftDetectorQuality = DetectorQualityTest( "SIFT", "quality-detector-sift" );
include/opencv2/features2d/features2d.hpp (copia locale)
45 45

  
46 46
#include "opencv2/core/core.hpp"
47 47
#include "opencv2/flann/flann.hpp"
48
#include "opencv2/imgproc/gaussian_pyramid.hpp"
48 49

  
49 50
#ifdef __cplusplus
50 51
#include <limits>
......
264 265
CV_EXPORTS void read(const FileNode& node, CV_OUT vector<KeyPoint>& keypoints);    
265 266

  
266 267
/*
268
 * Elliptic region around interest point 
269
 */
270
class CV_EXPORTS Elliptic_KeyPoint : public KeyPoint{
271
public:
272
	Point centre;
273
	Size_<float> axes;
274
	double phi;
275
	float size;
276
	float si;
277
	Mat transf;
278
	Elliptic_KeyPoint();
279
	Elliptic_KeyPoint(Point centre, double phi, Size axes, float size, float si);
280
	virtual ~Elliptic_KeyPoint();
281
};
282

  
283

  
284
/*
267 285
 * A class filters a vector of keypoints.
268 286
 * Because now it is difficult to provide a convenient interface for all usage scenarios of the keypoints filter class,
269 287
 * it has only 3 needed by now static methods.
......
422 440
        CV_OUT vector<vector<Point> >& msers, const Mat& mask ) const;
423 441
};
424 442

  
443
class CV_EXPORTS HarrisLaplace
444
{
445

  
446
public:
447
    HarrisLaplace();
448
    HarrisLaplace(int numOctaves, float corn_thresh, float DOG_thresh,int maxCorners=1500, int num_layers=4);
449
    void detect(const Mat& image, vector<KeyPoint>& keypoints) const;
450
    virtual ~HarrisLaplace();
451

  
452
    int numOctaves;
453
    float corn_thresh;
454
    float DOG_thresh;
455
    int maxCorners;
456
    int num_layers;
457

  
458
};
459

  
460

  
425 461
/*!
426 462
 The "Star" Detector.
427 463
 
......
1478 1514
    int levels;
1479 1515
};
1480 1516

  
1517
class CV_EXPORTS HarrisLaplaceFeatureDetector : public FeatureDetector
1518
{
1519
public:
1520
 class CV_EXPORTS Params
1521
    {
1522
    public:
1523
        Params( int numOctaves=6, float corn_thresh=0.01, float DOG_thresh=0.01, int maxCorners=5000, int num_layers=4 );
1524
        
1525

  
1526
        int numOctaves;
1527
        float corn_thresh;
1528
        float DOG_thresh;
1529
        int maxCorners;
1530
        int num_layers;
1531
       
1532
    };
1533
    HarrisLaplaceFeatureDetector( const HarrisLaplaceFeatureDetector::Params& params=HarrisLaplaceFeatureDetector::Params() );
1534
    HarrisLaplaceFeatureDetector( int numOctaves, float corn_thresh, float DOG_thresh, int maxCorners, int num_layers);
1535
    virtual void read( const FileNode& fn );
1536
    virtual void write( FileStorage& fs ) const;
1537

  
1538
protected:
1539
	virtual void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
1540

  
1541
    HarrisLaplace harris;
1542
    Params params;
1543
};
1544

  
1545

  
1546
class CV_EXPORTS HarrisAffineFeatureDetector : public FeatureDetector
1547
{
1548
public:
1549
 class CV_EXPORTS Params
1550
    {
1551
    public:
1552
        Params( int numOctaves=6, float corn_thresh=0.01, float DOG_thresh=0.01, int maxCorners=5000, int num_layers=4 );
1553
        
1554

  
1555
        int numOctaves;
1556
        float corn_thresh;
1557
        float DOG_thresh;
1558
        int maxCorners;
1559
        int num_layers;
1560
       
1561
    };
1562
    HarrisAffineFeatureDetector( const HarrisAffineFeatureDetector::Params& params=HarrisAffineFeatureDetector::Params() );
1563
    HarrisAffineFeatureDetector( int numOctaves, float corn_thresh, float DOG_thresh, int maxCorners, int num_layers);
1564
    void detect( const Mat& image, vector<Elliptic_KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
1565
    virtual void read( const FileNode& fn );
1566
    virtual void write( FileStorage& fs ) const;
1567

  
1568
protected:
1569
	virtual void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
1570

  
1571
    HarrisLaplace harris;
1572
    Params params;
1573
};
1574

  
1481 1575
/** \brief A feature detector parameter adjuster, this is used by the DynamicAdaptedFeatureDetector
1482 1576
 *  and is a wrapper for FeatureDetector that allow them to be adjusted after a detection
1483 1577
 */
......
2688 2782
                                         float& repeatability, int& correspCount,
2689 2783
                                         const Ptr<FeatureDetector>& fdetector=Ptr<FeatureDetector>() );
2690 2784

  
2785
CV_EXPORTS void evaluateFeatureDetector( const Mat& img1, const Mat& img2, const Mat& H1to2,
2786
                              vector<Elliptic_KeyPoint>* _keypoints1, vector<Elliptic_KeyPoint>* _keypoints2,
2787
                              float& repeatability, int& correspCount,
2788
                              const Ptr<HarrisAffineFeatureDetector>& _fdetector );
2691 2789
CV_EXPORTS void computeRecallPrecisionCurve( const vector<vector<DMatch> >& matches1to2,
2692 2790
                                             const vector<vector<uchar> >& correctMatches1to2Mask,
2693 2791
                                             vector<Point2f>& recallPrecisionCurve );
......
2780 2878
    Ptr<DescriptorMatcher> dmatcher;
2781 2879
};
2782 2880

  
2881
/*
2882
 * Functions to perform affine adaptation of circular keypoint 
2883
 */
2884
void calcAffineCovariantRegions(const Mat& image, const vector<KeyPoint>& keypoints, vector<Elliptic_KeyPoint>& affRegions, string detector_type);
2885
void calcAffineCovariantDescriptors( const Ptr<DescriptorExtractor>& dextractor, const Mat& img, vector<Elliptic_KeyPoint>& affRegions, Mat& descriptors );
2783 2886
} /* namespace cv */
2784 2887

  
2785 2888
#endif /* __cplusplus */
src/evaluation.cpp (copia locale)
86 86

  
87 87
    static void convert( const vector<KeyPoint>& src, vector<EllipticKeyPoint>& dst );
88 88
    static void convert( const vector<EllipticKeyPoint>& src, vector<KeyPoint>& dst );
89
	static void convert(const vector<Elliptic_KeyPoint>& src, vector<EllipticKeyPoint>& dst);
89 90

  
90 91
    static Mat_<double> getSecondMomentsMatrix( const Scalar& _ellipse );
91 92
    Mat_<double> getSecondMomentsMatrix() const;
......
174 175
    }
175 176
}
176 177

  
178
void EllipticKeyPoint::convert(const vector<Elliptic_KeyPoint>& src, vector<EllipticKeyPoint>& dst)
179
{
180
    if (!src.empty())
181
    {
182
        dst.resize(src.size());
183
        for (size_t i = 0; i < src.size(); i++)
184
        {
185
            
186
            Mat transf = src[i].transf; //square root of second moment matrix
187
            Mat_<float> M(2, 2);
188
            M(0, 0) = transf.at<float> (0, 0);
189
            M(0, 1) = M(1, 0) = transf.at<float> (1, 0);
190
            M(1, 1) = transf.at<float> (1, 1);
191
            M = M.inv() * 3 * src[i].si;
192
            M = M * M;
193
            M = M.inv();
194
            dst[i] = EllipticKeyPoint(src[i].centre, Scalar(M(0, 0), M(1, 0), M(1, 1)));
195
        }
196
    }
197
}
198

  
177 199
void EllipticKeyPoint::calcProjection( const vector<EllipticKeyPoint>& src, const Mat_<double>& H, vector<EllipticKeyPoint>& dst )
178 200
{
179 201
    if( !src.empty() )
......
565 587

  
566 588
    computeRecallPrecisionCurve( *matches1to2, *correctMatches1to2Mask, recallPrecisionCurve );
567 589
}
590

  
591

  
592

  
593
static void calculateRepeatability(const Mat& img1, const Mat& img2, const Mat& H1to2,
594
        const vector<Elliptic_KeyPoint>& _keypoints1, const vector<Elliptic_KeyPoint>& _keypoints2,
595
        float& repeatability, int& correspondencesCount, Mat* thresholdedOverlapMask = 0)
596
{
597
    vector<EllipticKeyPoint> keypoints1, keypoints2, keypoints1t, keypoints2t;
598
    EllipticKeyPoint::convert(_keypoints1, keypoints1);
599
    EllipticKeyPoint::convert(_keypoints2, keypoints2);
600

  
601
    // calculate projections of key points
602
    EllipticKeyPoint::calcProjection(keypoints1, H1to2, keypoints1t);
603

  
604
    Mat H2to1;
605
    invert(H1to2, H2to1);
606
    EllipticKeyPoint::calcProjection(keypoints2, H2to1, keypoints2t);
607
    
608
    float overlapThreshold;
609
    bool ifEvaluateDetectors = thresholdedOverlapMask == 0;
610
    if (ifEvaluateDetectors)
611
    {
612
        overlapThreshold = 1.f - 0.4f;
613

  
614
        // remove key points from outside of the common image part
615
        Size sz1 = img1.size(), sz2 = img2.size();
616
        filterEllipticKeyPointsByImageSize(keypoints1, sz1);
617
        filterEllipticKeyPointsByImageSize(keypoints1t, sz2);
618
        filterEllipticKeyPointsByImageSize(keypoints2, sz2);
619
        filterEllipticKeyPointsByImageSize(keypoints2t, sz1);
620
    } else
621
    {
622
        overlapThreshold = 1.f - 0.5f;
623

  
624
        thresholdedOverlapMask->create((int) keypoints1.size(), (int) keypoints2t.size(), CV_8UC1);
625
        thresholdedOverlapMask->setTo(Scalar::all(0));
626
    }
627
    size_t minCount = min(keypoints1.size(), keypoints2t.size());
628
    
629
    // calculate overlap errors
630
    vector<SIdx> overlaps;
631
    computeOneToOneMatchedOverlaps(keypoints1, keypoints2t, ifEvaluateDetectors, overlaps,
632
            overlapThreshold/*min overlap*/);
633

  
634
    correspondencesCount = -1;
635
    repeatability = -1.f;
636
    if (overlaps.empty())
637
        return;
638

  
639
    if (ifEvaluateDetectors)
640
    {
641
        // regions one-to-one matching
642
        correspondencesCount = (int) overlaps.size();
643
        repeatability = minCount ? (float) correspondencesCount / minCount : -1;
644

  
645
    } else
646
    {
647
        for (size_t i = 0; i < overlaps.size(); i++)
648
        {
649
            int y = overlaps[i].i1;
650
            int x = overlaps[i].i2;
651
            thresholdedOverlapMask->at<uchar> (y, x) = 1;
652
        }
653
    }
654
}
655
void cv::evaluateFeatureDetector(const Mat& img1, const Mat& img2, const Mat& H1to2, vector<
656
        Elliptic_KeyPoint>* _keypoints1, vector<Elliptic_KeyPoint>* _keypoints2,
657
        float& repeatability, int& correspCount, const Ptr<HarrisAffineFeatureDetector>& _fdetector)
658
{
659
    Ptr<HarrisAffineFeatureDetector> fdetector(_fdetector);
660
    vector<Elliptic_KeyPoint> *keypoints1, *keypoints2, buf1, buf2;
661
    keypoints1 = _keypoints1 != 0 ? _keypoints1 : &buf1;
662
    keypoints2 = _keypoints2 != 0 ? _keypoints2 : &buf2;
663

  
664
    if ((keypoints1->empty() || keypoints2->empty()) && fdetector.empty())
665
        CV_Error(CV_StsBadArg, "fdetector must be no empty when keypoints1 or keypoints2 is empty");
666

  
667
    if (keypoints1->empty())
668
        fdetector->detect(img1, *keypoints1);
669
    if (keypoints2->empty())
670
        fdetector->detect(img2, *keypoints2);
671
    
672
    calculateRepeatability(img1, img2, H1to2, *keypoints1, *keypoints2, repeatability, correspCount);
673
}
src/detectors.cpp (copia locale)
132 132
        pos += string("Dynamic").size();
133 133
        fd = new DynamicAdaptedFeatureDetector( AdjusterAdapter::create(detectorType.substr(pos)) );
134 134
    }
135
    else if( !detectorType.compare( "HarrisLaplace" ) )
136
    {
137
        fd = new HarrisLaplaceFeatureDetector();
138
    }
139
    else if( !detectorType.compare( "HarrisAffine" ) )
140
    {
141
        fd = new HarrisAffineFeatureDetector();
142
    }
135 143

  
136 144
    return fd;
137 145
}
......
567 575
    }
568 576
}
569 577

  
578
/*
579
 *  HarrisLaplaceFeatureDetector
580
 */
581
HarrisLaplaceFeatureDetector::Params::Params(int _numOctaves, float _corn_thresh, float _DOG_thresh, int _maxCorners, int _num_layers) :
582
    numOctaves(_numOctaves), corn_thresh(_corn_thresh), DOG_thresh(_DOG_thresh), maxCorners(_maxCorners), num_layers(_num_layers)
583
{}
584
HarrisLaplaceFeatureDetector::HarrisLaplaceFeatureDetector( int numOctaves, float corn_thresh, float DOG_thresh, int maxCorners, int num_layers)
585
  : harris( numOctaves, corn_thresh, DOG_thresh, maxCorners, num_layers)
586
{}
587

  
588
HarrisLaplaceFeatureDetector::HarrisLaplaceFeatureDetector(  const Params& params  )
589
 : harris( params.numOctaves, params.corn_thresh, params.DOG_thresh, params.maxCorners, params.num_layers)
590
 
591
{}
592

  
593
void HarrisLaplaceFeatureDetector::read (const FileNode& fn)
594
{
595
	int numOctaves = fn["numOctaves"];
596
	float corn_thresh = fn["corn_thresh"];
597
	float DOG_thresh = fn["DOG_thresh"];
598
	int maxCorners = fn["maxCorners"];
599
	int num_layers = fn["num_layers"];
600
	
601
    harris = HarrisLaplace( numOctaves, corn_thresh, DOG_thresh, maxCorners,num_layers );
570 602
}
603

  
604
void HarrisLaplaceFeatureDetector::write (FileStorage& fs) const
605
{
606

  
607
    fs << "numOctaves" << harris.numOctaves;
608
    fs << "corn_thresh" << harris.corn_thresh;
609
    fs << "DOG_thresh" << harris.DOG_thresh;
610
    fs << "maxCorners" << harris.maxCorners;
611
    fs << "num_layers" << harris.num_layers;
612

  
613
    
614
}
615

  
616

  
617
void HarrisLaplaceFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
618
{
619
	       
620
	harris.detect(image, keypoints);
621
}
622

  
623
/*
624
 *  HarrisAffineFeatureDetector
625
 */
626
HarrisAffineFeatureDetector::Params::Params(int _numOctaves, float _corn_thresh, float _DOG_thresh, int _maxCorners, int _num_layers) :
627
    numOctaves(_numOctaves), corn_thresh(_corn_thresh), DOG_thresh(_DOG_thresh), maxCorners(_maxCorners), num_layers(_num_layers)
628
{}
629
HarrisAffineFeatureDetector::HarrisAffineFeatureDetector( int numOctaves, float corn_thresh, float DOG_thresh, int maxCorners, int num_layers)
630
  : harris( numOctaves, corn_thresh, DOG_thresh, maxCorners, num_layers)
631
{}
632

  
633
HarrisAffineFeatureDetector::HarrisAffineFeatureDetector(  const Params& params  )
634
 : harris( params.numOctaves, params.corn_thresh, params.DOG_thresh, params.maxCorners, params.num_layers)
635
 
636
{}
637

  
638
void HarrisAffineFeatureDetector::read (const FileNode& fn)
639
{
640
	int numOctaves = fn["numOctaves"];
641
	float corn_thresh = fn["corn_thresh"];
642
	float DOG_thresh = fn["DOG_thresh"];
643
	int maxCorners = fn["maxCorners"];
644
	int num_layers = fn["num_layers"];
645
	
646
    harris = HarrisLaplace( numOctaves, corn_thresh, DOG_thresh, maxCorners,num_layers );
647
}
648

  
649
void HarrisAffineFeatureDetector::write (FileStorage& fs) const
650
{
651

  
652
    fs << "numOctaves" << harris.numOctaves;
653
    fs << "corn_thresh" << harris.corn_thresh;
654
    fs << "DOG_thresh" << harris.DOG_thresh;
655
    fs << "maxCorners" << harris.maxCorners;
656
    fs << "num_layers" << harris.num_layers;
657

  
658
    
659
}
660
void HarrisAffineFeatureDetector::detect( const Mat& image, vector<Elliptic_KeyPoint>& ekeypoints, const Mat& mask ) const
661
{
662
	vector<KeyPoint> keypoints;
663
	harris.detect(image, keypoints);
664
	Mat fimage;
665
    image.convertTo(fimage, CV_32F, 1.f/255);
666
	calcAffineCovariantRegions(fimage, keypoints, ekeypoints, "HarrisLaplace");
667
	}
668

  
669
void HarrisAffineFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& ekeypoints, const Mat& mask ) const
670
{
671
}
672
}
src/affineAdaptation.cpp (revisione 0)
1
/*
2
 * Functions to perform affine adaptation of keypoint and to calculate descriptors of elliptic regions
3
 */
4

  
5
#include "precomp.hpp"
6
#include <opencv2/highgui/highgui.hpp>
7
namespace cv
8
{
9

  
10
void calcDerivatives(const Mat& image, Mat & dx2, Mat & dxy, Mat & dy2, float si, float sd);
11
void calcSecondMomentMatrix(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat& M);
12
bool calcAffineAdaptation(const Mat & image, Elliptic_KeyPoint& keypoint);
13
float selIntegrationScale(const Mat & image, float si, Point c);
14
float selDifferentiationScale(const Mat & image, Mat & Lxm2smooth, Mat & Lxmysmooth, Mat & Lym2smooth, float si, Point c);
15
float calcSecondMomentSqrt(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat& Mk);
16
float normMaxEval(Mat & U, Mat& uVal, Mat& uVect);
17

  
18

  
19
/*
20
 * Calculates second moments matrix in point p
21
 */
22
void calcSecondMomentMatrix(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat & M)
23
{
24
    int x = p.x;
25
    int y = p.y;
26

  
27
    M.create(2, 2, CV_32FC1);
28
    M.at<float> (0, 0) = dx2.at<float> (y, x);
29
    M.at<float> (0, 1) = M.at<float> (1, 0) = dxy.at<float> (y, x);
30
    M.at<float> (1, 1) = dy2.at<float> (y, x);
31
}
32

  
33
/*
34
 * Performs affine adaptation
35
 */
36
bool calcAffineAdaptation(const Mat & fimage, Elliptic_KeyPoint & keypoint)
37
{
38
    Mat_<float> transf(2, 3)/*Trasformation matrix*/,
39
            size(2, 1)/*Image size after transformation*/, 
40
            c(2, 1)/*Transformed point*/, 
41
            p(2, 1) /*Image point*/;
42
            
43
    Mat U = Mat::eye(2, 2, CV_32F) * 1; /*Normalization matrix*/
44

  
45
    Mat warpedImg, Mk, Lxm2smooth, Lym2smooth, Lxmysmooth, img_roi;
46
    float Qinv = 1, q, si = keypoint.si, sd = 0.75 * si;
47
    bool divergence = false, convergence = false;
48
    int i = 0;
49

  
50
    //Coordinates in image
51
    int py = keypoint.centre.y;
52
    int px = keypoint.centre.x;
53

  
54
    //Roi coordinates
55
    int roix, roiy;
56

  
57
    //Coordinates in U-trasformation
58
    int cx = px;
59
    int cy = py;
60
    int cxPr = cx;
61
    int cyPr = cy;
62

  
63
    float radius = keypoint.size / 2 * 1.4;
64
    float half_width, half_height;
65

  
66
    Rect roi;
67
    float ax1, ax2;
68
    double phi = 0;
69
    ax1 = ax2 = keypoint.size / 2;
70
    Mat drawImg;
71

  
72
    //Affine adaptation
73
    while (i <= 10 && !divergence && !convergence)
74
    {
75
        cvtColor(fimage, drawImg, CV_GRAY2RGB);
76
        
77
        //Transformation matrix 
78
        transf.setTo(0);
79
        Mat col0 = transf.col(0);
80
        U.col(0).copyTo(col0);
81
        Mat col1 = transf.col(1);
82
        U.col(1).copyTo(col1);
83
        keypoint.transf = Mat(transf);
84

  
85
        Size_<float> boundingBox;
86
        
87
        double ac_b2 = determinant(U);
88
        boundingBox.width = ceil(U.at<float> (1, 1)/ac_b2  * 3 * si*1.4 );
89
        boundingBox.height = ceil(U.at<float> (0, 0)/ac_b2 * 3 * si*1.4 );
90

  
91
        //Create window around interest point
92
        half_width = std::min((float) std::min(fimage.cols - px-1, px), boundingBox.width);
93
        half_height = std::min((float) std::min(fimage.rows - py-1, py), boundingBox.height);
94
        roix = max(px - (int) boundingBox.width, 0);
95
        roiy = max(py - (int) boundingBox.height, 0);
96
        roi = Rect(roix, roiy, px - roix + half_width+1, py - roiy + half_height+1);
97
               
98
		//create ROI
99
        img_roi = fimage(roi);
100

  
101
        
102
        //Point within the ROI
103
        p(0, 0) = px - roix;
104
        p(1, 0) = py - roiy;
105

  
106
        if (half_width <= 0 || half_height <= 0)
107
            return divergence;
108

  
109
        //Find coordinates of square's angles to find size of warped ellipse's bounding box
110
        float u00 = U.at<float> (0, 0);
111
        float u01 = U.at<float> (0, 1);
112
        float u10 = U.at<float> (1, 0);
113
        float u11 = U.at<float> (1, 1);
114

  
115
        float minx = u01 * img_roi.rows < 0 ? u01 * img_roi.rows : 0;
116
        float miny = u10 * img_roi.cols < 0 ? u10 * img_roi.cols : 0;
117
        float maxx = (u00 * img_roi.cols > u00 * img_roi.cols + u01 * img_roi.rows ? u00
118
                * img_roi.cols : u00 * img_roi.cols + u01 * img_roi.rows) - minx;
119
        float maxy = (u11 * img_roi.rows > u10 * img_roi.cols + u11 * img_roi.rows ? u11
120
                * img_roi.rows : u10 * img_roi.cols + u11 * img_roi.rows) - miny;
121

  
122
        //Shift
123
        transf.at<float> (0, 2) = -minx;
124
        transf.at<float> (1, 2) = -miny;
125
        
126
        /*float min_width = minx >= 0 ? u00 * img_roi.cols - u01 * img_roi.rows : u00 * img_roi.cols
127
                + u01 * img_roi.rows;
128
        float min_height = miny >= 0 ? u11 * img_roi.rows - u10 * img_roi.cols : u10 * img_roi.cols
129
                + u11 * img_roi.rows;*/
130

  
131
        if (maxx >=  2*radius+1 && maxy >=  2*radius+1)
132
        {
133
            //Size of normalized window must be 2*radius
134
            //Transformation
135
            Mat warpedImgRoi;
136
            warpAffine(img_roi, warpedImgRoi, transf, Size(maxx, maxy),INTER_AREA, BORDER_REPLICATE);
137

  
138
            //Point in U-Normalized coordinates
139
            c = U * p;
140
            cx = c(0, 0) - minx;
141
            cy = c(1, 0) - miny;
142

  
143
            
144
            if (warpedImgRoi.rows > 2 * radius+1 && warpedImgRoi.cols > 2 * radius+1)
145
            {
146
                //Cut around normalized patch
147
                roix = std::max(cx - ceil(radius), 0.0);
148
                roiy = std::max(cy - ceil(radius), 0.0);
149
                roi = Rect(roix, roiy,
150
                        cx - roix + std::min(ceil(radius), (double) warpedImgRoi.cols - cx-1)+1,
151
                        cy - roiy + std::min(ceil(radius), (double) warpedImgRoi.rows - cy-1)+1);
152
                warpedImg = warpedImgRoi(roi);
153
                
154
                //Coordinates in cutted ROI
155
                cx = cx - roix;
156
                cy = cy - roiy;
157
            } else
158
                warpedImgRoi.copyTo(warpedImg);
159
                
160
            
161
            //Integration Scale selection
162
            si = selIntegrationScale(warpedImg, si, Point(cx, cy));
163

  
164
            //Differentation scale selection
165
            sd = selDifferentiationScale(warpedImg, Lxm2smooth, Lxmysmooth, Lym2smooth, si,
166
                    Point(cx, cy));
167

  
168
            //Spatial Localization
169
            cxPr = cx; //Previous iteration point in normalized window
170
            cyPr = cy;
171

  
172
            float cornMax = 0;
173
            for (int j = 0; j < 3; j++)
174
            {
175
                for (int t = 0; t < 3; t++)
176
                {
177
                    float dx2 = Lxm2smooth.at<float> (cyPr - 1 + j, cxPr - 1 + t);
178
                    float dy2 = Lym2smooth.at<float> (cyPr - 1 + j, cxPr - 1 + t);
179
                    float dxy = Lxmysmooth.at<float> (cyPr - 1 + j, cxPr - 1 + t);
180
                    float det = dx2 * dy2 - dxy * dxy;
181
                    float tr = dx2 + dy2;
182
                    float cornerness = det - (0.04 * pow(tr, 2));
183
                    if (cornerness > cornMax)
184
                    {
185
                        cornMax = cornerness;
186
                        cx = cxPr - 1 + t;
187
                        cy = cyPr - 1 + j;
188
                    }
189
                }
190
            }
191
            
192
            //Transform point in image coordinates
193
            p(0, 0) = px;
194
            p(1, 0) = py;
195
            //Displacement vector
196
            c(0, 0) = cx - cxPr;
197
            c(1, 0) = cy - cyPr;
198
            //New interest point location in image
199
            p = p + U.inv() * c;
200
            px = p(0, 0);
201
            py = p(1, 0);
202
            
203
            q = calcSecondMomentSqrt(Lxm2smooth, Lxmysmooth, Lym2smooth, Point(cx, cy), Mk);
204

  
205
            float ratio = 1 - q;
206

  
207
            //if ratio == 1 means q == 0 and one axes equals to 0
208
            if (!isnan(ratio) && ratio != 1)
209
            {
210
                //Update U matrix
211
                U = U * Mk;
212

  
213
                Mat uVal, uV;
214
                eigen(U, uVal, uV);
215

  
216
                Qinv = normMaxEval(U, uVal, uV);
217
                
218
                
219
                //Keypoint doesn't converge
220
                if (Qinv >= 6)
221
					divergence = true;
222

  
223
                                   
224
                //Keypoint converges
225
                else if (ratio <= 0.05)
226
                {
227
                    convergence = true;
228

  
229
                    //Set transformation matrix
230
                    transf.setTo(0);
231
                    Mat col0 = transf.col(0);
232
                    U.col(0).copyTo(col0);
233
                    Mat col1 = transf.col(1);
234
                    U.col(1).copyTo(col1);
235
                    keypoint.transf = Mat(transf);
236

  
237
                    ax1 = 1. / std::abs(uVal.at<float> (0, 0)) * 3 * si;
238
                    ax2 = 1. / std::abs(uVal.at<float> (1, 0)) * 3 * si;
239
                    phi = atan(uV.at<float> (1, 0) / uV.at<float> (0, 0)) * (180) / CV_PI;
240
                    keypoint.axes = Size_<float> (ax1, ax2);
241
                    keypoint.phi = phi;
242
                    keypoint.centre = Point(px, py);
243
                    keypoint.si = si;
244
                    keypoint.size = 2 * 3 * si;
245
                    
246
                } else
247
                    radius = 3 * si * 1.4;
248

  
249
            } else divergence = true;
250
            
251
        } else divergence = true;
252
            
253
        ++i;
254
    }
255

  
256
    return convergence;
257
}
258

  
259
/*
260
 * Selects the integration scale that maximize LoG in point c
261
 */
262
float selIntegrationScale(const Mat & image, float si, Point c)
263
{
264
    Mat Lap, L;
265
    int cx = c.x;
266
    int cy = c.y;
267
    float maxLap = 0;
268
    float maxsx = si;
269
    int gsize;
270
    float sigma, sigma_prev = 0;
271

  
272
    image.copyTo(L);
273
    /* Search best integration scale between previous and successive layer
274
     */
275
    for (float u = 0.7; u <= 1.41; u += 0.1)
276
    {
277
        float sik = u * si;
278
        sigma = sqrt(powf(sik, 2) - powf(sigma_prev, 2));
279

  
280
        gsize = ceil(sigma * 3) * 2 + 1;
281

  
282
        GaussianBlur(L, L, Size(gsize, gsize), sigma);
283
        sigma_prev = sik;
284

  
285
        Laplacian(L, Lap, CV_32F, 3);
286

  
287
        float lapVal = sik * sik * std::abs(Lap.at<float> (cy, cx));
288

  
289
        if (u == 0.7)
290
            maxLap = lapVal;
291

  
292
        if (lapVal >= maxLap)
293
        {
294
            maxLap = lapVal;
295
            maxsx = sik;
296

  
297
        }
298

  
299
    }
300
    return maxsx;
301
}
302

  
303
/*
304
 * Calculates second moments matrix square root
305
 */
306
float calcSecondMomentSqrt(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat & Mk)
307
{
308
    Mat M, V, eigVal, Vinv, D;
309

  
310
    calcSecondMomentMatrix(dx2, dxy, dy2, p, M);
311

  
312
    /* *
313
     * M = V * D * V.inv()
314
     * V has eigenvectors as columns
315
     * D is a diagonal Matrix with eigenvalues as elements
316
     * V.inv() is the inverse of V
317
     * */
318

  
319
    eigen(M, eigVal, V);
320
    V = V.t();
321
    Vinv = V.inv();
322

  
323
    float eval1 = eigVal.at<float> (0, 0) = sqrt(eigVal.at<float> (0, 0));
324
    float eval2 = eigVal.at<float> (1, 0) = sqrt(eigVal.at<float> (1, 0));
325

  
326
    D = Mat::diag(eigVal);
327

  
328
    //square root of M
329
    Mk = V * D * Vinv;
330
    //return q isotropic measure
331
    return min(eval1, eval2) / max(eval1, eval2);
332
}
333

  
334
float normMaxEval(Mat & U, Mat & uVal, Mat & uVec)
335
{
336
    /* *
337
     * Decomposition:
338
     * U = V * D * V.inv()
339
     * V has eigenvectors as columns
340
     * D is a diagonal Matrix with eigenvalues as elements
341
     * V.inv() is the inverse of V
342
     * */
343
    uVec = uVec.t();
344
    Mat uVinv = uVec.inv();
345

  
346
    //Normalize min eigenvalue to 1 to expand patch in the direction of min eigenvalue of U.inv()
347
    double uval1 = uVal.at<float> (0, 0);
348
    double uval2 = uVal.at<float> (1, 0);
349

  
350
    if (std::abs(uval1) < std::abs(uval2))
351
    {
352
        uVal.at<float> (0, 0) = 1;
353
        uVal.at<float> (1, 0) = uval2 / uval1;
354

  
355
    } else
356
    {
357
        uVal.at<float> (1, 0) = 1;
358
        uVal.at<float> (0, 0) = uval1 / uval2;
359

  
360
    }
361

  
362
    Mat D = Mat::diag(uVal);
363
    //U normalized
364
    U = uVec * D * uVinv;
365

  
366
    return max(std::abs(uVal.at<float> (0, 0)), std::abs(uVal.at<float> (1, 0))) / min(
367
            std::abs(uVal.at<float> (0, 0)), std::abs(uVal.at<float> (1, 0))); //define the direction of warping
368
}
369

  
370
/*
371
 * Selects diffrentiation scale
372
 */
373
float selDifferentiationScale(const Mat & img, Mat & Lxm2smooth, Mat & Lxmysmooth,
374
        Mat & Lym2smooth, float si, Point c)
375
{
376
    float s = 0.5;
377
    float sdk = s * si;
378
    float sigma_prev = 0, sigma;
379

  
380
    Mat L, dx2, dxy, dy2;
381

  
382
    double qMax = 0;
383

  
384
    //Gaussian kernel size
385
    int gsize;
386
    Size ksize;
387

  
388
    img.copyTo(L);
389

  
390
    while (s <= 0.751)
391
    {
392
        Mat M;
393
        float sd = s * si;
394

  
395
        //Smooth previous smoothed image L
396
        sigma = sqrt(powf(sd, 2) - powf(sigma_prev, 2));
397

  
398
        gsize = ceil(sigma * 3) * 2 + 1;
399

  
400
        GaussianBlur(L, L, Size(gsize, gsize), sigma);
401

  
402
        sigma_prev = sd;
403

  
404
        //X and Y derivatives
405
        Mat Lx, Ly;
406
        Sobel(L, Lx, L.depth(), 1, 0, 1);
407
        Lx = Lx * sd;
408
        Sobel(L, Ly, L.depth(), 0, 1, 1);
409
        Ly = Ly * sd;
410

  
411
        //Size of gaussian kernel
412
        gsize = ceil(si * 3) * 2 + 1;
413
        ksize = Size(gsize, gsize);
414

  
415
        Mat Lxm2 = Lx.mul(Lx);
416
        GaussianBlur(Lxm2, dx2, ksize, si);
417

  
418
        Mat Lym2 = Ly.mul(Ly);
419
        GaussianBlur(Lym2, dy2, ksize, si);
420

  
421
        Mat Lxmy = Lx.mul(Ly);
422
        GaussianBlur(Lxmy, dxy, ksize, si);
423

  
424
        calcSecondMomentMatrix(dx2, dxy, dy2, Point(c.x, c.y), M);
425

  
426
        //calc eigenvalues
427
        Mat eval;
428
        eigen(M, eval);
429
        double eval1 = std::abs(eval.at<float> (0, 0));
430
        double eval2 = std::abs(eval.at<float> (1, 0));
431
        double q = min(eval1, eval2) / max(eval1, eval2);
432

  
433
        if (q >= qMax)
434
        {
435
            qMax = q;
436
            sdk = sd;
437
            dx2.copyTo(Lxm2smooth);
438
            dxy.copyTo(Lxmysmooth);
439
            dy2.copyTo(Lym2smooth);
440

  
441
        }
442

  
443
        s += 0.05;
444
    }
445

  
446
    return sdk;
447
}
448

  
449
void calcAffineCovariantRegions(const Mat & image, const vector<KeyPoint> & keypoints,
450
        vector<Elliptic_KeyPoint> & affRegions, string detector_type)
451
{
452

  
453
    for (size_t i = 0; i < keypoints.size(); ++i)
454
    {
455
        KeyPoint kp = keypoints[i];
456
        Elliptic_KeyPoint ex(kp.pt, 0, Size_<float> (kp.size / 2, kp.size / 2), kp.size,
457
                kp.size / 6);
458

  
459
        if (calcAffineAdaptation(image, ex))        
460
            affRegions.push_back(ex);
461
        
462
    }
463
    //Erase similar keypoint
464
    float maxDiff = 4;
465
    Mat colorimg;
466
    for (size_t i = 0; i < affRegions.size(); i++)
467
        {
468
            Elliptic_KeyPoint kp1 = affRegions[i];
469
            for (size_t j = i+1; j < affRegions.size(); j++){
470

  
471
                Elliptic_KeyPoint kp2 = affRegions[j];
472
                
473
                if(norm(kp1.centre-kp2.centre)<=maxDiff){
474
                    double phi1, phi2;
475
                    Size axes1, axes2;
476
                    double si1, si2;
477
                    phi1 = kp1.phi;
478
                    phi2 = kp2.phi;
479
                    axes1 = kp1.axes;
480
                    axes2 = kp2.axes;
481
                    si1 = kp1.si;
482
                    si2 = kp2.si;
483
                    if(std::abs(phi1-phi2)<15 && std::max(si1,si2)/std::min(si1,si2)<1.4 && axes1.width-axes2.width<5 && axes1.height-axes2.height<5){
484
                        affRegions.erase(affRegions.begin()+j);
485
                        j--;                        
486
                    }
487
                    
488
                }
489
                    
490
                
491

  
492
                
493
            }
494

  
495
        }
496
    
497
}
498

  
499
void calcAffineCovariantDescriptors(const Ptr<DescriptorExtractor>& dextractor, const Mat& img,
500
        vector<Elliptic_KeyPoint>& affRegions, Mat& descriptors)
501
{
502

  
503
    assert(!affRegions.empty());
504
    int size = dextractor->descriptorSize();
505
    int type = dextractor->descriptorType();
506
    descriptors = Mat(Size(size, affRegions.size()), type);
507
    descriptors.setTo(0);
508

  
509
    int i = 0;
510

  
511
    for (vector<Elliptic_KeyPoint>::iterator it = affRegions.begin(); it < affRegions.end(); ++it)
512
    {
513
        Point p = it->centre;
514

  
515
        Mat_<float> size(2, 1);
516
        size(0, 0) = size(1, 0) = it->size;
517

  
518
        //U matrix
519
        Mat transf = it->transf;
520
        Mat_<float> U(2, 2);
521
        U.setTo(0);
522
        Mat col0 = U.col(0);
523
        transf.col(0).copyTo(col0);
524
        Mat col1 = U.col(1);
525
        transf.col(1).copyTo(col1);
526

  
527
        float radius = it->size / 2;
528
        float si = it->si;
529
        
530
        Size_<float> boundingBox;
531
        
532
        double ac_b2 = determinant(U);
533
        boundingBox.width = ceil(U.at<float> (1, 1)/ac_b2  * 3 * si );
534
        boundingBox.height = ceil(U.at<float> (0, 0)/ac_b2 * 3 * si );
535

  
536
        //Create window around interest point
537
        float half_width = std::min((float) std::min(img.cols - p.x-1, p.x), boundingBox.width);
538
        float half_height = std::min((float) std::min(img.rows - p.y-1, p.y), boundingBox.height);
539
        float roix = max(p.x - (int) boundingBox.width, 0);
540
        float roiy = max(p.y - (int) boundingBox.height, 0);
541
        Rect roi = Rect(roix, roiy, p.x - roix + half_width+1, p.y - roiy + half_height+1);
542
                
543
        Mat img_roi = img(roi);
544

  
545
        size(0, 0) = img_roi.cols;
546
        size(1, 0) = img_roi.rows;
547

  
548
        size = U * size;
549

  
550
        Mat transfImgRoi, transfImg;
551
        warpAffine(img_roi, transfImgRoi, transf, Size(ceil(size(0, 0)), ceil(size(1, 0))),
552
                INTER_AREA, BORDER_DEFAULT);
553
		
554
        
555
        Mat_<float> c(2, 1); //Transformed point
556
        Mat_<float> pt(2, 1); //Image point
557
        //Point within the Roi
558
        pt(0, 0) = p.x - roix;
559
        pt(1, 0) = p.y - roiy;
560

  
561
        //Point in U-Normalized coordinates
562
        c = U * pt;
563
        float cx = c(0, 0);
564
        float cy = c(1, 0);
565
        
566

  
567
        //Cut around point to have patch of 2*keypoint->size
568

  
569
        roix = std::max(cx - radius, 0.f);
570
        roiy = std::max(cy - radius, 0.f);
571

  
572
        roi = Rect(roix, roiy, std::min(cx - roix + radius, size(0, 0)),
573
                std::min(cy - roiy + radius, size(1, 0)));
574
        transfImg = transfImgRoi(roi);
575

  
576
        cx = c(0, 0) - roix;
577
        cy = c(1, 0) - roiy;
578

  
579
        Mat tmpDesc;
580
        KeyPoint kp(Point(cx, cy), it->size);
581

  
582
        vector<KeyPoint> k(1, kp);
583

  
584
        transfImg.convertTo(transfImg, CV_8U);
585
        dextractor->compute(transfImg, k, tmpDesc);
586

  
587
        for (int j = 0; j < tmpDesc.cols; j++)
588
        {
589
            descriptors.at<float> (i, j) = tmpDesc.at<float> (0, j);
590
        }
591

  
592
        i++;
593

  
594
    }
595

  
596
}
597
}