feature2d.diff
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 |
} |