1
#include <opencv2/features2d.hpp>
2
#include <opencv2/videoio.hpp>
3
#include <opencv2/opencv.hpp>
8
#include "stats.h" // Stats structure definition
9
#include "utils.h" // Drawing and printing functions
14
const double akaze_thresh = 3e-4; // AKAZE detection threshold set to locate about 1000 keypoints
15
const double ransac_thresh = 2.5f; // RANSAC inlier threshold
16
const double nn_match_ratio = 0.8f; // Nearest-neighbour matching ratio
17
const int bb_min_inliers = 100; // Minimal number of inliers to draw bounding box
18
const int stats_update_period = 10; // On-screen statistics are updated every 10 frames
23
Tracker(Ptr<Feature2D> _detector, Ptr<DescriptorMatcher> _matcher) :
28
void setFirstFrame(const Mat frame, vector<Point2f> bb, string title, Stats& stats);
29
Mat process(const Mat frame, Stats& stats);
30
Ptr<Feature2D> getDetector() {
34
Ptr<Feature2D> detector;
35
Ptr<DescriptorMatcher> matcher;
36
Mat first_frame, first_desc;
37
vector<KeyPoint> first_kp;
38
vector<Point2f> object_bb;
41
void Tracker::setFirstFrame(const Mat frame, vector<Point2f> bb, string title, Stats& stats)
43
first_frame = frame.clone();
44
detector->detectAndCompute(first_frame, noArray(), first_kp, first_desc);
45
stats.keypoints = (int)first_kp.size();
46
drawBoundingBox(first_frame, bb);
47
putText(first_frame, title, Point(0, 60), FONT_HERSHEY_PLAIN, 5, Scalar::all(0), 4);
51
Mat Tracker::process(const Mat frame, Stats& stats)
55
detector->detectAndCompute(frame, noArray(), kp, desc);
56
stats.keypoints = (int)kp.size();
58
vector< vector<DMatch> > matches;
59
vector<KeyPoint> matched1, matched2;
60
matcher->knnMatch(first_desc, desc, matches, 2);
61
for(unsigned i = 0; i < matches.size(); i++) {
62
if(matches[i][0].distance < nn_match_ratio * matches[i][1].distance) {
63
matched1.push_back(first_kp[matches[i][0].queryIdx]);
64
matched2.push_back( kp[matches[i][0].trainIdx]);
67
stats.matches = (int)matched1.size();
69
Mat inlier_mask, homography;
70
vector<KeyPoint> inliers1, inliers2;
71
vector<DMatch> inlier_matches;
72
if(matched1.size() >= 4) {
73
homography = findHomography(Points(matched1), Points(matched2),
74
RANSAC, ransac_thresh, inlier_mask);
77
if(matched1.size() < 4 || homography.empty()) {
79
hconcat(first_frame, frame, res);
84
for(unsigned i = 0; i < matched1.size(); i++) {
85
if(inlier_mask.at<uchar>(i)) {
86
int new_i = static_cast<int>(inliers1.size());
87
inliers1.push_back(matched1[i]);
88
inliers2.push_back(matched2[i]);
89
inlier_matches.push_back(DMatch(new_i, new_i, 0));
92
stats.inliers = (int)inliers1.size();
93
stats.ratio = stats.inliers * 1.0 / stats.matches;
95
vector<Point2f> new_bb;
96
perspectiveTransform(object_bb, new_bb, homography);
97
Mat frame_with_bb = frame.clone();
98
if(stats.inliers >= bb_min_inliers) {
99
drawBoundingBox(frame_with_bb, new_bb);
102
drawMatches(first_frame, inliers1, frame_with_bb, inliers2,
104
Scalar(255, 0, 0), Scalar(255, 0, 0));
108
int main(int argc, char **argv)
111
cerr << "Usage: " << endl <<
112
"akaze_track input_path output_path bounding_box" << endl;
115
VideoCapture video_in(argv[1]);
116
VideoWriter video_out(argv[2],
117
(int)video_in.get(CAP_PROP_FOURCC),
118
(int)video_in.get(CAP_PROP_FPS),
119
Size(2 * (int)video_in.get(CAP_PROP_FRAME_WIDTH),
120
2 * (int)video_in.get(CAP_PROP_FRAME_HEIGHT)));
122
if(!video_in.isOpened()) {
123
cerr << "Couldn't open " << argv[1] << endl;
126
if(!video_out.isOpened()) {
127
cerr << "Couldn't open " << argv[2] << endl;
132
FileStorage fs(argv[3], FileStorage::READ);
133
if(fs["bounding_box"].empty()) {
134
cerr << "Couldn't read bounding_box from " << argv[3] << endl;
137
fs["bounding_box"] >> bb;
139
Stats stats, akaze_stats, orb_stats;
140
Ptr<AKAZE> akaze = AKAZE::create();
141
akaze->setThreshold(akaze_thresh);
142
Ptr<ORB> orb = ORB::create();
143
orb->setMaxFeatures(stats.keypoints);
144
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
145
Tracker akaze_tracker(akaze, matcher);
146
Tracker orb_tracker(orb, matcher);
150
akaze_tracker.setFirstFrame(frame, bb, "AKAZE", stats);
151
orb_tracker.setFirstFrame(frame, bb, "ORB", stats);
153
Stats akaze_draw_stats, orb_draw_stats;
154
int frame_count = (int)video_in.get(CAP_PROP_FRAME_COUNT);
155
Mat akaze_res, orb_res, res_frame;
156
for(int i = 1; i < frame_count; i++) {
157
bool update_stats = (i % stats_update_period == 0);
160
akaze_res = akaze_tracker.process(frame, stats);
161
akaze_stats += stats;
163
akaze_draw_stats = stats;
166
orb->setMaxFeatures(stats.keypoints);
167
orb_res = orb_tracker.process(frame, stats);
170
orb_draw_stats = stats;
173
drawStatistics(akaze_res, akaze_draw_stats);
174
drawStatistics(orb_res, orb_draw_stats);
175
vconcat(akaze_res, orb_res, res_frame);
176
video_out << res_frame;
177
cout << i << "/" << frame_count - 1 << endl;
179
akaze_stats /= frame_count - 1;
180
orb_stats /= frame_count - 1;
181
printStatistics("AKAZE", akaze_stats);
182
printStatistics("ORB", orb_stats);