SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
WAIMapStorage Class Reference

#include <WAIMapStorage.h>

Classes

struct  KeyFrameInfo
 
struct  KeyPointData
 
struct  MapInfo
 
struct  MapPointInfo
 

Static Public Member Functions

static bool saveMap (WAIMap *waiMap, SLNode *mapNode, std::string fileName, std::string imgDir="", bool saveBOW=true)
 
static bool saveMapRaw (WAIMap *waiMap, SLNode *mapNode, std::string fileName, std::string imgDir="")
 
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 bool loadMapBinary (WAIMap *waiMap, cv::Mat &mapNodeOm, WAIOrbVocabulary *voc, std::string path, bool loadImgs, bool fixKfsAndMPts)
 
static cv::Mat convertToCVMat (const SLMat4f slMat)
 
static SLMat4f convertToSLMat (const cv::Mat &cvMat)
 
static std::vector< uint8_t > convertCVMatToVector (const cv::Mat &mat)
 
static void saveKeyFrameVideoMatching (std::vector< int > &keyFrameVideoMatching, std::vector< std::string > vidname, const std::string &mapDir, const std::string outputKFMatchingFile)
 
static void loadKeyFrameVideoMatching (std::vector< int > &keyFrameVideoMatching, std::vector< std::string > &vidname, const std::string &mapDir, const std::string outputKFMatchingFile)
 
template<typename T >
static void writeVectorToBinaryFile (FILE *f, const std::vector< T > vec)
 
template<typename T >
static std::vector< T > loadVectorFromBinaryStream (uint8_t **data, int count)
 
static void writeCVMatToBinaryFile (FILE *f, const cv::Mat &mat)
 
static cv::Mat loadCVMatFromBinaryStream (uint8_t **data, int rows, int cols, int type)
 

Detailed Description

Definition at line 11 of file WAIMapStorage.h.

Member Function Documentation

◆ convertCVMatToVector()

std::vector< uint8_t > WAIMapStorage::convertCVMatToVector ( const cv::Mat &  mat)
static

Definition at line 366 of file WAIMapStorage.cpp.

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 }

◆ convertToCVMat()

cv::Mat WAIMapStorage::convertToCVMat ( const SLMat4f  slMat)
static

Definition at line 4 of file WAIMapStorage.cpp.

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 }
void m(int i, T val)
Definition: SLMat4.h:93

◆ convertToSLMat()

SLMat4f WAIMapStorage::convertToSLMat ( const cv::Mat &  cvMat)
static

Definition at line 36 of file WAIMapStorage.cpp.

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 }
void setMatrix(const SLMat4 &A)
Set matrix by other 4x4 matrix.
Definition: SLMat4.h:335

◆ loadCVMatFromBinaryStream()

cv::Mat WAIMapStorage::loadCVMatFromBinaryStream ( uint8_t **  data,
int  rows,
int  cols,
int  type 
)
static

Definition at line 664 of file WAIMapStorage.cpp.

668 {
669  cv::Mat result = cv::Mat(rows, cols, type, *data);
670 
671  *data += rows * cols * result.elemSize();
672 
673  return result;
674 }

◆ loadKeyFrameVideoMatching()

void WAIMapStorage::loadKeyFrameVideoMatching ( std::vector< int > &  keyFrameVideoMatching,
std::vector< std::string > &  vidname,
const std::string &  mapDir,
const std::string  outputKFMatchingFile 
)
static

Definition at line 1558 of file WAIMapStorage.cpp.

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 }
string getFileName(const string &pathFilename)
Returns the filename of path-filename string.
Definition: Utils.cpp:580

◆ loadMap()

bool WAIMapStorage::loadMap ( WAIMap waiMap,
cv::Mat &  mapNodeOm,
WAIOrbVocabulary voc,
std::string  path,
bool  loadImgs,
bool  fixKfsAndMPts 
)
static

Definition at line 1090 of file WAIMapStorage.cpp.

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 }
#define PROFILE_SCOPE(name)
Definition: Instrumentor.h:40
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
#define wai_assert(expression)
Definition: WAIHelper.h:67
void add(WAIKeyFrame *pKF)
AR Keyframe node class.
Definition: WAIKeyFrame.h:60
void SetBowVector(WAIBowVector &bow)
void AddMapPoint(WAIMapPoint *pMP, size_t idx)
void setTexturePath(const std::string &path)
Definition: WAIKeyFrame.h:291
void ChangeParent(WAIKeyFrame *pKF)
long unsigned int mnId
Definition: WAIKeyFrame.h:175
void FindAndUpdateConnections(bool buildSpanningTree=true)
cv::Mat imgGray
Definition: WAIKeyFrame.h:248
void UpdateConnections(std::map< WAIKeyFrame *, int > KFcounter, bool buildSpanningTree)
vector< WAIKeyFrame * > mvpKeyFrameOrigins
Definition: WAIMap.h:88
void AddKeyFrame(WAIKeyFrame *pKF)
Definition: WAIMap.cpp:49
void setNumLoopClosings(int n)
Definition: WAIMap.cpp:469
WAIKeyFrameDB * GetKeyFrameDB()
Definition: WAIMap.h:78
void AddMapPoint(WAIMapPoint *pMP)
Definition: WAIMap.cpp:58
void SetMinDistance(float minDist)
void AddObservation(WAIKeyFrame *pKF, size_t idx)
void SetDescriptor(const cv::Mat &descriptor)
void SetNormal(const cv::Mat &normal)
void SetMaxDistance(float maxDist)
WAIKeyFrame * refKf() const
Definition: WAIMapPoint.h:90
bool fileExists(const string &pathfilename)
Returns true if a file exists.
Definition: Utils.cpp:897
string getFileNameWOExt(const string &pathFilename)
Returns the filename without extension.
Definition: Utils.cpp:616
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

