SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
WAIMapStorage.cpp
Go to the documentation of this file.
1 #include <WAIMapStorage.h>
2 #include <Profiler.h>
3 
5 {
6  cv::Mat cvMat = cv::Mat(4, 4, CV_32F);
7  // clang-format off
8  //so ein scheiss!!!
9  // T M0, T M4, T M8, T M12,
10  // T M1, T M5, T M9, T M13,
11  // T M2, T M6, T M10, T M14,
12  // T M3, T M7, T M11, T M15)
13  cvMat.at<float>(0, 0) = slMat.m(0);
14  cvMat.at<float>(1, 0) = slMat.m(1);
15  cvMat.at<float>(2, 0) = slMat.m(2);
16  cvMat.at<float>(3, 0) = slMat.m(3);
17 
18  cvMat.at<float>(0, 1) = slMat.m(4);
19  cvMat.at<float>(1, 1) = slMat.m(5);
20  cvMat.at<float>(2, 1) = slMat.m(6);
21  cvMat.at<float>(3, 1) = slMat.m(7);
22 
23  cvMat.at<float>(0, 2) = slMat.m(8);
24  cvMat.at<float>(1, 2) = slMat.m(9);
25  cvMat.at<float>(2, 2) = slMat.m(10);
26  cvMat.at<float>(3, 2) = slMat.m(11);
27 
28  cvMat.at<float>(0, 3) = slMat.m(12);
29  cvMat.at<float>(1, 3) = slMat.m(13);
30  cvMat.at<float>(2, 3) = slMat.m(14);
31  cvMat.at<float>(3, 3) = slMat.m(15);
32  // clang-format on
33  return cvMat;
34 }
35 
37 {
38  SLMat4f slMat;
39  // clang-format off
40  // T M0, T M4, T M8, T M12,
41  // T M1, T M5, T M9, T M13,
42  // T M2, T M6, T M10, T M14,
43  // T M3, T M7, T M11, T M15)
44  slMat.setMatrix(
45  cvMat.at<float>(0, 0), cvMat.at<float>(0, 1), cvMat.at<float>(0, 2), cvMat.at<float>(0, 3),
46  cvMat.at<float>(1, 0), cvMat.at<float>(1, 1), cvMat.at<float>(1, 2), cvMat.at<float>(1, 3),
47  cvMat.at<float>(2, 0), cvMat.at<float>(2, 1), cvMat.at<float>(2, 2), cvMat.at<float>(2, 3),
48  cvMat.at<float>(3, 0), cvMat.at<float>(3, 1), cvMat.at<float>(3, 2), cvMat.at<float>(3, 3));
49  // clang-format on
50 
51  return slMat;
52 }
53 
54 void buildMatching(std::vector<WAIKeyFrame*>& kfs,
55  std::map<WAIKeyFrame*, std::map<size_t, size_t>>& KFmatching)
56 {
57  for (int i = 0; i < kfs.size(); ++i)
58  {
59  WAIKeyFrame* kf = kfs[i];
60  if (kf->isBad())
61  continue;
62  // if (kf->mBowVec.data.empty())
63  // continue;
64 
65  std::vector<WAIMapPoint*> mps = kf->GetMapPointMatches();
66  std::map<size_t, size_t> matching;
67 
68  size_t id = 0;
69  for (int j = 0; j < mps.size(); j++)
70  {
71  if (mps[j] != nullptr)
72  {
73  matching.insert(std::pair<size_t, size_t>(j, id));
74  id++;
75  }
76  }
77  KFmatching.insert(std::pair<WAIKeyFrame*, std::map<size_t, size_t>>(kf, matching));
78  }
79 }
80 
81 void saveKeyFrames(std::vector<WAIKeyFrame*>& kfs,
82  std::map<WAIKeyFrame*, std::map<size_t, size_t>>& KFmatching,
83  cv::FileStorage& fs,
84  std::string imgDir,
85  bool saveBOW)
86 {
87  // start sequence keyframes
88  fs << "KeyFrames"
89  << "[";
90  for (int i = 0; i < kfs.size(); ++i)
91  {
92  WAIKeyFrame* kf = kfs[i];
93  if (kf->isBad())
94  continue;
95  if (kf->mBowVec.data.empty())
96  continue;
97 
98  fs << "{"; // new map keyFrame
99  // add id
100  fs << "id" << (int)kf->mnId;
101  if (kf->mnId != 0) // kf with id 0 has no parent
102  fs << "parentId" << (int)kf->GetParent()->mnId;
103  else
104  fs << "parentId" << -1;
105 
106  // loop edges: we store the id of the connected kf
107  auto loopEdges = kf->GetLoopEdges();
108  if (loopEdges.size())
109  {
110  std::vector<int> loopEdgeIds;
111  for (auto loopEdgeKf : loopEdges)
112  {
113  loopEdgeIds.push_back(loopEdgeKf->mnId);
114  }
115  fs << "loopEdges" << loopEdgeIds;
116  }
117 
118  // world w.r.t camera
119  fs << "Tcw" << kf->GetPose();
120 
121  if (KFmatching.size() > 0)
122  {
123  cv::Mat descriptors;
124  const std::map<size_t, size_t>& matching = KFmatching[kf];
125  descriptors.create((int)matching.size(), 32, CV_8U);
126  std::vector<cv::KeyPoint> keypoints(matching.size());
127  for (int j = 0; j < kf->mvKeysUn.size(); j++)
128  {
129  auto it = matching.find(j);
130  if (it != matching.end())
131  {
132  kf->mDescriptors.row(j).copyTo(descriptors.row(it->second));
133  keypoints[it->second] = kf->mvKeysUn[j];
134  }
135  }
136  fs << "featureDescriptors" << descriptors;
137  fs << "keyPtsUndist" << keypoints;
138  }
139  else
140  {
141  fs << "featureDescriptors" << kf->mDescriptors;
142  fs << "keyPtsUndist" << kf->mvKeysUn;
143  }
144 
145  if (saveBOW)
146  {
147  WAIBowVector& bowVec = kf->mBowVec;
148  std::vector<int> wordsId;
149  std::vector<float> tfIdf;
150  for (auto it = bowVec.getWordScoreMapping().begin(); it != bowVec.getWordScoreMapping().end(); it++)
151  {
152  wordsId.push_back(it->first);
153  tfIdf.push_back(it->second);
154  }
155 
156  fs << "BowVectorWordsId" << wordsId;
157  fs << "TfIdf" << tfIdf;
158  }
159 
160  // scale factor
161  fs << "scaleFactor" << kf->mfScaleFactor;
162  // number of pyriamid scale levels
163  fs << "nScaleLevels" << kf->mnScaleLevels;
164  fs << "K" << kf->mK;
165 
166  fs << "nMinX" << kf->mnMinX;
167  fs << "nMinY" << kf->mnMinY;
168  fs << "nMaxX" << kf->mnMaxX;
169  fs << "nMaxY" << kf->mnMaxY;
170 
171 #if 0
172  std::vector<int> bestCovisibleKeyFrameIds;
173  std::vector<int> bestCovisibleWeights;
174  std::vector<WAIKeyFrame*> bestCovisibles = kf->GetBestCovisibilityKeyFrames(20);
175  for (WAIKeyFrame* covisible : bestCovisibles)
176  {
177  if (covisible->isBad())
178  continue;
179  int weight = kf->GetWeight(covisible);
180  if (weight)
181  {
182  bestCovisibleKeyFrameIds.push_back(covisible->mnId);
183  bestCovisibleWeights.push_back(weight);
184  }
185  }
186 
187  fs << "bestCovisibleKeyFrameIds" << bestCovisibleKeyFrameIds;
188  fs << "bestCovisibleWeights" << bestCovisibleWeights;
189 #endif
190 
191  fs << "}"; // close map
192 
193  // save the original frame image for this keyframe
194  if (imgDir != "")
195  {
196  cv::Mat imgColor;
197  if (!kf->imgGray.empty())
198  {
199  std::stringstream ss;
200  ss << imgDir << "kf" << (int)kf->mnId << ".jpg";
201 
202  cv::cvtColor(kf->imgGray, imgColor, cv::COLOR_GRAY2BGR);
203  cv::imwrite(ss.str(), imgColor);
204 
205  // if this kf was never loaded, we still have to set the texture path
206  kf->setTexturePath(ss.str());
207  }
208  }
209  }
210  fs << "]"; // close sequence keyframes
211 }
212 
213 void saveMapPoints(std::vector<WAIMapPoint*> mpts,
214  std::map<WAIKeyFrame*, std::map<size_t, size_t>>& KFmatching,
215  cv::FileStorage& fs)
216 {
217  // start map points sequence
218  fs << "MapPoints"
219  << "[";
220  for (int i = 0; i < mpts.size(); ++i)
221  {
222  WAIMapPoint* mpt = mpts[i];
223  // TODO: ghm1: check if it is necessary to removed points that have no reference keyframe OR can we somehow update the reference keyframe in the SLAM
224  if (mpt->isBad() || mpt->refKf()->isBad())
225  continue;
226 
227  fs << "{"; // new map for MapPoint
228  // add id
229  fs << "id" << (int)mpt->mnId;
230  // add position
231  fs << "mWorldPos" << mpt->GetWorldPos();
232  // save keyframe observations
233  auto observations = mpt->GetObservations();
234  vector<int> observingKfIds;
235  vector<int> corrKpIndices; // corresponding keypoint indices in observing keyframe
236 
237  if (!KFmatching.empty())
238  {
239  for (auto it : observations)
240  {
241  WAIKeyFrame* kf = it.first;
242  size_t kpIdx = it.second;
243  if (!kf || kf->isBad() || kf->mBowVec.data.empty())
244  continue;
245 
246  if (KFmatching.find(kf) == KFmatching.end())
247  {
248  std::cout << "observation not found in kfmatching" << std::endl;
249  continue;
250  }
251 
252  const std::map<size_t, size_t>& matching = KFmatching[kf];
253  auto mit = matching.find(kpIdx);
254  if (mit != matching.end())
255  {
256  observingKfIds.push_back(kf->mnId);
257  corrKpIndices.push_back(mit->second);
258  }
259  }
260  }
261  else
262  {
263  for (auto it : observations)
264  {
265  if (!it.first->isBad())
266  {
267  observingKfIds.push_back(it.first->mnId);
268  corrKpIndices.push_back(it.second);
269  }
270  }
271  }
272 
273  fs << "observingKfIds" << observingKfIds;
274  fs << "corrKpIndices" << corrKpIndices;
275 
276  fs << "mfMaxDistance" << mpt->GetMaxDistance();
277  fs << "mfMinDistance" << mpt->GetMinDistance();
278  fs << "mNormalVector" << mpt->GetNormal();
279  fs << "mDescriptor" << mpt->GetDescriptor();
280 
281  fs << "refKfId" << (int)mpt->refKf()->mnId;
282  fs << "}"; // close map
283  }
284  fs << "]";
285 }
286 
288  SLNode* mapNode,
289  std::string filename,
290  std::string imgDir,
291  bool saveBOW)
292 {
293  std::vector<WAIKeyFrame*> kfs = waiMap->GetAllKeyFrames();
294  std::vector<WAIMapPoint*> mpts = waiMap->GetAllMapPoints();
295  std::map<WAIKeyFrame*, std::map<size_t, size_t>> KFmatching;
296 
297  if (kfs.size() == 0)
298  return false;
299 
300  buildMatching(kfs, KFmatching);
301 
302  // save keyframes (without graph/neigbourhood information)
303  cv::FileStorage fs(filename, cv::FileStorage::WRITE);
304 
305  if (!fs.isOpened())
306  {
307  return false;
308  }
309 
310  if (mapNode)
311  {
312  SLMat4f slOm = mapNode->om();
313  std::cout << "slOm: " << slOm.toString() << std::endl;
314  cv::Mat cvOm = convertToCVMat(mapNode->om());
315  std::cout << "cvOM: " << cvOm << std::endl;
316  fs << "mapNodeOm" << cvOm;
317  }
318 
319  saveKeyFrames(kfs, KFmatching, fs, imgDir, saveBOW);
320  saveMapPoints(mpts, KFmatching, fs);
321 
322  // explicit close
323  fs.release();
324  return true;
325 }
326 
328  SLNode* mapNode,
329  std::string filename,
330  std::string imgDir)
331 {
332  std::vector<WAIKeyFrame*> kfs = waiMap->GetAllKeyFrames();
333  std::vector<WAIMapPoint*> mpts = waiMap->GetAllMapPoints();
334  std::map<WAIKeyFrame*, std::map<size_t, size_t>> KFmatching;
335 
336  if (kfs.size() == 0)
337  return false;
338 
339  // in this case we dont build a keyframe matching..
340 
341  // save keyframes (without graph/neigbourhood information)
342  cv::FileStorage fs(filename, cv::FileStorage::WRITE);
343 
344  if (!fs.isOpened())
345  {
346  return false;
347  }
348 
349  if (mapNode)
350  {
351  SLMat4f slOm = mapNode->om();
352  std::cout << "slOm: " << slOm.toString() << std::endl;
353  cv::Mat cvOm = convertToCVMat(mapNode->om());
354  std::cout << "cvOM: " << cvOm << std::endl;
355  fs << "mapNodeOm" << cvOm;
356  }
357 
358  saveKeyFrames(kfs, KFmatching, fs, imgDir, false);
359  saveMapPoints(mpts, KFmatching, fs);
360 
361  // explicit close
362  fs.release();
363  return true;
364 }
365 
366 std::vector<uint8_t> WAIMapStorage::convertCVMatToVector(const cv::Mat& mat)
367 {
368  std::vector<uint8_t> result;
369 
370  // makes sure mat is continuous
371  cv::Mat continuousMat = mat.clone();
372 
373  // TODO(dgj1): verify that this is correct
374  result.assign(continuousMat.data, continuousMat.data + continuousMat.total() * continuousMat.elemSize());
375 
376  return result;
377 }
378 
379 template<typename T>
380 void WAIMapStorage::writeVectorToBinaryFile(FILE* f, const std::vector<T> vec)
381 {
382  fwrite(vec.data(), sizeof(T), vec.size(), f);
383 }
384 
385 void WAIMapStorage::writeCVMatToBinaryFile(FILE* f, const cv::Mat& mat)
386 {
387  std::vector<uint8_t> data = convertCVMatToVector(mat);
388 
389  writeVectorToBinaryFile(f, data);
390 }
391 
393  SLNode* mapNode,
394  std::string filename,
395  std::string imgDir,
396  bool saveBOW)
397 {
398  std::vector<WAIKeyFrame*> kfs = waiMap->GetAllKeyFrames();
399  std::vector<WAIMapPoint*> mpts = waiMap->GetAllMapPoints();
400  std::map<WAIKeyFrame*, std::map<size_t, size_t>> KFmatching;
401 
402  if (kfs.size() == 0)
403  return false;
404 
405  buildMatching(kfs, KFmatching);
406 
407  FILE* f = fopen(filename.c_str(), "wb");
408  if (!f)
409  {
410  return false;
411  }
412 
413  WAIMapStorage::MapInfo mapInfo = {};
414  mapInfo.version = 1;
415 
416  for (int i = 0; i < kfs.size(); ++i)
417  {
418  WAIKeyFrame* kf = kfs[i];
419  if (kf->isBad())
420  continue;
421  if (kf->mBowVec.data.empty())
422  continue;
423 
424  mapInfo.kfCount++;
425  }
426 
427  for (int i = 0; i < mpts.size(); ++i)
428  {
429  WAIMapPoint* mpt = mpts[i];
430  // TODO: ghm1: check if it is necessary to removed points that have no reference keyframe OR can we somehow update the reference keyframe in the SLAM
431  if (mpt->isBad() || mpt->refKf()->isBad())
432  continue;
433 
434  mapInfo.mpCount++;
435  }
436 
437  if (mapNode)
438  {
439  mapInfo.nodeOmSaved = true;
440  }
441 
442  fwrite(&mapInfo, sizeof(WAIMapStorage::MapInfo), 1, f);
443 
444  std::vector<uchar> omVec;
445  if (mapNode)
446  {
447  SLMat4f slOm = mapNode->om();
448  cv::Mat cvOm = convertToCVMat(mapNode->om());
449 
450  writeCVMatToBinaryFile(f, cvOm);
451  }
452 
453  // start keyframes sequence
454  for (int i = 0; i < kfs.size(); ++i)
455  {
456  WAIKeyFrame* kf = kfs[i];
457  if (kf->isBad())
458  continue;
459  if (kf->mBowVec.data.empty())
460  continue;
461 
462  WAIMapStorage::KeyFrameInfo kfInfo = {};
463 
464  kfInfo.id = (int32_t)kf->mnId;
465 
466  // scale factor
467  kfInfo.scaleFactor = kf->mfScaleFactor;
468  // number of pyramid scale levels
469  kfInfo.scaleLevels = kf->mnScaleLevels;
470 
471  kfInfo.minX = kf->mnMinX;
472  kfInfo.minY = kf->mnMinY;
473  kfInfo.maxX = kf->mnMaxX;
474  kfInfo.maxY = kf->mnMaxY;
475 
476  cv::Mat descriptors;
477  CVVKeyPoint keyPoints;
478  if (KFmatching.size() > 0)
479  {
480  const std::map<size_t, size_t>& matching = KFmatching[kf];
481  descriptors.create((int)matching.size(), 32, CV_8U);
482  keyPoints.resize(matching.size());
483  for (int j = 0; j < kf->mvKeysUn.size(); j++)
484  {
485  auto it = matching.find(j);
486  if (it != matching.end())
487  {
488  kf->mDescriptors.row(j).copyTo(descriptors.row(it->second));
489  keyPoints[it->second] = kf->mvKeysUn[j];
490  }
491  }
492  }
493  else
494  {
495  descriptors = kf->mDescriptors;
496  keyPoints = kf->mvKeysUn;
497  }
498 
499  kfInfo.kpCount = keyPoints.size();
500 
501  if (kf->mnId != 0) // kf with id 0 has no parent
502  kfInfo.parentId = (int32_t)kf->GetParent()->mnId;
503  else
504  kfInfo.parentId = -1;
505 
506  // loop edges: we store the id of the connected kf
507  std::set<WAIKeyFrame*> loopEdges = kf->GetLoopEdges();
508  std::vector<int32_t> loopEdgeIds;
509  if (loopEdges.size())
510  {
511  for (WAIKeyFrame* loopEdgeKf : loopEdges)
512  {
513  loopEdgeIds.push_back(loopEdgeKf->mnId);
514  kfInfo.loopEdgesCount++; // TODO(dgj1): probably not ideal for cache coherence
515  }
516  }
517 
518  std::vector<int32_t> wordsId;
519  std::vector<float> tfIdf;
520  if (saveBOW)
521  {
522  WAIBowVector& bowVec = kf->mBowVec;
523  for (auto it = bowVec.getWordScoreMapping().begin();
524  it != bowVec.getWordScoreMapping().end();
525  it++)
526  {
527  wordsId.push_back(it->first);
528  tfIdf.push_back(it->second);
529  }
530 
531  kfInfo.bowVecSize = wordsId.size();
532  }
533 
534  std::vector<int32_t> bestCovisibleKeyFrameIds;
535  std::vector<int32_t> bestCovisibleWeights;
536  std::vector<WAIKeyFrame*> bestCovisibles = kf->GetBestCovisibilityKeyFrames(20);
537  for (WAIKeyFrame* covisible : bestCovisibles)
538  {
539  if (covisible->isBad())
540  continue;
541  int weight = kf->GetWeight(covisible);
542  if (weight)
543  {
544  bestCovisibleKeyFrameIds.push_back(covisible->mnId);
545  bestCovisibleWeights.push_back(weight);
546  }
547  }
548 
549  kfInfo.covisiblesCount = bestCovisibleKeyFrameIds.size();
550 
551  fwrite(&kfInfo, sizeof(KeyFrameInfo), 1, f);
552  writeCVMatToBinaryFile(f, kf->mK);
554  writeVectorToBinaryFile(f, loopEdgeIds);
555  writeCVMatToBinaryFile(f, descriptors);
556  writeVectorToBinaryFile(f, keyPoints);
557 
558  if (saveBOW)
559  {
560  writeVectorToBinaryFile(f, wordsId);
561  writeVectorToBinaryFile(f, tfIdf);
562  }
563 
564  writeVectorToBinaryFile(f, bestCovisibleKeyFrameIds);
565  writeVectorToBinaryFile(f, bestCovisibleWeights);
566 
567  // save the original frame image for this keyframe
568  if (imgDir != "")
569  {
570  cv::Mat imgColor;
571  if (!kf->imgGray.empty())
572  {
573  std::stringstream ss;
574  ss << imgDir << "kf" << (int)kf->mnId << ".jpg";
575 
576  cv::cvtColor(kf->imgGray, imgColor, cv::COLOR_GRAY2BGR);
577  cv::imwrite(ss.str(), imgColor);
578 
579  // if this kf was never loaded, we still have to set the texture path
580  kf->setTexturePath(ss.str());
581  }
582  }
583  }
584 
585  // start map points sequence
586  for (int i = 0; i < mpts.size(); ++i)
587  {
588  WAIMapPoint* mpt = mpts[i];
589  // TODO: ghm1: check if it is necessary to removed points that have no reference keyframe OR can we somehow update the reference keyframe in the SLAM
590  if (mpt->isBad() || mpt->refKf()->isBad())
591  continue;
592 
593  MapPointInfo mpInfo = {};
594  mpInfo.id = (int32_t)mpt->mnId;
595  mpInfo.refKfId = (int32_t)mpt->refKf()->mnId;
596 
597  // save keyframe observations
598  std::map<WAIKeyFrame*, size_t> observations = mpt->GetObservations();
599  vector<int32_t> observingKfIds;
600  vector<int32_t> corrKpIndices; // corresponding keypoint indices in observing keyframe
601  if (!KFmatching.empty())
602  {
603  for (std::pair<WAIKeyFrame* const, size_t> it : observations)
604  {
605  WAIKeyFrame* kf = it.first;
606  size_t kpIdx = it.second;
607  if (!kf || kf->isBad() || kf->mBowVec.data.empty())
608  continue;
609 
610  if (KFmatching.find(kf) == KFmatching.end())
611  {
612  std::cout << "observation not found in kfmatching" << std::endl;
613  continue;
614  }
615 
616  const std::map<size_t, size_t>& matching = KFmatching[kf];
617  auto mit = matching.find(kpIdx);
618  if (mit != matching.end())
619  {
620  observingKfIds.push_back(kf->mnId);
621  corrKpIndices.push_back(mit->second);
622  }
623  }
624  }
625  else
626  {
627  for (std::pair<WAIKeyFrame* const, size_t> it : observations)
628  {
629  if (!it.first->isBad())
630  {
631  observingKfIds.push_back(it.first->mnId);
632  corrKpIndices.push_back(it.second);
633  }
634  }
635  }
636 
637  mpInfo.nObervations = observingKfIds.size();
638  mpInfo.minDistance = mpt->GetMinDistance();
639  mpInfo.maxDistance = mpt->GetMaxDistance();
640 
641  fwrite(&mpInfo, sizeof(mpInfo), 1, f);
643  writeVectorToBinaryFile(f, observingKfIds);
644  writeVectorToBinaryFile(f, corrKpIndices);
647  }
648 
649  fclose(f);
650 
651  return true;
652 }
653 
654 template<typename T>
655 std::vector<T> WAIMapStorage::loadVectorFromBinaryStream(uint8_t** data, int count)
656 {
657  std::vector<T> result((T*)(*data), ((T*)(*data)) + count);
658  *data += sizeof(T) * count;
659 
660  return result;
661 }
662 
663 // returns the number of bytes loaded
665  int rows,
666  int cols,
667  int type)
668 {
669  cv::Mat result = cv::Mat(rows, cols, type, *data);
670 
671  *data += rows * cols * result.elemSize();
672 
673  return result;
674 }
675 
677  cv::Mat& mapNodeOm,
678  WAIOrbVocabulary* voc,
679  std::string path,
680  bool loadImgs,
681  bool fixKfsAndMPts)
682 {
684 
685  std::vector<WAIMapPoint*> mapPoints;
686  std::vector<WAIKeyFrame*> keyFrames;
687  std::map<int, int> parentIdMap;
688  std::map<int, std::vector<int>> loopEdgesMap;
689  std::map<int, WAIKeyFrame*> kfsMap;
690  int numLoopClosings = 0;
691 
692  std::string imgDir;
693  if (loadImgs)
694  {
695  std::string dir = Utils::getPath(path);
696  imgDir = dir + Utils::getFileNameWOExt(path) + "/";
697  }
698 
699  FILE* f = fopen(path.c_str(), "rb");
700  if (!f)
701  return false;
702 
703  fseek(f, 0, SEEK_END);
704  uint32_t contentSize = ftell(f);
705  rewind(f);
706 
707  uint8_t* fContent = (uint8_t*)malloc(sizeof(uint8_t*) * contentSize);
708  uint8_t* fContentStart = fContent;
709  if (!fContent)
710  return false;
711 
712  size_t readResult = fread(fContent, 1, contentSize, f);
713  if (readResult != contentSize)
714  return false;
715 
716  fclose(f);
717 
718  MapInfo* mapInfo = (MapInfo*)fContent;
719  fContent += sizeof(MapInfo);
720 
721  if (mapInfo->nodeOmSaved)
722  {
723  cv::Mat cvMat = loadCVMatFromBinaryStream(&fContent, 4, 4, CV_32F);
724  mapNodeOm = cvMat.clone();
725  }
726 
727  std::map<int, std::vector<int>> bestCovisibleKeyFrameIdsMap;
728  std::map<int, std::vector<int>> bestCovisibleWeightsMap;
729 
730  for (int i = 0; i < mapInfo->kfCount; i++)
731  {
732  PROFILE_SCOPE("WAI::WAIMapStorage::loadMapBinary::keyFrames");
733 
734  KeyFrameInfo* kfInfo = (KeyFrameInfo*)fContent;
735  fContent += sizeof(KeyFrameInfo);
736 
737  int id = kfInfo->id;
738  int parentId = kfInfo->parentId;
739 
740  if (parentId != -1)
741  {
742  parentIdMap[id] = parentId;
743  }
744 
745  cv::Mat K = loadCVMatFromBinaryStream(&fContent, 3, 3, CV_32F);
746  cv::Mat Tcw = loadCVMatFromBinaryStream(&fContent, 4, 4, CV_32F);
747 
748  if (kfInfo->loopEdgesCount > 0)
749  {
750  std::vector<int32_t> loopEdges =
751  loadVectorFromBinaryStream<int32_t>(&fContent, kfInfo->loopEdgesCount);
752 
753  loopEdgesMap[id] = loopEdges;
754  }
755 
756  cv::Mat featureDescriptors = loadCVMatFromBinaryStream(&fContent, kfInfo->kpCount, 32, CV_8U);
757  std::vector<cv::KeyPoint> keyPtsUndist = loadVectorFromBinaryStream<cv::KeyPoint>(&fContent, kfInfo->kpCount);
758 
759  float scaleFactor = kfInfo->scaleFactor;
760  int nScaleLevels = kfInfo->scaleLevels;
761 
762  // vectors for precalculation of scalefactors
763  std::vector<float> vScaleFactor;
764  std::vector<float> vInvScaleFactor;
765  std::vector<float> vLevelSigma2;
766  std::vector<float> vInvLevelSigma2;
767  vScaleFactor.clear();
768  vLevelSigma2.clear();
769  vScaleFactor.resize(nScaleLevels);
770  vLevelSigma2.resize(nScaleLevels);
771  // todo: crashes when vScaleFactor is empty
772  vScaleFactor[0] = 1.0f;
773  vLevelSigma2[0] = 1.0f;
774  for (int j = 1; j < nScaleLevels; j++)
775  {
776  vScaleFactor[j] = vScaleFactor[j - 1] * scaleFactor;
777  vLevelSigma2[j] = vScaleFactor[j] * vScaleFactor[j];
778  }
779 
780  vInvScaleFactor.resize(nScaleLevels);
781  vInvLevelSigma2.resize(nScaleLevels);
782  for (int j = 0; j < nScaleLevels; j++)
783  {
784  vInvScaleFactor[j] = 1.0f / vScaleFactor[j];
785  vInvLevelSigma2[j] = 1.0f / vLevelSigma2[j];
786  }
787 
788  float fx, fy, cx, cy;
789  fx = K.at<float>(0, 0);
790  fy = K.at<float>(1, 1);
791  cx = K.at<float>(0, 2);
792  cy = K.at<float>(1, 2);
793 
794  // image bounds
795  float nMinX = kfInfo->minX;
796  float nMinY = kfInfo->minY;
797  float nMaxX = kfInfo->maxX;
798  float nMaxY = kfInfo->maxY;
799 
800  WAIKeyFrame* newKf = new WAIKeyFrame(Tcw,
801  id,
802  fixKfsAndMPts,
803  fx,
804  fy,
805  cx,
806  cy,
807  keyPtsUndist.size(),
808  keyPtsUndist,
809  featureDescriptors,
810  voc,
811  nScaleLevels,
812  scaleFactor,
813  vScaleFactor,
814  vLevelSigma2,
815  vInvLevelSigma2,
816  (int)nMinX,
817  (int)nMinY,
818  (int)nMaxX,
819  (int)nMaxY,
820  K);
821 
822  if (kfInfo->bowVecSize > 0)
823  {
824  std::vector<int32_t> wordsId = loadVectorFromBinaryStream<int32_t>(&fContent, kfInfo->bowVecSize);
825  std::vector<float> tfIdf = loadVectorFromBinaryStream<float>(&fContent, kfInfo->bowVecSize);
826 
827  WAIBowVector bow(wordsId, tfIdf);
828  newKf->SetBowVector(bow);
829  }
830 
831  if (imgDir != "")
832  {
833  stringstream ss;
834  ss << imgDir << "kf" << id << ".jpg";
835  // newKf->imgGray = kfImg;
836  if (Utils::fileExists(ss.str()))
837  {
838  newKf->setTexturePath(ss.str());
839  cv::Mat imgColor = cv::imread(ss.str());
840  cv::cvtColor(imgColor, newKf->imgGray, cv::COLOR_BGR2GRAY);
841  }
842  }
843 
844  keyFrames.push_back(newKf);
845  kfsMap[newKf->mnId] = newKf;
846 
847  std::vector<int32_t> bestCovisibleKeyFrameIds = loadVectorFromBinaryStream<int32_t>(&fContent, kfInfo->covisiblesCount);
848  std::vector<int32_t> bestCovisibleWeights = loadVectorFromBinaryStream<int32_t>(&fContent, kfInfo->covisiblesCount);
849 
850  bestCovisibleKeyFrameIdsMap[newKf->mnId] = bestCovisibleKeyFrameIds;
851  bestCovisibleWeightsMap[newKf->mnId] = bestCovisibleWeights;
852  }
853 
854  // set parent keyframe pointers into keyframes
855  for (WAIKeyFrame* kf : keyFrames)
856  {
857  if (kf->mnId != 0)
858  {
859  auto itParentId = parentIdMap.find(kf->mnId);
860  if (itParentId != parentIdMap.end())
861  {
862  int parentId = itParentId->second;
863  auto itParentKf = kfsMap.find(parentId);
864  if (itParentKf != kfsMap.end())
865  kf->ChangeParent(itParentKf->second);
866  else
867  cerr << "[WAIMapIO] loadKeyFrames: Parent does not exist of keyframe " << kf->mnId << "! FAIL" << endl;
868  }
869  else
870  cerr << "[WAIMapIO] loadKeyFrames: Parent does not exist of keyframe " << kf->mnId << "! FAIL" << endl;
871  }
872  }
873 
874  int numberOfLoopClosings = 0;
875  // set loop edge pointer into keyframes
876  for (WAIKeyFrame* kf : keyFrames)
877  {
878  auto it = loopEdgesMap.find(kf->mnId);
879  if (it != loopEdgesMap.end())
880  {
881  const auto& loopEdgeIds = it->second;
882  for (int loopKfId : loopEdgeIds)
883  {
884  auto loopKfIt = kfsMap.find(loopKfId);
885  if (loopKfIt != kfsMap.end())
886  {
887  kf->AddLoopEdge(loopKfIt->second);
888  numberOfLoopClosings++;
889  }
890  else
891  cerr << "[WAIMapIO] loadKeyFrames: Loop keyframe id does not exist! FAIL" << endl;
892  }
893  }
894  }
895  numLoopClosings = numberOfLoopClosings / 2;
896 
897  for (int i = 0; i < mapInfo->mpCount; i++)
898  {
899  PROFILE_SCOPE("WAI::WAIMapStorage::loadMapBinary::mapPoints");
900 
901  MapPointInfo* mpInfo = (MapPointInfo*)fContent;
902  fContent += sizeof(MapPointInfo);
903 
904  int id = mpInfo->id;
905 
906  cv::Mat mWorldPos = loadCVMatFromBinaryStream(&fContent, 3, 1, CV_32F);
907  std::vector<int32_t> observingKfIds = loadVectorFromBinaryStream<int32_t>(&fContent, mpInfo->nObervations);
908  std::vector<int32_t> corrKpIndices = loadVectorFromBinaryStream<int32_t>(&fContent, mpInfo->nObervations);
909 
910  cv::Mat normal = loadCVMatFromBinaryStream(&fContent, 3, 1, CV_32F);
911  cv::Mat descriptor = loadCVMatFromBinaryStream(&fContent, 1, 32, CV_8U);
912 
913  WAIMapPoint* newPt = new WAIMapPoint(id, mWorldPos, fixKfsAndMPts);
914  newPt->SetMinDistance(mpInfo->minDistance);
915  newPt->SetMaxDistance(mpInfo->maxDistance);
916  newPt->SetNormal(normal);
917  newPt->SetDescriptor(descriptor);
918 
919  // get reference keyframe id
920  int refKfId = (int)mpInfo->refKfId;
921  bool refKFFound = false;
922 
923  if (kfsMap.find(refKfId) != kfsMap.end())
924  {
925  newPt->refKf(kfsMap[refKfId]);
926  refKFFound = true;
927  }
928  else
929  {
930  cout << "no reference keyframe found!" << endl;
931  if (observingKfIds.size())
932  {
933  // we use the first of the observing keyframes
934  int kfId = observingKfIds[0];
935  if (kfsMap.find(kfId) != kfsMap.end())
936  {
937  newPt->refKf(kfsMap[kfId]);
938  refKFFound = true;
939  }
940  }
941  }
942 
943  if (refKFFound)
944  {
945  // find and add pointers of observing keyframes to map point
946  for (int j = 0; j < observingKfIds.size(); j++)
947  {
948  const int kfId = observingKfIds[j];
949  if (kfsMap.find(kfId) != kfsMap.end())
950  {
951  WAIKeyFrame* kf = kfsMap[kfId];
952  kf->AddMapPoint(newPt, corrKpIndices[j]);
953  newPt->AddObservation(kf, corrKpIndices[j]);
954  }
955  }
956  mapPoints.push_back(newPt);
957  }
958  else
959  {
960  delete newPt;
961  }
962  }
963 
964  // update the covisibility graph, when all keyframes and mappoints are loaded
965  WAIKeyFrame* firstKF = nullptr;
966  bool buildSpanningTree = false;
967  for (WAIKeyFrame* kf : keyFrames)
968  {
969  PROFILE_SCOPE("WAI::WAIMapStorage::loadMapBinary::updateConnections");
970 
971  std::map<WAIKeyFrame*, int> keyFrameWeightMap;
972 
973  std::vector<int> bestCovisibleKeyFrameIds = bestCovisibleKeyFrameIdsMap[kf->mnId];
974  std::vector<int> bestCovisibleWeights = bestCovisibleWeightsMap[kf->mnId];
975 
976  for (int i = 0; i < bestCovisibleKeyFrameIds.size(); i++)
977  {
978  int keyFrameId = bestCovisibleKeyFrameIds[i];
979  int weight = bestCovisibleWeights[i];
980  WAIKeyFrame* covisibleKF = kfsMap[keyFrameId];
981  keyFrameWeightMap[covisibleKF] = weight;
982  }
983 
984  kf->UpdateConnections(keyFrameWeightMap, false);
985 
986  if (kf->mnId == 0)
987  {
988  firstKF = kf;
989  }
990  else if (kf->GetParent() == NULL)
991  {
992  buildSpanningTree = true;
993  }
994  }
995 
996  wai_assert(firstKF && "Could not find keyframe with id 0\n");
997 
998  // Build spanning tree if keyframes have no parents (legacy support)
999  if (buildSpanningTree)
1000  {
1001  PROFILE_SCOPE("WAI::WAIMapStorage::loadMapBinary::buildSpanningTree");
1002 
1003  // QueueElem: <unconnected_kf, graph_kf, weight>
1004  using QueueElem = std::tuple<WAIKeyFrame*, WAIKeyFrame*, int>;
1005  auto cmpQueue = [](const QueueElem& left, const QueueElem& right)
1006  { return (std::get<2>(left) < std::get<2>(right)); };
1007  auto cmpMap = [](const pair<WAIKeyFrame*, int>& left, const pair<WAIKeyFrame*, int>& right)
1008  { return left.second < right.second; };
1009  std::set<WAIKeyFrame*> graph;
1010  std::set<WAIKeyFrame*> unconKfs;
1011  for (auto& kf : keyFrames)
1012  unconKfs.insert(kf);
1013 
1014  // pick first kf
1015  graph.insert(firstKF);
1016  unconKfs.erase(firstKF);
1017 
1018  while (unconKfs.size())
1019  {
1020  std::priority_queue<QueueElem, std::vector<QueueElem>, decltype(cmpQueue)> q(cmpQueue);
1021  // update queue with keyframes with neighbous in the graph
1022  for (auto& unconKf : unconKfs)
1023  {
1024  const std::map<WAIKeyFrame*, int>& weights = unconKf->GetConnectedKfWeights();
1025  for (auto& graphKf : graph)
1026  {
1027  auto it = weights.find(graphKf);
1028  if (it != weights.end())
1029  {
1030  QueueElem newElem = std::make_tuple(unconKf, it->first, it->second);
1031  q.push(newElem);
1032  }
1033  }
1034  }
1035 
1036  if (q.size() == 0)
1037  {
1038  // no connection: the remaining keyframes are unconnected
1039  Utils::log("WAIMapStorage", "Error in building spanning tree: There are %i unconnected keyframes!", unconKfs.size());
1040  break;
1041  }
1042  else
1043  {
1044  // extract keyframe with shortest connection
1045  QueueElem topElem = q.top();
1046  // remove it from unconKfs and add it to graph
1047  WAIKeyFrame* newGraphKf = std::get<0>(topElem);
1048  unconKfs.erase(newGraphKf);
1049  newGraphKf->ChangeParent(std::get<1>(topElem));
1050  // std::cout << "Added kf " << newGraphKf->mnId << " with parent " << std::get<1>(topElem)->mnId << std::endl;
1051  // update parent
1052  graph.insert(newGraphKf);
1053  }
1054  }
1055  }
1056 
1057  for (WAIKeyFrame* kf : keyFrames)
1058  {
1059  PROFILE_SCOPE("WAI::WAIMapStorage::loadMapBinary::addKeyFrame");
1060 
1061  if (kf->mBowVec.data.empty())
1062  {
1063  std::cout << "kf->mBowVec.data empty" << std::endl;
1064  continue;
1065  }
1066  waiMap->AddKeyFrame(kf);
1067  waiMap->GetKeyFrameDB()->add(kf);
1068 
1069  // Add keyframe with id 0 to this vector. Otherwise RunGlobalBundleAdjustment in LoopClosing after loop was detected crashes.
1070  if (kf->mnId == 0)
1071  {
1072  waiMap->mvpKeyFrameOrigins.push_back(kf);
1073  }
1074  }
1075 
1076  for (WAIMapPoint* point : mapPoints)
1077  {
1078  PROFILE_SCOPE("WAI::WAIMapStorage::loadMapBinary::addMapPoint");
1079 
1080  waiMap->AddMapPoint(point);
1081  }
1082 
1083  waiMap->setNumLoopClosings(numLoopClosings);
1084 
1085  free(fContentStart);
1086 
1087  return true;
1088 }
1089 
1091  cv::Mat& mapNodeOm,
1092  WAIOrbVocabulary* voc,
1093  std::string path,
1094  bool loadImgs,
1095  bool fixKfsAndMPts)
1096 {
1097  PROFILE_FUNCTION();
1098 
1099  std::vector<WAIMapPoint*> mapPoints;
1100  std::vector<WAIKeyFrame*> keyFrames;
1101  std::map<int, int> parentIdMap;
1102  std::map<int, std::vector<int>> loopEdgesMap;
1103  std::map<int, WAIKeyFrame*> kfsMap;
1104  int numLoopClosings = 0;
1105 
1106  std::string imgDir;
1107  if (loadImgs)
1108  {
1109  std::string dir = Utils::getPath(path);
1110  imgDir = dir + Utils::getFileNameWOExt(path) + "/";
1111  }
1112 
1113  cv::FileStorage fs(path, cv::FileStorage::READ);
1114 
1115  if (!fs.isOpened())
1116  {
1117  return false;
1118  }
1119 
1120  if (!fs["mapNodeOm"].empty())
1121  {
1122  fs["mapNodeOm"] >> mapNodeOm;
1123  }
1124 
1125  std::map<int, std::vector<int>> bestCovisibleKeyFrameIdsMap;
1126  std::map<int, std::vector<int>> bestCovisibleWeightsMap;
1127 
1128  bool updateKeyFrameConnections = false;
1129 
1130  cv::FileNode n = fs["KeyFrames"];
1131  for (auto it = n.begin(); it != n.end(); ++it)
1132  {
1133  int id = (*it)["id"];
1134  if (!(*it)["parentId"].empty())
1135  {
1136  int parentId = (*it)["parentId"];
1137  parentIdMap[id] = parentId;
1138  }
1139  if (!(*it)["loopEdges"].empty() && (*it)["loopEdges"].isSeq())
1140  {
1141  cv::FileNode les = (*it)["loopEdges"];
1142  std::vector<int> loopEdges;
1143  for (auto itLes = les.begin(); itLes != les.end(); ++itLes)
1144  {
1145  loopEdges.push_back((int)*itLes);
1146  }
1147  loopEdgesMap[id] = loopEdges;
1148  }
1149  cv::Mat Tcw; // has to be here!
1150  (*it)["Tcw"] >> Tcw;
1151 
1152  cv::Mat featureDescriptors; // has to be here!
1153  (*it)["featureDescriptors"] >> featureDescriptors;
1154  std::vector<cv::KeyPoint> keyPtsUndist;
1155  (*it)["keyPtsUndist"] >> keyPtsUndist;
1156 
1157  std::vector<int> wordsId;
1158  std::vector<float> tfIdf;
1159  if (!(*it)["BowVectorWordsId"].empty())
1160  (*it)["BowVectorWordsId"] >> wordsId;
1161  if (!(*it)["TfIdf"].empty())
1162  (*it)["TfIdf"] >> tfIdf;
1163 
1164  float scaleFactor;
1165  (*it)["scaleFactor"] >> scaleFactor;
1166  int nScaleLevels = -1;
1167  (*it)["nScaleLevels"] >> nScaleLevels;
1168 
1169  // vectors for precalculation of scalefactors
1170  std::vector<float> vScaleFactor;
1171  std::vector<float> vInvScaleFactor;
1172  std::vector<float> vLevelSigma2;
1173  std::vector<float> vInvLevelSigma2;
1174  vScaleFactor.clear();
1175  vLevelSigma2.clear();
1176  vScaleFactor.resize(nScaleLevels);
1177  vLevelSigma2.resize(nScaleLevels);
1178  vScaleFactor[0] = 1.0f;
1179  vLevelSigma2[0] = 1.0f;
1180  for (int i = 1; i < nScaleLevels; i++)
1181  {
1182  vScaleFactor[i] = vScaleFactor[i - 1] * scaleFactor;
1183  vLevelSigma2[i] = vScaleFactor[i] * vScaleFactor[i];
1184  }
1185 
1186  vInvScaleFactor.resize(nScaleLevels);
1187  vInvLevelSigma2.resize(nScaleLevels);
1188  for (int i = 0; i < nScaleLevels; i++)
1189  {
1190  vInvScaleFactor[i] = 1.0f / vScaleFactor[i];
1191  vInvLevelSigma2[i] = 1.0f / vLevelSigma2[i];
1192  }
1193 
1194  cv::Mat K;
1195  (*it)["K"] >> K;
1196  float fx, fy, cx, cy;
1197  fx = K.at<float>(0, 0);
1198  fy = K.at<float>(1, 1);
1199  cx = K.at<float>(0, 2);
1200  cy = K.at<float>(1, 2);
1201 
1202  // image bounds
1203  float nMinX, nMinY, nMaxX, nMaxY;
1204  (*it)["nMinX"] >> nMinX;
1205  (*it)["nMinY"] >> nMinY;
1206  (*it)["nMaxX"] >> nMaxX;
1207  (*it)["nMaxY"] >> nMaxY;
1208 
1209  WAIKeyFrame* newKf = new WAIKeyFrame(Tcw,
1210  id,
1211  fixKfsAndMPts,
1212  fx,
1213  fy,
1214  cx,
1215  cy,
1216  keyPtsUndist.size(),
1217  keyPtsUndist,
1218  featureDescriptors,
1219  voc,
1220  nScaleLevels,
1221  scaleFactor,
1222  vScaleFactor,
1223  vLevelSigma2,
1224  vInvLevelSigma2,
1225  (int)nMinX,
1226  (int)nMinY,
1227  (int)nMaxX,
1228  (int)nMaxY,
1229  K);
1230 
1231  if (!wordsId.empty() && !tfIdf.empty())
1232  {
1233  WAIBowVector bow(wordsId, tfIdf);
1234  newKf->SetBowVector(bow);
1235  }
1236 
1237  if (imgDir != "")
1238  {
1239  stringstream ss;
1240  ss << imgDir << "kf" << id << ".jpg";
1241  // newKf->imgGray = kfImg;
1242  if (Utils::fileExists(ss.str()))
1243  {
1244  newKf->setTexturePath(ss.str());
1245  cv::Mat imgColor = cv::imread(ss.str());
1246  cv::cvtColor(imgColor, newKf->imgGray, cv::COLOR_BGR2GRAY);
1247  }
1248  }
1249  keyFrames.push_back(newKf);
1250  kfsMap[newKf->mnId] = newKf;
1251 
1252  if (!(*it)["bestCovisibleKeyFrameIds"].empty() &&
1253  !(*it)["bestCovisibleWeights"].empty())
1254  {
1255  std::vector<int> bestCovisibleKeyFrameIds;
1256  (*it)["bestCovisibleKeyFrameIds"] >> bestCovisibleKeyFrameIds;
1257  std::vector<int> bestCovisibleWeights;
1258  (*it)["bestCovisibleWeights"] >> bestCovisibleWeights;
1259 
1260  bestCovisibleKeyFrameIdsMap[newKf->mnId] = bestCovisibleKeyFrameIds;
1261  bestCovisibleWeightsMap[newKf->mnId] = bestCovisibleWeights;
1262  }
1263  else
1264  {
1265  updateKeyFrameConnections = true;
1266  }
1267  }
1268 
1269  // set parent keyframe pointers into keyframes
1270  for (WAIKeyFrame* kf : keyFrames)
1271  {
1272  if (kf->mnId != 0)
1273  {
1274  auto itParentId = parentIdMap.find(kf->mnId);
1275  if (itParentId != parentIdMap.end())
1276  {
1277  int parentId = itParentId->second;
1278  auto itParentKf = kfsMap.find(parentId);
1279  if (itParentKf != kfsMap.end())
1280  kf->ChangeParent(itParentKf->second);
1281  else
1282  cerr << "[WAIMapIO] loadKeyFrames: Parent does not exist of keyframe " << kf->mnId << "! FAIL" << endl;
1283  }
1284  else
1285  cerr << "[WAIMapIO] loadKeyFrames: Parent does not exist of keyframe " << kf->mnId << "! FAIL" << endl;
1286  }
1287  }
1288 
1289  int numberOfLoopClosings = 0;
1290  // set loop edge pointer into keyframes
1291  for (WAIKeyFrame* kf : keyFrames)
1292  {
1293  auto it = loopEdgesMap.find(kf->mnId);
1294  if (it != loopEdgesMap.end())
1295  {
1296  const auto& loopEdgeIds = it->second;
1297  for (int loopKfId : loopEdgeIds)
1298  {
1299  auto loopKfIt = kfsMap.find(loopKfId);
1300  if (loopKfIt != kfsMap.end())
1301  {
1302  kf->AddLoopEdge(loopKfIt->second);
1303  numberOfLoopClosings++;
1304  }
1305  else
1306  cerr << "[WAIMapIO] loadKeyFrames: Loop keyframe id does not exist! FAIL" << endl;
1307  }
1308  }
1309  }
1310  numLoopClosings = numberOfLoopClosings / 2;
1311 
1312  n = fs["MapPoints"];
1313  if (n.type() != cv::FileNode::SEQ)
1314  {
1315  cerr << "strings is not a sequence! FAIL" << endl;
1316  }
1317 
1318  bool needMapPointUpdate = false;
1319  for (auto it = n.begin(); it != n.end(); ++it)
1320  {
1321  // newPt->id( (int)(*it)["id"]);
1322  int id = (int)(*it)["id"];
1323 
1324  cv::Mat mWorldPos; // has to be here!
1325  (*it)["mWorldPos"] >> mWorldPos;
1326 
1327  WAIMapPoint* newPt = new WAIMapPoint(id, mWorldPos, fixKfsAndMPts);
1328  vector<int> observingKfIds;
1329  (*it)["observingKfIds"] >> observingKfIds;
1330  vector<int> corrKpIndices;
1331  (*it)["corrKpIndices"] >> corrKpIndices;
1332 
1333  // get reference keyframe id
1334  int refKfId = (int)(*it)["refKfId"];
1335  bool refKFFound = false;
1336 
1337  if (kfsMap.find(refKfId) != kfsMap.end())
1338  {
1339  newPt->refKf(kfsMap[refKfId]);
1340  refKFFound = true;
1341  }
1342  else
1343  {
1344  cout << "no reference keyframe found!" << endl;
1345  if (observingKfIds.size())
1346  {
1347  // we use the first of the observing keyframes
1348  int kfId = observingKfIds[0];
1349  if (kfsMap.find(kfId) != kfsMap.end())
1350  {
1351  newPt->refKf(kfsMap[kfId]);
1352  refKFFound = true;
1353  }
1354  }
1355  }
1356 
1357  if (!(*it)["mfMaxDistance"].empty() &&
1358  !(*it)["mfMinDistance"].empty() &&
1359  !(*it)["mNormalVector"].empty() &&
1360  !(*it)["mDescriptor"].empty())
1361  {
1362  newPt->SetMaxDistance((float)(*it)["mfMaxDistance"]);
1363  newPt->SetMinDistance((float)(*it)["mfMinDistance"]);
1364  cv::Mat normal, descriptor;
1365  (*it)["mNormalVector"] >> normal;
1366  (*it)["mDescriptor"] >> descriptor;
1367  newPt->SetNormal(normal);
1368  newPt->SetDescriptor(descriptor);
1369  }
1370  else
1371  {
1372  needMapPointUpdate = true;
1373  }
1374 
1375  if (refKFFound)
1376  {
1377  // find and add pointers of observing keyframes to map point
1378  for (int i = 0; i < observingKfIds.size(); ++i)
1379  {
1380  const int kfId = observingKfIds[i];
1381  if (kfsMap.find(kfId) != kfsMap.end())
1382  {
1383  WAIKeyFrame* kf = kfsMap[kfId];
1384  kf->AddMapPoint(newPt, corrKpIndices[i]);
1385  newPt->AddObservation(kf, corrKpIndices[i]);
1386  }
1387  }
1388  mapPoints.push_back(newPt);
1389  }
1390  else
1391  {
1392  delete newPt;
1393  }
1394  }
1395 
1396  std::cout << "update the covisibility graph, when all keyframes and mappoints are loaded" << std::endl;
1397  // update the covisibility graph, when all keyframes and mappoints are loaded
1398  WAIKeyFrame* firstKF = nullptr;
1399  bool buildSpanningTree = false;
1400  for (WAIKeyFrame* kf : keyFrames)
1401  {
1402  if (updateKeyFrameConnections)
1403  {
1404  // Update links in the Covisibility Graph, do not build the spanning tree yet
1405  kf->FindAndUpdateConnections(false);
1406  }
1407  else
1408  {
1409  std::map<WAIKeyFrame*, int> keyFrameWeightMap;
1410 
1411  std::vector<int> bestCovisibleKeyFrameIds = bestCovisibleKeyFrameIdsMap[kf->mnId];
1412  std::vector<int> bestCovisibleWeights = bestCovisibleWeightsMap[kf->mnId];
1413 
1414  for (int i = 0; i < bestCovisibleKeyFrameIds.size(); i++)
1415  {
1416  int keyFrameId = bestCovisibleKeyFrameIds[i];
1417  int weight = bestCovisibleWeights[i];
1418  WAIKeyFrame* covisibleKF = kfsMap[keyFrameId];
1419  keyFrameWeightMap[covisibleKF] = weight;
1420  }
1421 
1422  kf->UpdateConnections(keyFrameWeightMap, false);
1423  }
1424  if (kf->mnId == 0)
1425  {
1426  firstKF = kf;
1427  }
1428  else if (kf->GetParent() == NULL)
1429  {
1430  buildSpanningTree = true;
1431  }
1432  }
1433 
1434  wai_assert(firstKF && "Could not find keyframe with id 0\n");
1435 
1436  // Build spanning tree if keyframes have no parents (legacy support)
1437  if (buildSpanningTree)
1438  {
1439  // QueueElem: <unconnected_kf, graph_kf, weight>
1440  using QueueElem = std::tuple<WAIKeyFrame*, WAIKeyFrame*, int>;
1441  auto cmpQueue = [](const QueueElem& left, const QueueElem& right)
1442  { return (std::get<2>(left) < std::get<2>(right)); };
1443  auto cmpMap = [](const pair<WAIKeyFrame*, int>& left, const pair<WAIKeyFrame*, int>& right)
1444  { return left.second < right.second; };
1445  std::set<WAIKeyFrame*> graph;
1446  std::set<WAIKeyFrame*> unconKfs;
1447  for (auto& kf : keyFrames)
1448  unconKfs.insert(kf);
1449 
1450  // pick first kf
1451  graph.insert(firstKF);
1452  unconKfs.erase(firstKF);
1453 
1454  while (unconKfs.size())
1455  {
1456  std::priority_queue<QueueElem, std::vector<QueueElem>, decltype(cmpQueue)> q(cmpQueue);
1457  // update queue with keyframes with neighbous in the graph
1458  for (auto& unconKf : unconKfs)
1459  {
1460  const std::map<WAIKeyFrame*, int>& weights = unconKf->GetConnectedKfWeights();
1461  for (auto& graphKf : graph)
1462  {
1463  auto it = weights.find(graphKf);
1464  if (it != weights.end())
1465  {
1466  QueueElem newElem = std::make_tuple(unconKf, it->first, it->second);
1467  q.push(newElem);
1468  }
1469  }
1470  }
1471 
1472  if (q.size() == 0)
1473  {
1474  // no connection: the remaining keyframes are unconnected
1475  Utils::log("WAIMapStorage", "Error in building spanning tree: There are %i unconnected keyframes!");
1476  break;
1477  }
1478  else
1479  {
1480  // extract keyframe with shortest connection
1481  QueueElem topElem = q.top();
1482  // remove it from unconKfs and add it to graph
1483  WAIKeyFrame* newGraphKf = std::get<0>(topElem);
1484  unconKfs.erase(newGraphKf);
1485  newGraphKf->ChangeParent(std::get<1>(topElem));
1486  // std::cout << "Added kf " << newGraphKf->mnId << " with parent " << std::get<1>(topElem)->mnId << std::endl;
1487  // update parent
1488  graph.insert(newGraphKf);
1489  }
1490  }
1491  }
1492 
1493  if (needMapPointUpdate)
1494  {
1495  PROFILE_SCOPE("Updating MapPoints");
1496 
1497  // compute resulting values for map points
1498  for (WAIMapPoint*& mp : mapPoints)
1499  {
1500  // mean viewing direction and depth
1501  mp->UpdateNormalAndDepth();
1502  mp->ComputeDistinctiveDescriptors();
1503  }
1504  }
1505 
1506  for (WAIKeyFrame* kf : keyFrames)
1507  {
1508  if (kf->mBowVec.data.empty())
1509  {
1510  std::cout << "kf->mBowVec.data empty" << std::endl;
1511  continue;
1512  }
1513  waiMap->AddKeyFrame(kf);
1514  waiMap->GetKeyFrameDB()->add(kf);
1515 
1516  // Add keyframe with id 0 to this vector. Otherwise RunGlobalBundleAdjustment in LoopClosing after loop was detected crashes.
1517  if (kf->mnId == 0)
1518  {
1519  waiMap->mvpKeyFrameOrigins.push_back(kf);
1520  }
1521  }
1522 
1523  for (WAIMapPoint* point : mapPoints)
1524  {
1525  waiMap->AddMapPoint(point);
1526  }
1527 
1528  waiMap->setNumLoopClosings(numLoopClosings);
1529  return true;
1530 }
1531 
1532 void WAIMapStorage::saveKeyFrameVideoMatching(std::vector<int>& keyFrameVideoMatching, std::vector<std::string> vidname, const std::string& dir, const std::string outputKFMatchingFile)
1533 {
1534  if (!Utils::dirExists(dir))
1535  Utils::makeDir(dir);
1536 
1537  std::ofstream ofs;
1538  ofs.open(dir + "/" + outputKFMatchingFile, std::ofstream::out);
1539 
1540  ofs << to_string(vidname.size()) << "\n";
1541 
1542  for (int i = 0; i < vidname.size(); i++)
1543  {
1544  vidname[i] = Utils::getFileName(vidname[i]);
1545  ofs << vidname[i] << "\n";
1546  }
1547 
1548  for (int i = 0; i < keyFrameVideoMatching.size(); i++)
1549  {
1550  if (keyFrameVideoMatching[i] >= 0)
1551  {
1552  ofs << to_string(i) + " " + to_string(keyFrameVideoMatching[i]) << "\n";
1553  }
1554  }
1555  ofs.close();
1556 }
1557 
1558 void WAIMapStorage::loadKeyFrameVideoMatching(std::vector<int>& keyFrameVideoMatching, std::vector<std::string>& vidname, const std::string& dir, const std::string kFMatchingFile)
1559 {
1560  std::ifstream ifs(dir + "/" + kFMatchingFile);
1561  keyFrameVideoMatching.resize(1000, -1);
1562 
1563  int nVid;
1564  ifs >> nVid;
1565  vidname.resize(nVid);
1566 
1567  for (int i = 0; i < nVid; i++)
1568  {
1569  ifs >> vidname[i];
1570  vidname[i] = Utils::getFileName(vidname[i]);
1571  }
1572 
1573  int kfId;
1574  int vid;
1575  while (ifs >> kfId >> vid)
1576  {
1577  if (kfId > keyFrameVideoMatching.size())
1578  {
1579  keyFrameVideoMatching.resize(keyFrameVideoMatching.size() * 2, -1);
1580  }
1581  keyFrameVideoMatching[kfId] = vid;
1582  }
1583 
1584  ifs.close();
1585 }
vector< cv::KeyPoint > CVVKeyPoint
Definition: CVTypedefs.h:88
#define PROFILE_SCOPE(name)
Definition: Instrumentor.h:40
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
#define wai_assert(expression)
Definition: WAIHelper.h:67
void saveKeyFrames(std::vector< WAIKeyFrame * > &kfs, std::map< WAIKeyFrame *, std::map< size_t, size_t >> &KFmatching, cv::FileStorage &fs, std::string imgDir, bool saveBOW)
void saveMapPoints(std::vector< WAIMapPoint * > mpts, std::map< WAIKeyFrame *, std::map< size_t, size_t >> &KFmatching, cv::FileStorage &fs)
void buildMatching(std::vector< WAIKeyFrame * > &kfs, std::map< WAIKeyFrame *, std::map< size_t, size_t >> &KFmatching)
void setMatrix(const SLMat4 &A)
Set matrix by other 4x4 matrix.
Definition: SLMat4.h:335
void m(int i, T val)
Definition: SLMat4.h:93
SLstring toString() const
Definition: SLMat4.h:1567
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
void om(const SLMat4f &mat)
Definition: SLNode.h:276
void add(WAIKeyFrame *pKF)
AR Keyframe node class.
Definition: WAIKeyFrame.h:60
void SetBowVector(WAIBowVector &bow)
const cv::Mat mK
Definition: WAIKeyFrame.h:245
WAIBowVector mBowVec
Definition: WAIKeyFrame.h:226
std::vector< WAIKeyFrame * > GetBestCovisibilityKeyFrames(const int &N)
const int mnMaxX
Definition: WAIKeyFrame.h:243
void AddMapPoint(WAIMapPoint *pMP, size_t idx)
const int mnScaleLevels
Definition: WAIKeyFrame.h:233
void setTexturePath(const std::string &path)
Definition: WAIKeyFrame.h:291
const int mnMinY
Definition: WAIKeyFrame.h:242
void ChangeParent(WAIKeyFrame *pKF)
WAIKeyFrame * GetParent()
long unsigned int mnId
Definition: WAIKeyFrame.h:175
const float mfScaleFactor
Definition: WAIKeyFrame.h:234
void FindAndUpdateConnections(bool buildSpanningTree=true)
std::set< WAIKeyFrame * > GetLoopEdges()
cv::Mat GetPose()
const int mnMaxY
Definition: WAIKeyFrame.h:244
const int mnMinX
Definition: WAIKeyFrame.h:241
const std::vector< cv::KeyPoint > mvKeysUn
Definition: WAIKeyFrame.h:220
cv::Mat imgGray
Definition: WAIKeyFrame.h:248
void UpdateConnections(std::map< WAIKeyFrame *, int > KFcounter, bool buildSpanningTree)
std::vector< WAIMapPoint * > GetMapPointMatches()
const cv::Mat mDescriptors
Definition: WAIKeyFrame.h:223
int GetWeight(WAIKeyFrame *pKF)
Definition: WAIMap.h:52
vector< WAIKeyFrame * > mvpKeyFrameOrigins
Definition: WAIMap.h:88
void AddKeyFrame(WAIKeyFrame *pKF)
Definition: WAIMap.cpp:49
void setNumLoopClosings(int n)
Definition: WAIMap.cpp:469
std::vector< WAIKeyFrame * > GetAllKeyFrames()
Definition: WAIMap.cpp:104
WAIKeyFrameDB * GetKeyFrameDB()
Definition: WAIMap.h:78
void AddMapPoint(WAIMapPoint *pMP)
Definition: WAIMap.cpp:58
std::vector< WAIMapPoint * > GetAllMapPoints()
Definition: WAIMap.cpp:110
void SetMinDistance(float minDist)
void AddObservation(WAIKeyFrame *pKF, size_t idx)
long unsigned int mnId
Definition: WAIMapPoint.h:108
std::map< WAIKeyFrame *, size_t > GetObservations()
cv::Mat GetNormal()
void SetDescriptor(const cv::Mat &descriptor)
cv::Mat GetDescriptor()
void SetNormal(const cv::Mat &normal)
float GetMaxDistance()
float GetMinDistance()
cv::Mat GetWorldPos()
void SetMaxDistance(float maxDist)
WAIKeyFrame * refKf() const
Definition: WAIMapPoint.h:90
static bool saveMapRaw(WAIMap *waiMap, SLNode *mapNode, std::string fileName, std::string imgDir="")
static void saveKeyFrameVideoMatching(std::vector< int > &keyFrameVideoMatching, std::vector< std::string > vidname, const std::string &mapDir, const std::string outputKFMatchingFile)
static std::vector< T > loadVectorFromBinaryStream(uint8_t **data, int count)
static void writeVectorToBinaryFile(FILE *f, const std::vector< T > vec)
static cv::Mat convertToCVMat(const SLMat4f slMat)
static void writeCVMatToBinaryFile(FILE *f, const cv::Mat &mat)
static bool saveMapBinary(WAIMap *waiMap, SLNode *mapNode, std::string fileName, std::string imgDir="", bool saveBOW=true)
static bool loadMap(WAIMap *waiMap, cv::Mat &mapNodeOm, WAIOrbVocabulary *voc, std::string path, bool loadImgs, bool fixKfsAndMPts)
static cv::Mat loadCVMatFromBinaryStream(uint8_t **data, int rows, int cols, int type)
static SLMat4f convertToSLMat(const cv::Mat &cvMat)
static void loadKeyFrameVideoMatching(std::vector< int > &keyFrameVideoMatching, std::vector< std::string > &vidname, const std::string &mapDir, const std::string outputKFMatchingFile)
static std::vector< uint8_t > convertCVMatToVector(const cv::Mat &mat)
static bool loadMapBinary(WAIMap *waiMap, cv::Mat &mapNodeOm, WAIOrbVocabulary *voc, std::string path, bool loadImgs, bool fixKfsAndMPts)
static bool saveMap(WAIMap *waiMap, SLNode *mapNode, std::string fileName, std::string imgDir="", bool saveBOW=true)
bool fileExists(const string &pathfilename)
Returns true if a file exists.
Definition: Utils.cpp:897
bool dirExists(const string &path)
Returns true if a directory exists.
Definition: Utils.cpp:790
bool makeDir(const string &path)
Creates a directory with given path.
Definition: Utils.cpp:810
string getFileNameWOExt(const string &pathFilename)
Returns the filename without extension.
Definition: Utils.cpp:616
string getFileName(const string &pathFilename)
Returns the filename of path-filename string.
Definition: Utils.cpp:580
string getPath(const string &pathFilename)
Returns the path w. '\' of path-filename string.
Definition: Utils.cpp:392
void log(const char *tag, const char *format,...)
logs a formatted string platform independently
Definition: Utils.cpp:1103
fbow::fBow & getWordScoreMapping()
fbow::fBow data