forked from BloodAxe/OpenCV-Features-Comparison
/
AlgorithmEstimation.cpp
129 lines (98 loc) · 3.42 KB
/
AlgorithmEstimation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "AlgorithmEstimation.hpp"
bool computeMatchesDistanceStatistics(const Matches& matches, float& meanDistance, float& stdDev)
{
if (matches.empty())
return false;
std::vector<float> distances(matches.size());
for (size_t i=0; i<matches.size(); i++)
distances[i] = matches[i].distance;
cv::Scalar mean, dev;
cv::meanStdDev(distances, mean, dev);
meanDistance = static_cast<float>(mean.val[0]);
stdDev = static_cast<float>(dev.val[0]);
return false;
}
void ratioTest(const std::vector<Matches>& knMatches, float maxRatio, Matches& goodMatches)
{
goodMatches.clear();
for (size_t i=0; i< knMatches.size(); i++)
{
const cv::DMatch& best = knMatches[i][0];
const cv::DMatch& good = knMatches[i][1];
assert(best.distance <= good.distance);
float ratio = (best.distance / good.distance);
if (ratio <= maxRatio)
{
goodMatches.push_back(best);
}
}
}
bool performEstimation
(
const FeatureAlgorithm& alg,
const ImageTransformation& transformation,
const cv::Mat& sourceImage,
std::vector<FrameMatchingStatistics>& stat
)
{
Keypoints sourceKp;
Descriptors sourceDesc;
cv::Mat gray;
if (sourceImage.channels() == 3)
cv::cvtColor(sourceImage, gray, CV_BGR2GRAY);
else if (sourceImage.channels() == 4)
cv::cvtColor(sourceImage, gray, CV_BGRA2GRAY);
else if(sourceImage.channels() == 1)
gray = sourceImage;
if (!alg.extractFeatures(gray, sourceKp, sourceDesc))
return false;
std::vector<float> x = transformation.getX();
stat.resize(x.size());
const int count = x.size();
cv::Mat transformedImage;
Keypoints resKpReal;
Descriptors resDesc;
Matches matches;
// To convert ticks to milliseconds
const double toMsMul = 1000. / cv::getTickFrequency();
#pragma omp parallel for private(transformedImage, resKpReal, resDesc, matches)
for (int i = 0; i < count; i++)
{
float arg = x[i];
FrameMatchingStatistics& s = stat[i];
transformation.transform(arg, gray, transformedImage);
int64 start = cv::getTickCount();
alg.extractFeatures(transformedImage, resKpReal, resDesc);
// Initialize required fields
s.isValid = resKpReal.size() > 0;
s.argumentValue = arg;
if (!s.isValid)
continue;
if (alg.knMatchSupported)
{
std::vector<Matches> knMatches;
alg.matchFeatures(sourceDesc, resDesc, 2, knMatches);
ratioTest(knMatches, 0.75, matches);
// Compute percent of false matches that were rejected by ratio test
s.ratioTestFalseLevel = (float)(knMatches.size() - matches.size()) / (float) knMatches.size();
}
else
{
alg.matchFeatures(sourceDesc, resDesc, matches);
}
int64 end = cv::getTickCount();
Matches correctMatches;
cv::Mat homography;
bool homographyFound = ImageTransformation::findHomography(sourceKp, resKpReal, matches, correctMatches, homography);
// Some simple stat:
s.isValid = homographyFound;
s.totalKeypoints = resKpReal.size();
s.consumedTimeMs = (end - start) * toMsMul;
// Compute overall percent of matched keypoints
s.percentOfMatches = (float) matches.size() / (float)(std::min(sourceKp.size(), resKpReal.size()));
s.correctMatchesPercent = (float) correctMatches.size() / (float)matches.size();
// Compute matching statistics
computeMatchesDistanceStatistics(correctMatches, s.meanDistance, s.stdDevDistance);
}
return true;
}