◆ loadMapBinary()

bool WAIMapStorage::loadMapBinary ( WAIMap waiMap,
cv::Mat &  mapNodeOm,
WAIOrbVocabulary voc,
std::string  path,
bool  loadImgs,
bool  fixKfsAndMPts 
)
static

Definition at line 676 of file WAIMapStorage.cpp.

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 }
static cv::Mat loadCVMatFromBinaryStream(uint8_t **data, int rows, int cols, int type)

◆ loadVectorFromBinaryStream()

template<typename T >
std::vector< T > WAIMapStorage::loadVectorFromBinaryStream ( uint8_t **  data,
int  count 
)
static

Definition at line 655 of file WAIMapStorage.cpp.

656 {
657  std::vector<T> result((T*)(*data), ((T*)(*data)) + count);
658  *data += sizeof(T) * count;
659 
660  return result;
661 }

◆ saveKeyFrameVideoMatching()

void WAIMapStorage::saveKeyFrameVideoMatching ( std::vector< int > &  keyFrameVideoMatching,
std::vector< std::string >  vidname,
const std::string &  mapDir,
const std::string  outputKFMatchingFile 
)
static

Definition at line 1532 of file WAIMapStorage.cpp.

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 }
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

◆ saveMap()

bool WAIMapStorage::saveMap ( WAIMap waiMap,
SLNode mapNode,
std::string  fileName,
std::string  imgDir = "",
bool  saveBOW = true 
)
static

Definition at line 287 of file WAIMapStorage.cpp.

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 }
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)
SLstring toString() const
Definition: SLMat4.h:1567
void om(const SLMat4f &mat)
Definition: SLNode.h:276
std::vector< WAIKeyFrame * > GetAllKeyFrames()
Definition: WAIMap.cpp:104
std::vector< WAIMapPoint * > GetAllMapPoints()
Definition: WAIMap.cpp:110
static cv::Mat convertToCVMat(const SLMat4f slMat)

◆ saveMapBinary()

bool WAIMapStorage::saveMapBinary ( WAIMap waiMap,
SLNode mapNode,
std::string  fileName,
std::string  imgDir = "",
bool  saveBOW = true 
)
static

Definition at line 392 of file WAIMapStorage.cpp.

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 }
vector< cv::KeyPoint > CVVKeyPoint
Definition: CVTypedefs.h:88
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
const int mnScaleLevels
Definition: WAIKeyFrame.h:233
const int mnMinY
Definition: WAIKeyFrame.h:242
WAIKeyFrame * GetParent()
const float mfScaleFactor
Definition: WAIKeyFrame.h:234
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
const cv::Mat mDescriptors
Definition: WAIKeyFrame.h:223
int GetWeight(WAIKeyFrame *pKF)
long unsigned int mnId
Definition: WAIMapPoint.h:108
std::map< WAIKeyFrame *, size_t > GetObservations()
cv::Mat GetNormal()
cv::Mat GetDescriptor()
float GetMaxDistance()
float GetMinDistance()
cv::Mat GetWorldPos()
static void writeVectorToBinaryFile(FILE *f, const std::vector< T > vec)
static void writeCVMatToBinaryFile(FILE *f, const cv::Mat &mat)
fbow::fBow & getWordScoreMapping()
fbow::fBow data

◆ saveMapRaw()

bool WAIMapStorage::saveMapRaw ( WAIMap waiMap,
SLNode mapNode,
std::string  fileName,
std::string  imgDir = "" 
)
static

Definition at line 327 of file WAIMapStorage.cpp.

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 }

◆ writeCVMatToBinaryFile()

void WAIMapStorage::writeCVMatToBinaryFile ( FILE *  f,
const cv::Mat &  mat 
)
static

Definition at line 385 of file WAIMapStorage.cpp.

386 {
387  std::vector<uint8_t> data = convertCVMatToVector(mat);
388 
389  writeVectorToBinaryFile(f, data);
390 }
static std::vector< uint8_t > convertCVMatToVector(const cv::Mat &mat)

◆ writeVectorToBinaryFile()

template<typename T >
void WAIMapStorage::writeVectorToBinaryFile ( FILE *  f,
const std::vector< T >  vec 
)
static

Definition at line 380 of file WAIMapStorage.cpp.

381 {
382  fwrite(vec.data(), sizeof(T), vec.size(), f);
383 }

The documentation for this class was generated from the following files: