forked from FabianGoettl/slam-prototype
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmy_slam_tracking.cpp
More file actions
330 lines (259 loc) · 8.27 KB
/
my_slam_tracking.cpp
File metadata and controls
330 lines (259 loc) · 8.27 KB
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#include "my_slam_tracking.h"
// Ratio to the second neighbor to consider a good match.
#define RATIO 0.6
// Max z-value (depth in mm)
// 40*stereobaseline is usually a good value
#define MAX_Z 3800
using namespace cv;
using namespace std;
namespace slam {
TrackingSharedData::TrackingSharedData() :
is_data_new(false),
is_tracking_enabled(true),
base_rgb(new cv::Mat3b(480, 640)),
//base_pointmap(new cv::Mat3f(480, 640)),
active_rgb(new cv::Mat3b(480, 640)),
//active_depth(new cv::Mat1s(480, 640)),
base_R(1, 0, 0, 0, 1, 0, 0, 0, 1),
base_T(0, 0, 0)
{
}
TrackingSharedData::~TrackingSharedData() {
delete base_rgb;
//delete base_pointmap;
delete active_rgb;
//delete active_depth;
}
/**
Matches new ORB features with tracks
*/
void TrackingModule::match_features(const std::list<FeatureTrack> &tracks, const cv::Mat &new_descriptors, std::vector<int> &match_idx) {
// Create a FlannMatcher based on values provided in docs
FlannBasedMatcher matcher(new cv::flann::LshIndexParams(12, 20, 2));
vector<Mat> train_vector;
train_vector.push_back(new_descriptors);
matcher.add(train_vector);
match_idx.resize(tracks.size());
int match_count = 0;
list<slam::FeatureTrack>::const_iterator track_it;
int i;
for (i = 0, track_it = tracks.begin(); track_it != tracks.end(); i++, track_it++) {
vector<vector<DMatch>> matches;
matcher.knnMatch(track_it->descriptor, matches, 2);
if (matches[0].size() >= 2) {
// Do a second neighbor ratio test
float best_dist = matches[0][0].distance;
float next_dist = matches[0][1].distance;
if (best_dist < next_dist * RATIO) {
match_idx[i] = matches[0][0].trainIdx;
match_count++;
}
else {
match_idx[i] = -1;
}
}
}
cout << "Matched features:" << match_count << endl;
}
void TrackingModule::update_tracks(std::list<FeatureTrack> &tracks, const std::vector<cv::KeyPoint> &feature_points,
const cv::Mat &feature_descriptors, std::vector<int> &match_idx, std::vector<cv::Point3f>& pnts3D) {
std::list<FeatureTrack>::iterator track_it;
int i, updated = 0, missed = 0;
for (i = 0, track_it = tracks.begin(); track_it != tracks.end(); i++, track_it++) {
int j = match_idx[i];
if (j >= 0) {
Point3d point = pnts3D[j];
if (point.x != 0 && point.y != 0 && point.z != 0) {
track_it->missed_frames = 0;
track_it->active_position = feature_points[j].pt;
track_it->active_position_3d = pnts3D[j];
feature_descriptors.row(j).copyTo(track_it->descriptor);
updated++;
continue;
}
}
// If not updated yet
track_it->missed_frames++;
missed++;
}
cout << "Updated Tracks:" << updated << " Missed:" << missed;
// Delete tracks
tracks.remove_if(TrackingModule::is_track_stale);
}
bool TrackingModule::is_track_stale(const FeatureTrack &track) {
return track.missed_frames > 10;
}
float TrackingModule::get_median_feature_movement(const std::list<FeatureTrack> &tracks) {
std::vector<float> vals;
std::list<FeatureTrack>::const_iterator track_it;
for (track_it = tracks.begin(); track_it != tracks.end(); track_it++) {
if (track_it->missed_frames == 0) {
// Diff. of base and active position
vals.push_back(fabs(track_it->base_position.x - track_it->active_position.x) +
fabs(track_it->base_position.y - track_it->active_position.y));
}
}
if (vals.empty())
return 0;
else {
int n = vals.size() / 2;
// Sort vector
std::nth_element(vals.begin(), vals.begin() + n, vals.end());
return vals[n];
}
}
void TrackingModule::transformation_from_tracks(const std::list<FeatureTrack> &tracks, cv::Matx33f &R, cv::Matx31f &T) {
std::list<FeatureTrack>::const_iterator track_it;
cv::Mat1f X(0, 3), Y(0, 3);
X.reserve(tracks.size());
Y.reserve(tracks.size());
for (track_it = tracks.begin(); track_it != tracks.end(); track_it++) {
if (track_it->missed_frames != 0)
continue;
const cv::Point3f &base_point = track_it->base_position_3d;
if (base_point.z <= 0)
continue;
const cv::Point3f &active_point = track_it->active_position_3d;
if (active_point.z <= 0)
continue;
// Add new row to matrices
int i = X.rows;
X.resize(i + 1);
X(i, 0) = base_point.x;
X(i, 1) = base_point.y;
X(i, 2) = base_point.z;
Y.resize(i + 1);
Y(i, 0) = active_point.x;
Y(i, 1) = active_point.y;
Y(i, 2) = active_point.z;
}
if (X.rows > 0 && Y.rows)
ransac_transformation(X, Y, R, T);
}
void TrackingModule::ransac_transformation(const cv::Mat1f &X, const cv::Mat1f &Y, cv::Matx33f &R, cv::Matx31f &T) {
const int max_iterations = 200;
const int min_support = 3;
const float inlier_error_threshold = 0.2f * 1000;
const int pcount = X.rows;
cv::RNG rng;
cv::Mat1f Xk(min_support, 3), Yk(min_support, 3);
cv::Matx33f Rk;
cv::Matx31f Tk;
std::vector<int> best_inliers;
for (int k = 0; k < max_iterations; k++) {
// Select random points
for (int i = 0; i < min_support; i++) {
int idx = rng(pcount);
Xk(i, 0) = X(idx, 0);
Xk(i, 1) = X(idx, 1);
Xk(i, 2) = X(idx, 2);
Yk(i, 0) = Y(idx, 0);
Yk(i, 1) = Y(idx, 1);
Yk(i, 2) = Y(idx, 2);
}
// Get orientation
absolute_orientation(Xk, Yk, Rk, Tk);
// Get error
std::vector<int> inliers;
for (int i = 0; i < pcount; i++) {
float a, b, c, errori;
cv::Matx31f py, pyy;
py(0) = Y(i, 0);
py(1) = Y(i, 1);
py(2) = Y(i, 2);
pyy = Rk*py + T;
a = pyy(0) - X(i, 0);
b = pyy(1) - X(i, 1);
c = pyy(2) - X(i, 2);
errori = sqrt(a*a + b*b + c*c);
if (errori < inlier_error_threshold) {
inliers.push_back(i);
}
}
if (inliers.size() > best_inliers.size()) {
best_inliers = inliers;
}
}
std::cout << "Inlier count: " << best_inliers.size() << "/" << pcount << endl;
// Do final estimation with inliers
Xk.resize(best_inliers.size());
Yk.resize(best_inliers.size());
for (unsigned int i = 0; i < best_inliers.size(); i++) {
int idx = best_inliers[i];
Xk(i, 0) = X(idx, 0);
Xk(i, 1) = X(idx, 1);
Xk(i, 2) = X(idx, 2);
Yk(i, 0) = Y(idx, 0);
Yk(i, 1) = Y(idx, 1);
Yk(i, 2) = Y(idx, 2);
}
absolute_orientation(Xk, Yk, R, T);
}
void TrackingModule::absolute_orientation(cv::Mat1f &X, cv::Mat1f &Y, cv::Matx33f &R, cv::Matx31f &T) {
cv::Matx31f meanX(0, 0, 0), meanY(0, 0, 0);
int point_count = X.rows;
// Calculate mean
for (int i = 0; i < point_count; i++) {
meanX(0) += X(i, 0);
meanX(1) += X(i, 1);
meanX(2) += X(i, 2);
meanY(0) += Y(i, 0);
meanY(1) += Y(i, 1);
meanY(2) += Y(i, 2);
}
meanX *= 1.0f / point_count;
meanY *= 1.0f / point_count;
// Subtract mean
for (int i = 0; i < point_count; i++) {
X(i, 0) -= meanX(0);
X(i, 1) -= meanX(1);
X(i, 2) -= meanX(2);
Y(i, 0) -= meanY(0);
Y(i, 1) -= meanY(1);
Y(i, 2) -= meanY(2);
}
// Rotation
cv::Mat1f A;
A = Y.t() * X;
cv::SVD svd(A);
cv::Mat1f Rmat;
Rmat = svd.vt.t() * svd.u.t();
Rmat.copyTo(R);
// Translation
T = meanX - R*meanY;
}
void TrackingModule::triangulate_matches(vector<DMatch>& matches, const vector<KeyPoint>&keypoints1, const vector<KeyPoint>& keypoints2,
Mat& cam1P, Mat& cam2P, vector<Point3f>& pnts3D)
{
// Convert keypoints into Point2f
vector<cv::Point2f> points1, points2;
int i = 0;
for (auto it = matches.begin(); it != matches.end(); ++it)
{
// Get the position of left keypoints
float xl = keypoints1[it->queryIdx].pt.x;
float yl = keypoints1[it->queryIdx].pt.y;
points1.push_back(Point2f(xl, yl));
// Get the position of right keypoints
float xr = keypoints2[it->trainIdx].pt.x;
float yr = keypoints2[it->trainIdx].pt.y;
points2.push_back(Point2f(xr, yr));
i++;
}
Mat pnts3DMat;
cv::triangulatePoints(cam1P, cam2P, points1, points2, pnts3DMat);
assert(pnts3DMat.cols == keypoints1.size());
for (int x = 0; x < pnts3DMat.cols; x++) {
float W = pnts3DMat.at<float>(3, x);
float Z = pnts3DMat.at<float>(2, x) / W; /// 1000;
if (fabs(Z - MAX_Z) < FLT_EPSILON || fabs(Z) > MAX_Z || Z < 0) {
pnts3D.push_back(Point3f(0, 0, 0)); // Push empty point TODO: replace with lookup table?
continue;
}
float X = pnts3DMat.at<float>(0, x) / W; /// 1000;
float Y = pnts3DMat.at<float>(1, x) / W; /// 1000;
pnts3D.push_back(Point3f(X, Y, Z));
}
assert(pnts3D.size() == keypoints1.size());
}
};