-
Notifications
You must be signed in to change notification settings - Fork 0
/
traj_match_direct.cpp
454 lines (362 loc) · 15.7 KB
/
traj_match_direct.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
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
/////////////////////////////////
/////// name: g2o_trajOpt ///////
/////// status: building ////////
/////////////////////////////////
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <cmath>
#include "/usr/include/boost/algorithm/string.hpp" // temp usage.
#include <Eigen/Core>
#include <Eigen/Dense>
#include "g2o/types/slam2d/vertex_point_xy.h"
#include "g2o/types/slam2d/vertex_se2.h"
#include "g2o/types/slam2d/edge_pointxy.h"
#include "g2o/types/slam2d/edge_se2_pointxy_offset.h"
#include "g2o/core/sparse_optimizer.h"
#include "g2o/core/block_solver.h"
#include "g2o/core/optimization_algorithm_levenberg.h"
#include "g2o/solvers/cholmod/linear_solver_cholmod.h"
#include "g2o/solvers/eigen/linear_solver_eigen.h"
using namespace std;
using namespace Eigen;
/////////////////////////////////////////////////////////////////////////
/// The function to calculate tranform matrix between two trajactory. ///
Matrix3d calculate_transform(Vector2d v1n, Vector2d v2n, Vector2d v1o, Vector2d v2o){
Vector2d _v1n = v1n, _v2n = v2n, _v1o = v1o, _v2o = v2o;
double _cos, _sin, _tx, _ty;
Matrix3d _coeff;
Vector3d _result;
Vector3d _solver;
// v1 means the first cross point. v2 means the second cross point.
// (0) means vector.x || (1) means vector.y
// n refers to new, means the new traj that need to be tranformed.
// o refers to old, means the old traj that should be tranformed to.
_coeff <<
_v1n(0) * _v1n(0) + _v1n(1) * _v1n(1), _v1n(0), _v1n(1),
_v2n(0) * _v2n(0) + _v2n(1) * _v2n(1), _v2n(0), _v2n(1),
_v1n(0) * _v2n(0) + _v1n(1) * _v2n(1), _v1n(0), _v2n(1);
_result <<
_v1n(0) * _v1o(0) + _v1n(1) * _v1o(1),
_v2n(0) * _v2o(0) + _v2n(1) * _v2o(1),
_v1n(0) * _v2o(0) + _v1o(1) * _v2n(1);
_solver = _coeff.colPivHouseholderQr().solve(_result);
_cos = _solver(0);
_tx = _solver(1);
_ty = _solver(2);
_sin = ( -_v1o(0) + _v1n(0) * _cos + _tx) / _v1n(1);
cerr << "cos= " << _cos << endl;
cerr << "tx= " << _tx << endl;
cerr << "ty= " << _ty << endl;
Matrix3d _tranform;
_tranform <<
_cos, -_sin, _tx,
_sin, _cos, _ty,
0, 0, 1;
return _tranform;
}
/////////////////////////////////////////////////////
/// This function is used to return the reference ///
/// of all combinations in a container. /////////////
vector<int> combine2(int top, int size, vector<int> memory){
if(size <= 1) { return memory; }
for(int i = 0; i < (size - 1); i++){
memory.push_back( i / (size - 1) + top - size);
memory.push_back( i % (size - 1) + 1 + top - size);
}
memory = combine2(top, size - 1, memory);
return memory;
}
/////////////////////////
/// Pre_define param. ///
const int tr_num = 80;
const int loops_each_traj = 6;
int main(int argc, char **argv) {
/////////////////////////////////////
/// Load all trajectories data. ///
vector<Vector2d> poses;
int* pose_sum = new int[tr_num];
int* traj_size = new int[tr_num];
int count = 0;
int diff = 0;
for(int i = 0; i < tr_num; i++){
stringstream intostr;
string traj_name, traj_index;
intostr << (i + 1); // Need to fix for different read.
intostr >> traj_index;
traj_name = "../data/traj" + traj_index + ".txt";
ifstream f(traj_name);
while(!f.eof()){
int index = 0;
float x = 0, y = 0;
f >> index >> x >> y;
if(!f.good() || index == 0) break;
poses.push_back(Vector2d(x, y));
count ++;
}
if(i > 0) diff = count - pose_sum[i - 1];
else diff = count;
*(pose_sum + i) = count;
*(traj_size + i) = diff;
cout << "Traj pose number: " << diff << endl;
cout << "Total pose number: " << count << endl;
}
///////////////////////
/// Load loop data. ///
string message;
ifstream loop_file("../data/loops.txt");
// Stored data. //
vector<int> loopIndex; // Store loop points.
vector<vector<int>> globeIndexList; // Store loop points' corresponding global IDs in all trajectories.
int loop_of_traj[tr_num][loops_each_traj]; // Store loop points in each traj.
int loopref_of_traj[tr_num][loops_each_traj]; // Store loop reference in each traj.
// Temp data. //
vector<string> temp, lmGTID, lmIndex; // temp loop points & global ID container.
int loop_check[loops_each_traj]; // to find the reference of loop points in loopIndex.
int tr_n = 0; // to check current reading trajactory.
int lookup = 0; // to check if current traj is the 1st among 10.
while(getline(loop_file, message)){
boost::split(temp, message, boost::is_any_of(":"));
boost::split(lmGTID, temp[2], boost::is_any_of(" "));
boost::split(lmIndex, temp[3], boost::is_any_of(" "));
if(lmGTID.size() != loops_each_traj || lmIndex.size() != loops_each_traj)
cerr << "Insufficient loop points." << endl;
// Construct loop point list. //
for(int i = 0; i < loops_each_traj; i++){
int int_ID = atoi(lmGTID[i].c_str());
// When starting, the loopIndex is blank. //
if(loopIndex.empty()){
loopIndex.push_back(int_ID);
vector<int> temp_vec; // Need to initialize global index as well.
globeIndexList.push_back(temp_vec);
}
// Assign new index if found. //
else{
vector<int>::iterator iter = find(
loopIndex.begin(), loopIndex.end(), int_ID);
if(iter == loopIndex.end()){
loopIndex.push_back(int_ID);
vector<int> temp_vec; // Need to initialize global index as well.
globeIndexList.push_back(temp_vec);
}
}
loop_check[i] = int_ID;
}
// copy(loopIndex.begin(), loopIndex.end(),
// ostream_iterator<int>(cout, "\n")); //for debugging.
// Assign global ID to the corresponding loop point. //
for(int i = 0; i < loops_each_traj; i++){
int loop_ref = 0;
while(loopIndex[loop_ref] != loop_check[i]) loop_ref++;
int int_ID = atoi(lmIndex[i].c_str());
int globeID = (*(pose_sum + tr_n)) - (*(traj_size + tr_n)) + int_ID - 1;
globeIndexList[loop_ref].push_back(globeID);
vector<int>::iterator end = globeIndexList[loop_ref].end();
cerr << "The " << i + 1 << "th loop point for lmGTID for traj " << tr_n + 1 << " is " << loopIndex[loop_ref] << endl;
cerr << "The " << i + 1 << "th loop point for lmIndex for traj " << tr_n + 1 << " is " << *(end - 1) << endl;
}
for(int i = 0; i < loops_each_traj; i++){
loop_of_traj[tr_n][i] = atoi(lmGTID[i].c_str());
loopref_of_traj[tr_n][i] = atoi(lmIndex[i].c_str());
}
tr_n++;
}
loop_file.close();
//////////////////////////////////////////////
/// Move trajs to fit in the global scene. ///
Matrix3d* trans_matrices = new Matrix3d[tr_num];
vector<int> traj_comb;
traj_comb = combine2(tr_num, tr_num, traj_comb);
vector<int> moved;
moved.push_back(0); // Initiate the first traj.
int match_count = 0;
int traj_old = 0, traj_new = 0;
for(int i = 0; i < (tr_num * (tr_num - 1) / 2); i++){
traj_old = traj_comb[2 * i];
traj_new = traj_comb[2 * i + 1];
Vector2d buf_old[2];
Vector2d buf_new[2];
// Search two points that exists in both trajs. //
int search = 2;
int loop_old = 0, loop_new = 0;
int ref_old = 0, ref_new = 0;
for(int j = 0; j < (loops_each_traj * loops_each_traj); j++){
loop_old = j / loops_each_traj;
loop_new = j % loops_each_traj;
if(loop_of_traj[traj_old][loop_old] == loop_of_traj[traj_new][loop_new] && search != 0){
ref_old = loopref_of_traj[traj_old][loop_old] + pose_sum[traj_old] - traj_size[traj_old];
buf_old[2 - search] = poses[ref_old];
ref_new = loopref_of_traj[traj_new][loop_new] + pose_sum[traj_new] - traj_size[traj_new];
buf_new[2 - search] = poses[ref_new];
search--;
}
}
// Use the matched point pair to calibrate. //
Matrix3d transform;
int traj_start = pose_sum[traj_new] - traj_size[traj_new];
int traj_end = pose_sum[traj_new];
if(search == 0) {
cerr << "traj" << traj_old + 1 << " and traj" << traj_new + 1 << " has match pairs " << endl;
match_count++;
vector<int>::iterator it_old;
vector<int>::iterator it_new;
it_old = find(moved.begin(), moved.end(), traj_old);
it_new = find(moved.begin(), moved.end(), traj_new);
if(it_new != moved.end()) {
continue; // If the new new traj has already been moved.
}
else if(it_old != moved.end()){
// The old traj has been moved, thus can be used to calibrate.
transform = calculate_transform(
buf_new[0], buf_new[1], buf_old[0], buf_old[1]);
for(int k = traj_start; k < traj_end; k++){
Vector3d temp;
temp << poses[k], 1;
temp = transform * temp;
poses[k](0) = temp(0);
poses[k](1) = temp(1);
}
moved.push_back(traj_new);
}
else{
cout << "Unable to calibrate now..." << endl;
}
}
}
cerr << match_count << " pairs found." << endl;
////////////////////////////////////
/// Create Optimization Problem. ///
g2o::SparseOptimizer optimizer;
g2o::BlockSolverX::LinearSolverType *linearSolver;
linearSolver = new g2o::LinearSolverEigen<g2o::BlockSolverX::PoseMatrixType>();
g2o::BlockSolverX *solver_ptr = new g2o::BlockSolverX( linearSolver );
g2o::OptimizationAlgorithmLevenberg *solver = new g2o::OptimizationAlgorithmLevenberg( solver_ptr );
optimizer.setAlgorithm( solver );
cout << "Solver initiated. " << endl;
/////////////////////////////////
/// Add odometry constraints. ///
cout << "Odometry Optimization... " << endl;
Matrix2d eye2d; eye2d << 1, 0, 0, 1;
int vertice_total = 0;
int edge_total = 0;
int* gap_ptr = pose_sum;
for(int i = 0; i < poses.size(); i++){
/// Add vertex. ///
g2o::VertexPointXY *vertice = new g2o::VertexPointXY();
vertice->setId(i);
vertice->setEstimate(poses[i]);
optimizer.addVertex(vertice);
vertice_total++;
}
/// Add edges. //
for(int i = 0; i < poses.size(); i++){
if(i != (*gap_ptr) - 1){
g2o::EdgePointXY *edge = new g2o::EdgePointXY();
edge->vertices()[0] = optimizer.vertex(i);
edge->vertices()[1] = optimizer.vertex(i + 1);
edge->setMeasurement(poses[i + 1] - poses[i]);
edge->setInformation(eye2d);
optimizer.addEdge(edge);
edge_total++;
}
else gap_ptr++;
}
//////////////////////////////////
/// Cross points Optimization. ///
// check input. //
int loopList_size = loopIndex.size();
for(int i = 0; i < loopList_size; i++){
cout << "loop point" << i + 1 << " is " << loopIndex[i] << endl;
cout << "Global IDs are ";
vector<int>::iterator iter;
for(iter = globeIndexList[i].begin(); iter != globeIndexList[i].end(); iter++){
cout << *iter << " ";
}
cout << endl;
}
for(int i = 0; i < tr_num; i++){
cout << "Loops in traj" << i + 1 << " are ";
for(int j = 0; j < loops_each_traj; j++){
cout << loop_of_traj[i][j] << " ";
}
cout << endl;
cout << "Global id in traj" << i + 1 << " are ";
for(int j = 0; j < loops_each_traj; j++){
cout << loopref_of_traj[i][j] << " ";
}
cout << endl;
}
// Add edge. //
vector<vector<int>>::iterator globe_iter = globeIndexList.begin() - 1;
while(globe_iter++ != globeIndexList.end()){
int list_size = (*globe_iter).size();
vector<int> globeList_comb;
globeList_comb = combine2(list_size, list_size, globeList_comb);
if(globeList_comb.size() != 0){
cerr << globeList_comb.size() << " combinations." << endl;
for(int i = 0; i < (list_size * (list_size - 1) / 2); i++){
int j = (*globe_iter)[globeList_comb[2 * i]];
int k = (*globe_iter)[globeList_comb[2 * i + 1]];
g2o::EdgePointXY *edge = new g2o::EdgePointXY();
edge->vertices()[0] = optimizer.vertex(j);
edge->vertices()[1] = optimizer.vertex(k);
edge->setMeasurement(Vector2d(0, 0));
edge->setInformation(eye2d);
optimizer.addEdge(edge);
edge_total++;
}
}
}
/////////////////////////////////////////////////////////////
/// Partial optimize every 10 traj to eliminate drifting. ///
for(int i = 0; i < (int)(tr_num / 10); i++){
for(int j = 0; j < 10; j++){
if(j != 9)
{ // For every two near trajs' sizes, calculate the smaller.
int less_size = min( (*(traj_size + 10 * i + j)), (*(traj_size + 10 * i + j + 1)) );
int start_a = (*(pose_sum + i * 10 + j)) - (*(traj_size + i * 10 + j));
int start_b = (*(pose_sum + i * 10 + j + 1)) - (*(traj_size + i * 10 + j + 1));
// Add constraints along the trajs for every 2 near point.
for(int k = 0; k < less_size; k++){
g2o::EdgePointXY *edge = new g2o::EdgePointXY;
edge->vertices()[0] = optimizer.vertex(start_a + k);
edge->vertices()[1] = optimizer.vertex(start_b + k);
edge->setMeasurement(Vector2d(0, 0));
edge->setInformation(eye2d);
optimizer.addEdge(edge);
edge_total++;
}
}
else
{ // The 10th traj take in 1st traj as its near next traj.
int less_size = min( (*(traj_size + 10 * i + 9)), (*traj_size + 10 * i) );
int start_a = (*(pose_sum + i * 10 + 9)) - (*(traj_size + i * 10 + 9));
int start_b = (*(pose_sum + i * 10)) - (*(traj_size + i * 10));
// Add constraints along the trajs for every 2 near point.
for(int k = 0; k < less_size; k++){
g2o::EdgePointXY *edge = new g2o::EdgePointXY;
edge->vertices()[0] = optimizer.vertex(start_a + k);
edge->vertices()[1] = optimizer.vertex(start_b + k);
edge->setMeasurement(Vector2d(0, 0));
edge->setInformation(eye2d);
optimizer.addEdge(edge);
edge_total++;
}
}
}
}
/////////////////////
/// Optimization. ///
cout << vertice_total << " vertices and " << edge_total << " edges" << " has been added to the graph." << endl;
optimizer.save("loaded.g2o");
cout << "Initialize optimization..." << endl;
optimizer.setVerbose(true);
optimizer.initializeOptimization();
cout << "Running optimization..." << endl;
optimizer.optimize(10);
cout << "Saving optimization results..." << endl;
optimizer.save("result.g2o");
delete traj_size, pose_sum, gap_ptr, loop_of_traj, trans_matrices;
return 0;
}