SLAMAlign.cpp
Go to the documentation of this file.
1 
39 
40 #include <iomanip>
41 
42 using namespace std;
43 
44 namespace lvr2
45 {
46 
47 SLAMAlign::SLAMAlign(const SLAMOptions& options, const vector<SLAMScanPtr>& scans, std::vector<bool> new_scans)
48  : m_options(options), m_scans(scans), m_graph(&m_options), m_foundLoop(false), m_loopIndexCount(0), m_new_scans(new_scans)
49 {
50 
51  for (auto& scan : m_scans)
52  {
53  reduceScan(scan);
54  }
55 }
56 
57 SLAMAlign::SLAMAlign(const SLAMOptions& options, std::vector<bool> new_scans)
58  : m_options(options), m_graph(&m_options), m_foundLoop(false), m_loopIndexCount(0), m_new_scans(new_scans)
59 {
60 }
61 
63 {
65 }
66 
68 {
69  return m_options;
70 }
71 
72 const SLAMOptions& SLAMAlign::options() const
73 {
74  return m_options;
75 }
76 
77 void SLAMAlign::addScan(const SLAMScanPtr& scan, bool match)
78 {
80  m_scans.push_back(scan);
81 
82  if (match)
83  {
84  this->match();
85  }
86 }
87 
88 void SLAMAlign::addScan(const ScanPtr& scan, bool match)
89 {
90  addScan(make_shared<SLAMScanWrapper>(scan));
91 }
92 
93 SLAMScanPtr SLAMAlign::scan(size_t index) const
94 {
95  return m_scans[index];
96 }
97 
99 {
100  size_t prev = scan->numPoints();
101  if (m_options.reduction >= 0)
102  {
104  }
105  if (m_options.minDistance >= 0)
106  {
107  scan->setMinDistance(m_options.minDistance);
108  }
109  if (m_options.maxDistance >= 0)
110  {
111  scan->setMaxDistance(m_options.maxDistance);
112  }
113 
114  if (scan->numPoints() < prev)
115  {
116  scan->trim();
117 
118  if (m_options.verbose)
119  {
120  cout << "Removed " << (prev - scan->numPoints()) << " / " << prev << " Points -> " << scan->numPoints() << " left" << endl;
121  }
122  }
123 }
124 
126 {
127  // need at least 2 Scans
128  if (m_scans.size() <= 1 || m_options.icpIterations <= 0)
129  {
130  return;
131  }
132 
133  if (m_options.metascan && !m_metascan)
134  {
135  Metascan* meta = new Metascan();
136 
137  meta->addScan(m_scans[0]);
138 
139  m_metascan = SLAMScanPtr(meta);
140  }
141 
142  string scan_number_string = to_string(m_scans.size() - 1);
143 
144  // only match everything after m_alreadyMatched
145  for (size_t i = 0; i < m_icp_graph.size(); i++)
146  {
147  if (m_new_scans.empty() || m_new_scans.at(m_icp_graph.at(i).second))
148  {
149  cout << m_scans.size() << endl;
150  ;
151 
152  if (m_options.verbose)
153  {
154  cout << "Iteration " << setw(scan_number_string.length()) << m_icp_graph.at(i).second << "/" << scan_number_string << ": " << endl;
155  }
156  else
157  {
158  cout << setw(scan_number_string.length()) << m_icp_graph.at(i).second << "/" << scan_number_string << ": " << flush;
159  }
160 
162  const SLAMScanPtr& cur = m_scans[m_icp_graph.at(i).second];
163 
164  if (!m_options.trustPose && m_icp_graph.at(i).second != 1) // no deltaPose on first run
165  {
166  applyTransform(cur, prev->deltaPose());
167  }
168  else
169  {
171  {
172  applyTransform(cur, Matrix4d::Identity());
173  }
174  }
175 
176  ICPPointAlign icp(prev, cur);
182 
183  icp.match();
184 
186  {
187  applyTransform(cur, Matrix4d::Identity());
188  }
189 
190  if (m_options.metascan)
191  {
192  ((Metascan*)m_metascan.get())->addScan(cur);
193  }
195  {
196  checkLoopClose(m_icp_graph.at(i).second);
197  }
198  else if (m_options.doGraphSLAM)
199  {
201  }
202 
203  }
204  }
205 }
206 
208 {
209  scan->transform(transform, m_options.createFrames);
210 
212  {
213  bool found = false;
214  for (const SLAMScanPtr& s : m_scans)
215  {
216  if (s != scan)
217  {
218  s->addFrame(found ? FrameUse::INVALID : FrameUse::UNUSED);
219  }
220  else
221  {
222  found = true;
223  }
224  }
225  }
226 }
227 
229 {
230  if (m_options.verbose)
231  {
232  cout << "check if a loop exists. current scan: " << m_icp_graph.at(last).second << endl;
233  }
234  int no_loop = INT_MAX;
235  vector<SLAMScanPtr> scans;
236  std::vector<bool> new_scans;
237  // create a new scan vector with all registered scans
238  scans.push_back(m_scans.at(m_icp_graph.at(0).first));
239  for (int i = 0; i <= last; i++)
240  {
241  scans.push_back(m_scans.at(m_icp_graph.at(i).second));
242 
243  if (!m_new_scans.empty())
244  {
245  new_scans.push_back(m_new_scans.at(m_icp_graph.at(i).second));
246  }
247  if (m_icp_graph.at(last).first == m_icp_graph.at(i).second)
248  {
249  no_loop = i;
250  }
251  }
252 
253  // when loop found than start graphSLAM
254  for (int i = 0; i < scans.size(); i++)
255  {
256  double distance_to_other = sqrt(
257  pow(m_scans.at(last)->innerScan()->poseEstimation(3,0) - scans.at(i)->innerScan()->poseEstimation(3,0), 2.0)+
258  pow(m_scans.at(last)->innerScan()->poseEstimation(3,1) - scans.at(i)->innerScan()->poseEstimation(3,1), 2.0)+
259  pow(m_scans.at(last)->innerScan()->poseEstimation(3,2) - scans.at(i)->innerScan()->poseEstimation(3,2), 2.0));
260  if (i != no_loop && distance_to_other < m_options.closeLoopDistance)
261  {
262  cout << "found loop" << endl;
263  m_graph.doGraphSLAM(scans, last, new_scans);
264  return;
265  }
266  }
267 }
268 
269 void SLAMAlign::checkLoopClose(size_t last)
270 {
272  {
273  return;
274  }
275 
276  bool hasLoop = false;
277  size_t first = 0;
278 
279  vector<size_t> others;
280  if (findCloseScans(m_scans, last, m_options, others))
281  {
282  hasLoop = true;
283  first = others[0];
284  }
285 
286  if (hasLoop && (m_loopIndexCount % 10 == 3) && m_options.doLoopClosing)
287  {
288  loopClose(first, last);
289  }
290  if (!hasLoop && m_loopIndexCount > 0 && m_options.doLoopClosing && !m_options.doGraphSLAM)
291  {
292  loopClose(first, last);
293  }
294 
295  // falling edge
296  if (m_foundLoop && !hasLoop && m_options.doGraphSLAM)
297  {
298  graphSLAM(last);
299  }
300 
301  if (hasLoop)
302  {
304  }
305  else
306  {
307  m_loopIndexCount = 0;
308  }
309  m_foundLoop = hasLoop;
310 }
311 
312 void SLAMAlign::loopClose(size_t first, size_t last)
313 {
314  cout << "Loopclose " << first << " -> " << last << endl;
315 
316  Metascan* metaFirst = new Metascan();
317  Metascan* metaLast = new Metascan();
318  for (size_t i = 0; i < 3; i++)
319  {
320  metaFirst->addScan(m_scans[first + i]);
321  metaLast->addScan(m_scans[last - i]);
322  }
323 
324  SLAMScanPtr scanFirst(metaFirst);
325  SLAMScanPtr scanLast(metaLast);
326 
327  ICPPointAlign icp(scanFirst, scanLast);
333 
334  Matrix4d transform = icp.match();
335 
336  for (size_t i = first + 3; i <= last - 3; i++)
337  {
338  double factor = (i - first) / (double)(last - first);
339 
340  Matrix4d delta = (transform - Matrix4d::Identity()) * factor + Matrix4d::Identity();
341 
342  m_scans[i]->transform(delta, m_options.createFrames, FrameUse::LOOPCLOSE);
343  }
344 
346  {
347  // Add frame to unaffected scans
348  for (size_t i = 0; i < 3; i++)
349  {
350  m_scans[first + i]->addFrame(FrameUse::LOOPCLOSE);
351  m_scans[last - i]->addFrame(FrameUse::LOOPCLOSE);
352  }
353  for (size_t i = 0; i < first; i++)
354  {
355  m_scans[i]->addFrame();
356  }
357  for (size_t i = last - 2; i < m_scans.size(); i++)
358  {
359  m_scans[i]->addFrame(FrameUse::INVALID);
360  }
361  }
362 }
363 
364 void SLAMAlign::graphSLAM(size_t last)
365 {
367 }
368 
370 {
371  createIcpGraph();
372  for (int i = 0; i< m_icp_graph.size(); i++)
373  {
374  cout << "icp graph: " << m_icp_graph.at(i).first << ":" << m_icp_graph.at(i).second << endl;
375  }
376 
377  match();
378 
380  {
381  graphSLAM(m_scans.size() - 1);
382  }
383 }
384 
386 {
387  if (m_options.verbose)
388  {
389  cout << "create ICP Graph" << endl;
390  }
391  m_icp_graph = std::vector<std::pair<int, int>>();
392  vector<vector<double>> mat(m_scans.size());
393 
394  // if useScanOrder: the m_icp_graph must the scnan order
396  {
397  for (int i = 1; i < m_scans.size(); i++)
398  {
399  m_icp_graph.push_back(std::pair<int, int>(i-1,i));
400  }
401  return;
402  }
403 
404  // calculate the euclidean distance from the first scna to all scans
405  {
406  vector<double> *v = &(mat.at(0));
407  auto trans_a = m_scans.at(0)->innerScan()->poseEstimation.block<3, 1>(0, 3);
408  for (int i = 0; i < m_scans.size(); i++)
409  {
410  auto trans_b = m_scans.at(i)->innerScan()->poseEstimation.block<3, 1>(0, 3);
411 
412  double translation_diff = 0.0;
413  for(int i = 0; i < 3; ++i)
414  {
415  translation_diff+= std::pow(trans_a[i] - trans_b[i], 2);
416  }
417  v->push_back(std::sqrt(translation_diff));
418 
419  if (m_options.verbose)
420  {
421  cout << "Calculated euclidean distancex: scan_0, scan_" << i << ", d="<< v->at(i) << endl;
422  }
423  }
424  }
425 
426  // vector of booleans: true if scan included in the graph; first scan is already included
427  vector<bool> scan_in_graph(m_scans.size());
428  scan_in_graph.at(0) = true;
429  for (int i = 1; i < scan_in_graph.size(); i++)
430  {
431  scan_in_graph.at(i) = false;
432  }
433 
434  for(int i = 1; i < m_scans.size(); i++)
435  {
436  double minimum = DBL_MAX;
437  int old_scan;
438  int new_scan;
439 
440  //search for minimum in mat
441  for(int x = 0; x < mat.size(); ++x)
442  {
443  for(int y = 0 ; y < mat.at(x).size(); ++y)
444  {
445  if (!scan_in_graph.at(y) && x!=y && mat[x][y] < minimum)
446  {
447  //cout << "new min: ";
448  minimum = mat[x][y];
449  old_scan = x;
450  new_scan = y;
451  }
452  }
453  }
454 
455  m_icp_graph.push_back(std::pair<int, int>(old_scan,new_scan));
456  scan_in_graph.at(new_scan) = true;
457 
458  {
459  vector<double> *v = &(mat.at(new_scan));
460  auto trans_a = m_scans.at(new_scan)->innerScan()->poseEstimation.block<3, 1>(0, 3);
461  for (int i = 0; i < m_scans.size(); i++)
462  {
463  auto trans_b = m_scans.at(i)->innerScan()->poseEstimation.block<3, 1>(0, 3);
464 
465  double translation_diff = 0.0;
466  for(int i = 0; i < 3; ++i)
467  {
468  translation_diff+= std::pow(trans_a[i] - trans_b[i], 2);
469  }
470  v->push_back(std::sqrt(translation_diff));
471 
472  if (m_options.verbose)
473  {
474  cout << "Calculated euclidean distancex: scan_" << new_scan << ", scan_" << i << ", d="<< v->at(i) << endl;
475  }
476  }
477  }
478  }
479 
480  if (m_options.verbose)
481  {
482  cout << "create ICP Graph finish" << endl;
483  }
484 }
485 
486 } /* namespace lvr2 */
lvr2::SLAMOptions::reduction
double reduction
The Voxel size for Octree based reduction.
Definition: SLAMOptions.hpp:67
lvr2::ICPPointAlign::setMaxLeafSize
void setMaxLeafSize(int maxLeafSize)
Definition: ICPPointAlign.cpp:137
lvr2::SLAMAlign::m_scans
std::vector< SLAMScanPtr > m_scans
Definition: SLAMAlign.hpp:179
lvr2::SLAMAlign::m_foundLoop
bool m_foundLoop
Definition: SLAMAlign.hpp:184
lvr2::SLAMOptions::createFrames
bool createFrames
Keep track of all previous Transformations of Scans for Animation purposes like 'show' from slam6D.
Definition: SLAMOptions.hpp:56
lvr2::SLAMAlign::reduceScan
void reduceScan(const SLAMScanPtr &scan)
Applies all reductions to the Scan.
Definition: SLAMAlign.cpp:98
transform
Definition: src/tools/lvr2_transform/Options.cpp:44
lvr2::Metascan
Represents several Scans as part of a single Scan.
Definition: Metascan.hpp:47
lvr2::SLAMOptions::trustPose
bool trustPose
Use the unmodified Pose of new Scans. If false, apply the relative refinement of previous Scans.
Definition: SLAMOptions.hpp:50
SLAMAlign.hpp
lvr2::SLAMOptions::icpMaxDistance
double icpMaxDistance
The maximum distance between two points during ICP.
Definition: SLAMOptions.hpp:82
lvr2::SLAMAlign::m_loopIndexCount
int m_loopIndexCount
Definition: SLAMAlign.hpp:185
lvr2::FrameUse::UNUSED
@ UNUSED
The Scan did not change since the last Frame.
lvr2::SLAMAlign::applyTransform
void applyTransform(SLAMScanPtr scan, const Matrix4d &transform)
Applies the Transformation to the specified Scan and adds a frame to all other Scans.
Definition: SLAMAlign.cpp:207
lvr2::SLAMOptions::doLoopClosing
bool doLoopClosing
Use simple Loopclosing.
Definition: SLAMOptions.hpp:93
lvr2::SLAMOptions::icpIterations
int icpIterations
Definition: SLAMOptions.hpp:79
lvr2::ICPPointAlign::setVerbose
void setVerbose(bool verbose)
Definition: ICPPointAlign.cpp:146
lvr2::SLAMAlign::m_new_scans
std::vector< bool > m_new_scans
Definition: SLAMAlign.hpp:187
lvr2::ICPPointAlign::setEpsilon
void setEpsilon(double epsilon)
Definition: ICPPointAlign.cpp:142
lvr2::FrameUse::INVALID
@ INVALID
The Scan has not been registered yet.
lvr2::SLAMOptions::closeLoopDistance
double closeLoopDistance
Definition: SLAMOptions.hpp:100
lvr2::SLAMOptions::epsilon
double epsilon
The epsilon difference between ICP-errors for the stop criterion of ICP.
Definition: SLAMOptions.hpp:88
lvr2::SLAMAlign::m_metascan
SLAMScanPtr m_metascan
Definition: SLAMAlign.hpp:181
options
const kaboom::Options * options
Definition: src/tools/lvr2_kaboom/Main.cpp:45
Metascan.hpp
lvr2::GraphSLAM::doGraphSLAM
void doGraphSLAM(const std::vector< SLAMScanPtr > &scans, size_t last, const std::vector< bool > &new_scans=std::vector< bool >()) const
runs the GraphSLAM algorithm
Definition: GraphSLAM.cpp:122
lvr2::SLAMOptions::useScanOrder
bool useScanOrder
use scan order as icp order (if false: start with lowest distance)
Definition: SLAMOptions.hpp:127
lvr2::SLAMAlign::scan
SLAMScanPtr scan(size_t index) const
Returns a shared_ptr to a Scan.
Definition: SLAMAlign.cpp:93
lvr2::SLAMOptions::verbose
bool verbose
Show more detailed output. Useful for fine-tuning Parameters or debugging.
Definition: SLAMOptions.hpp:59
lvr2::Matrix4d
Eigen::Matrix4d Matrix4d
Eigen 4x4 matrix, double precision.
Definition: MatrixTypes.hpp:150
lvr2::SLAMAlign::setOptions
void setOptions(const SLAMOptions &options)
Sets the SLAMOptions struct to the parameter.
Definition: SLAMAlign.cpp:62
lvr2::SLAMAlign::options
SLAMOptions & options()
Returns a reference to the internal SLAMOptions struct.
Definition: SLAMAlign.cpp:67
lvr2::SLAMAlign::loopClose
void loopClose(size_t first, size_t last)
Closes a simple Loop between first and last.
Definition: SLAMAlign.cpp:312
lvr2::SLAMAlign::checkLoopClose
void checkLoopClose(size_t last)
Checks for and executes any loopcloses that occur.
Definition: SLAMAlign.cpp:269
lvr2::SLAMScanPtr
std::shared_ptr< SLAMScanWrapper > SLAMScanPtr
Definition: SLAMScanWrapper.hpp:221
lvr2::SLAMOptions::slamMaxDistance
double slamMaxDistance
The maximum distance between two points during SLAM.
Definition: SLAMOptions.hpp:115
lvr2::ICPPointAlign
A class to align two Scans with ICP.
Definition: ICPPointAlign.hpp:49
lvr2::SLAMAlign::match
void match()
Executes SLAM on all current Scans.
Definition: SLAMAlign.cpp:125
lvr2::SLAMAlign::checkLoopCloseOtherOrder
void checkLoopCloseOtherOrder(size_t last)
checkLoopClose(size_t last) if the m_icp_graph is in a spezial order
Definition: SLAMAlign.cpp:228
lvr2::SLAMOptions::metascan
bool metascan
Match scans to the combined Pointcloud of all previous Scans instead of just the last Scan.
Definition: SLAMOptions.hpp:53
lvr2::SLAMAlign::m_options
SLAMOptions m_options
Definition: SLAMAlign.hpp:177
lvr2::SLAMAlign::graphSLAM
void graphSLAM(size_t last)
Executes GraphSLAM up to and including the specified last Scan.
Definition: SLAMAlign.cpp:364
lvr2::SLAMAlign::createIcpGraph
void createIcpGraph()
Create m_icp_graph which defined the order of registrations.
Definition: SLAMAlign.cpp:385
lvr2::ICPPointAlign::setMaxMatchDistance
void setMaxMatchDistance(double distance)
Definition: ICPPointAlign.cpp:127
lvr2::SLAMOptions::minDistance
double minDistance
Ignore all Points closer than to the origin of a scan.
Definition: SLAMOptions.hpp:70
lvr2::SLAMOptions::doGraphSLAM
bool doGraphSLAM
Use complex Loopclosing with GraphSLAM.
Definition: SLAMOptions.hpp:96
std
Definition: HalfEdge.hpp:124
lvr2::Metascan::addScan
void addScan(SLAMScanPtr scan)
Definition: Metascan.cpp:72
lvr2
Definition: BaseBufferManipulators.hpp:39
lvr2::SLAMAlign::SLAMAlign
SLAMAlign(const SLAMOptions &options, const std::vector< SLAMScanPtr > &scans, std::vector< bool > new_scans=std::vector< bool >())
Creates a new SLAMAlign instance with the given Options and Scans.
lvr2::SLAMOptions::maxDistance
double maxDistance
Ignore all Points farther away than from the origin of a scan.
Definition: SLAMOptions.hpp:73
first
void first(int id)
Definition: example.cpp:7
lvr2::ICPPointAlign::setMaxIterations
void setMaxIterations(int iterations)
Definition: ICPPointAlign.cpp:132
lvr2::SLAMOptions::slamIterations
int slamIterations
Number of ICP iterations during Loopclosing and number of GraphSLAM iterations.
Definition: SLAMOptions.hpp:112
lvr2::SLAMOptions::slamEpsilon
double slamEpsilon
The epsilon difference of SLAM corrections for the stop criterion of SLAM.
Definition: SLAMOptions.hpp:118
lvr2::SLAMAlign::finish
void finish()
Indicates that no new Scans will be added.
Definition: SLAMAlign.cpp:369
ICPPointAlign.hpp
lvr2::ICPPointAlign::match
Transformd match()
Executes the ICPAlign.
Definition: ICPPointAlign.cpp:58
lvr2::FrameUse::LOOPCLOSE
@ LOOPCLOSE
The Scan was part of a Loopclose Iteration.
lvr2::SLAMOptions
A struct to configure SLAMAlign.
Definition: SLAMOptions.hpp:45
lvr2::SLAMAlign::m_icp_graph
std::vector< std::pair< int, int > > m_icp_graph
Definition: SLAMAlign.hpp:189
lvr2::SLAMAlign::addScan
void addScan(const SLAMScanPtr &scan, bool match=false)
Adds a new Scan to the SLAM instance.
Definition: SLAMAlign.cpp:77
lvr2::SLAMAlign::m_graph
GraphSLAM m_graph
Definition: SLAMAlign.hpp:183
lvr2::findCloseScans
bool findCloseScans(const std::vector< SLAMScanPtr > &scans, size_t scan, const SLAMOptions &options, std::vector< size_t > &output)
finds Scans that are "close" to a Scan as determined by a Loopclosing strategy
lvr2::SLAMOptions::maxLeafSize
int maxLeafSize
The maximum number of Points in a Leaf of a KDTree.
Definition: SLAMOptions.hpp:85
lvr2::ScanPtr
std::shared_ptr< Scan > ScanPtr
Shared pointer to scans.
Definition: ScanTypes.hpp:98


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Wed Mar 2 2022 00:37:25