MRPT  1.9.9
CLandmarksMap.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "vision-precomp.h" // Precompiled headers
11 
13 #include <mrpt/maps/CLandmark.h>
15 #include <mrpt/math/geometry.h>
16 #include <mrpt/math/ops_matrices.h>
28 #include <mrpt/random.h>
29 #include <mrpt/system/os.h>
30 #include <Eigen/Dense>
31 
32 using namespace mrpt;
33 using namespace mrpt::math;
34 using namespace mrpt::maps;
35 using namespace mrpt::obs;
36 using namespace mrpt::poses;
37 using namespace mrpt::tfest;
38 using namespace mrpt::random;
39 using namespace mrpt::system;
40 using namespace mrpt::vision;
41 using namespace mrpt::img;
42 using namespace mrpt::containers;
43 using namespace std;
45 
46 // =========== Begin of Map definition ============
48  "mrpt::maps::CLandmarksMap,landmarksMap", mrpt::maps::CLandmarksMap)
49 
50 CLandmarksMap::TMapDefinition::TMapDefinition() = default;
51 void CLandmarksMap::TMapDefinition::loadFromConfigFile_map_specific(
52  const mrpt::config::CConfigFileBase& source,
53  const std::string& sectionNamePrefix)
54 {
55  // [<sectionNamePrefix>+"_creationOpts"]
56  const std::string sSectCreation =
57  sectionNamePrefix + string("_creationOpts");
58  this->initialBeacons.clear();
59  const unsigned int nBeacons = source.read_int(sSectCreation, "nBeacons", 0);
60  for (unsigned int q = 1; q <= nBeacons; q++)
61  {
62  TPairIdBeacon newPair;
63  newPair.second =
64  source.read_int(sSectCreation, format("beacon_%03u_ID", q), 0);
65 
66  newPair.first.x =
67  source.read_float(sSectCreation, format("beacon_%03u_x", q), 0);
68  newPair.first.y =
69  source.read_float(sSectCreation, format("beacon_%03u_y", q), 0);
70  newPair.first.z =
71  source.read_float(sSectCreation, format("beacon_%03u_z", q), 0);
72 
73  this->initialBeacons.push_back(newPair);
74  }
75 
76  insertionOpts.loadFromConfigFile(
77  source, sectionNamePrefix + string("_insertOpts"));
78  likelihoodOpts.loadFromConfigFile(
79  source, sectionNamePrefix + string("_likelihoodOpts"));
80 }
81 
82 void CLandmarksMap::TMapDefinition::dumpToTextStream_map_specific(
83  std::ostream& out) const
84 {
85  out << mrpt::format(
86  "number of initial beacons = %u\n",
87  (int)initialBeacons.size());
88 
89  out << " ID (X,Y,Z)\n";
90  out << "--------------------------------------------------------\n";
91  for (const auto& initialBeacon : initialBeacons)
92  out << mrpt::format(
93  " %03u (%8.03f,%8.03f,%8.03f)\n", initialBeacon.second,
94  initialBeacon.first.x, initialBeacon.first.y,
95  initialBeacon.first.z);
96 
97  this->insertionOpts.dumpToTextStream(out);
98  this->likelihoodOpts.dumpToTextStream(out);
99 }
100 
101 mrpt::maps::CMetricMap* CLandmarksMap::internal_CreateFromMapDefinition(
103 {
104  const CLandmarksMap::TMapDefinition& def =
105  *dynamic_cast<const CLandmarksMap::TMapDefinition*>(&_def);
106  auto* obj = new CLandmarksMap();
107 
108  for (const auto& initialBeacon : def.initialBeacons)
109  {
110  CLandmark lm;
111 
112  lm.createOneFeature();
113  lm.features[0].type = featBeacon;
114 
115  lm.features[0].keypoint.ID = initialBeacon.second;
116  lm.ID = initialBeacon.second;
117 
118  lm.pose_mean = initialBeacon.first;
119 
120  lm.pose_cov_11 = lm.pose_cov_22 = lm.pose_cov_33 = lm.pose_cov_12 =
121  lm.pose_cov_13 = lm.pose_cov_23 = square(0.01f);
122 
123  obj->landmarks.push_back(lm);
124  }
125 
126  obj->insertionOptions = def.insertionOpts;
127  obj->likelihoodOptions = def.likelihoodOpts;
128  return obj;
129 }
130 // =========== End of Map definition Block =========
131 
133 
134 /*---------------------------------------------------------------
135  Static variables initialization
136  ---------------------------------------------------------------*/
137 std::map<
138  std::pair<
140  double>
141  CLandmarksMap::_mEDD;
142 mrpt::maps::CLandmark::TLandmarkID CLandmarksMap::_mapMaxID;
143 bool CLandmarksMap::_maxIDUpdated = false;
144 
145 void CLandmarksMap::internal_clear() { landmarks.clear(); }
146 
147 size_t CLandmarksMap::size() const { return landmarks.size(); }
148 
149 uint8_t CLandmarksMap::serializeGetVersion() const { return 0; }
150 void CLandmarksMap::serializeTo(mrpt::serialization::CArchive& out) const
151 {
152  uint32_t n = landmarks.size();
153 
154  // First, write the number of landmarks:
155  out << n;
156 
157  // Write all landmarks:
158  for (const auto& landmark : landmarks) out << landmark;
159 }
160 
161 void CLandmarksMap::serializeFrom(
162  mrpt::serialization::CArchive& in, uint8_t version)
163 {
164  switch (version)
165  {
166  case 0:
167  {
168  uint32_t n, i;
169  CLandmark lm;
170 
171  // Delete previous content of map:
172  // -------------------------------------
173  landmarks.clear();
174 
175  // Load from stream:
176  // -------------------------------------
177  in >> n;
178 
179  landmarks.clear(); // resize(n);
180 
181  // Read all landmarks:
182  for (i = 0; i < n; i++)
183  {
184  in >> lm;
185  landmarks.push_back(lm);
186  }
187  }
188  break;
189  default:
191  };
192 }
193 
194 /*---------------------------------------------------------------
195  computeObservationLikelihood
196  ---------------------------------------------------------------*/
197 double CLandmarksMap::internal_computeObservationLikelihood(
198  const CObservation& obs, const CPose3D& robotPose3D)
199 {
200  MRPT_START
201 
203  insertionOptions.insert_Landmarks_from_range_scans)
204  {
205  /********************************************************************
206  OBSERVATION TYPE: CObservation2DRangeScan
207  ********************************************************************/
208  const auto& o = dynamic_cast<const CObservation2DRangeScan&>(obs);
209  CLandmarksMap auxMap;
210  CPose2D sensorPose2D(robotPose3D + o.sensorPose);
211 
213  o, &robotPose3D, likelihoodOptions.rangeScan2D_decimation);
214 
215  // And compute its likelihood:
216  return computeLikelihood_RSLC_2007(&auxMap, sensorPose2D);
217  } // end of likelihood of 2D range scan:
219  {
220  /********************************************************************
221  OBSERVATION TYPE: CObservationStereoImages
222  Lik. between "this" and "auxMap";
223  ********************************************************************/
224  const auto& o = dynamic_cast<const CObservationStereoImages&>(obs);
225 
226  CLandmarksMap auxMap;
227  auxMap.insertionOptions = insertionOptions;
229  o, CLandmarksMap::_mapMaxID, likelihoodOptions.SIFT_feat_options);
230  auxMap.changeCoordinatesReference(robotPose3D);
231 
232  // ACCESS TO STATIC VARIABLE
233  // std::cout << "_mapMaxID, from " << CLandmarksMap::_mapMaxID << " to
234  // ";
235  if (!CLandmarksMap::_maxIDUpdated)
236  {
237  CLandmarksMap::_mapMaxID += auxMap.size();
238  CLandmarksMap::_maxIDUpdated = true;
239  } // end if
240 
241  // std::cout << CLandmarksMap::_mapMaxID <<std::endl;
242  return computeLikelihood_SIFT_LandmarkMap(&auxMap);
243 
244  } // end of likelihood of Stereo Images scan:
246  {
247  /********************************************************************
248 
249  OBSERVATION TYPE: CObservationBeaconRanges
250 
251  Lik. between "this" and "auxMap";
252 
253  ********************************************************************/
254  const auto& o = dynamic_cast<const CObservationBeaconRanges&>(obs);
255 
256  const double sensorStd = likelihoodOptions.beaconRangesUseObservationStd
257  ? o.stdError
258  : likelihoodOptions.beaconRangesStd;
259  ASSERT_ABOVE_(sensorStd, .0);
260  const auto unif_val =
261  std::log(1.0 / (o.maxSensorDistance - o.minSensorDistance));
262 
263  CPointPDFGaussian beaconPDF;
264  double ret = 0;
265 
266  for (const auto& meas : o.sensedData)
267  {
268  // Look for the beacon in this map:
269  unsigned int sensedID = meas.beaconID;
270  bool found = false;
271 
272  if (std::isnan(meas.sensedDistance)) continue;
273 
274  // Compute the 3D position of the sensor:
275  const auto point3D = robotPose3D + meas.sensorLocationOnRobot;
276 
277  for (const auto& lm : landmarks)
278  {
279  if ((lm.getType() != featBeacon) || (lm.ID != sensedID))
280  continue; // Skip
281 
282  lm.getPose(beaconPDF);
283  const auto& beacon3D = beaconPDF.mean;
284 
285  const double expectedRange = point3D.distanceTo(beacon3D);
286  const double sensedDist =
287  std::max<double>(.0, meas.sensedDistance);
288  MRPT_CHECK_NORMAL_NUMBER(expectedRange);
289 
290  ret +=
291  (-0.5 *
292  mrpt::square((expectedRange - sensedDist) / sensorStd));
293  found = true;
294  break; // we found the beacon, skip the rest of landmarks
295  }
296 
297  // If not found, uniform distribution:
298  if (!found && o.maxSensorDistance > o.minSensorDistance)
299  {
300  ret += unif_val;
302  }
303 
304  } // for each sensed beacon
305 
307  return ret;
308 
309  } // end of likelihood of CObservationBeaconRanges
311  {
312  /********************************************************************
313 
314  OBSERVATION TYPE: CObservationRobotPose
315 
316  Lik. between "this" and "robotPose";
317 
318  ********************************************************************/
319  const auto& o = dynamic_cast<const CObservationRobotPose&>(obs);
320 
321  // Compute the 3D position of the sensor:
322  CPose3D sensorPose3D = robotPose3D + o.sensorPose;
323 
324  // Compute the likelihood according to mahalanobis distance between
325  // poses:
326  CMatrixD dij(1, 6), Cij(6, 6), Cij_1;
327  dij(0, 0) = o.pose.mean.x() - sensorPose3D.x();
328  dij(0, 1) = o.pose.mean.y() - sensorPose3D.y();
329  dij(0, 2) = o.pose.mean.z() - sensorPose3D.z();
330  dij(0, 3) = wrapToPi(o.pose.mean.yaw() - sensorPose3D.yaw());
331  dij(0, 4) = wrapToPi(o.pose.mean.pitch() - sensorPose3D.pitch());
332  dij(0, 5) = wrapToPi(o.pose.mean.roll() - sensorPose3D.roll());
333 
334  // Equivalent covariance from "i" to "j":
335  Cij = CMatrixDouble(o.pose.cov);
336  Cij_1 = Cij.inverse_LLt();
337 
338  double distMahaFlik2 = mrpt::math::multiply_HCHt_scalar(dij, Cij_1);
339  double ret =
340  -0.5 * (distMahaFlik2 / square(likelihoodOptions.extRobotPoseStd));
341 
343  return ret;
344 
345  } // end of likelihood of CObservation
346  else if (CLASS_ID(CObservationGPS) == obs.GetRuntimeClass())
347  {
348  /********************************************************************
349 
350  OBSERVATION TYPE: CObservationGPS
351 
352  ********************************************************************/
353  const auto& o = dynamic_cast<const CObservationGPS&>(obs);
354  // Compute the 3D position of the sensor:
355  CPoint3D point3D = CPoint3D(robotPose3D);
356  CPoint3D GPSpose;
357  double x, y;
358  double earth_radius = 6378137;
359 
360  if ((o.has_GGA_datum()) &&
361  (likelihoodOptions.GPSOrigin.min_sat <=
362  o.getMsgByClass<gnss::Message_NMEA_GGA>().fields.satellitesUsed))
363  {
364  // Compose GPS robot position
365 
366  x = DEG2RAD(
367  (o.getMsgByClass<gnss::Message_NMEA_GGA>()
369  likelihoodOptions.GPSOrigin.longitude)) *
370  earth_radius * 1.03;
371  y = DEG2RAD(
372  (o.getMsgByClass<gnss::Message_NMEA_GGA>()
374  likelihoodOptions.GPSOrigin.latitude)) *
375  earth_radius * 1.15;
376  GPSpose.x(
377  (x * cos(likelihoodOptions.GPSOrigin.ang) +
378  y * sin(likelihoodOptions.GPSOrigin.ang) +
379  likelihoodOptions.GPSOrigin.x_shift));
380  GPSpose.y(
381  (-x * sin(likelihoodOptions.GPSOrigin.ang) +
382  y * cos(likelihoodOptions.GPSOrigin.ang) +
383  likelihoodOptions.GPSOrigin.y_shift));
384  GPSpose.z(
385  (o.getMsgByClass<gnss::Message_NMEA_GGA>()
387  likelihoodOptions.GPSOrigin.altitude));
388  // std::cout<<"GPSpose calculo: "<<GPSpose.x<<","<<GPSpose.y<<"\n";
389 
390  //-------------------------------//
391  // sigmaGPS =
392  // f(o.getMsgByClass<gnss::Message_NMEA_GGA>().fields.satellitesUsed)
393  // //funcion del numero de satelites
394  //-------------------------------//
395 
396  // std::cout<<"datos de longitud y latitud:
397  // "<<o.getMsgByClass<gnss::Message_NMEA_GGA>().fields.longitude_degrees<<","<<o.getMsgByClass<gnss::Message_NMEA_GGA>().fields.latitude_degrees<<","<<"\n";
398  // std::cout<<"x,y sin rotar: "<<x<<","<<y<<","<<"\n";
399  // std::cout<<"angulo: "<<likelihoodOptions.GPSOrigin.ang<<"\n";
400  // std::cout<<"desp x,y:
401  // "<<likelihoodOptions.GPSOrigin.x_shift<<","<<likelihoodOptions.GPSOrigin.y_shift<<"\n";
402  // std::cout<<"GPS ORIGIN :
403  // "<<likelihoodOptions.GPSOrigin.longitude<<","<<likelihoodOptions.GPSOrigin.latitude<<","<<likelihoodOptions.GPSOrigin.altitude<<"\n";
404  // std::cout<<"POSE DEL ROBOT:
405  // "<<point3D.x<<","<<point3D.y<<","<<point3D.z<<"\n";
406  // std::cout<<"POSE GPS :
407  // "<<GPSpose.x<<","<<GPSpose.y<<","<<GPSpose.z<<"\n";
408  // std::cin.get();
409 
410  float distance = GPSpose.distanceTo(point3D);
411 
412  // std::cout<<"likel gps:"<<-0.5f*square( ( distance
413  // )/likelihoodOptions.GPS_sigma)<<"\n";;
414  double ret =
415  -0.5f * square((distance) / likelihoodOptions.GPS_sigma);
417  return ret;
418  }
419  else
420  return 0.5;
421  } // end of likelihood of CObservationGPS
422  else
423  {
424  /********************************************************************
425 
426  OBSERVATION TYPE: Unknown
427 
428  ********************************************************************/
429  return 0.5;
430  }
431 
432  MRPT_END
433 }
434 
435 /*---------------------------------------------------------------
436  insertObservation
437  ---------------------------------------------------------------*/
438 bool CLandmarksMap::internal_insertObservation(
439  const CObservation& obs, const CPose3D* robotPose)
440 {
441  MRPT_START
442 
443  CPose2D robotPose2D;
444  CPose3D robotPose3D;
445 
446  if (robotPose)
447  {
448  robotPose2D = CPose2D(*robotPose);
449  robotPose3D = (*robotPose);
450  }
451  else
452  {
453  // Default values are (0,0,0)
454  }
455 
457  insertionOptions.insert_SIFTs_from_monocular_images)
458  {
459  /********************************************************************
460 
461  OBSERVATION TYPE: CObservationImage
462 
463  ********************************************************************/
464  const auto& o = dynamic_cast<const CObservationImage&>(obs);
465  CLandmarksMap tempMap;
466 
467  // 1) Load the features in a temporary 3D landmarks map:
469  o, insertionOptions.SIFT_feat_options);
470 
471  // 2) This temp. map must be moved to its real position on the global
472  // reference coordinates:
473  tempMap.changeCoordinatesReference(robotPose3D);
474 
475  // 3) Fuse that map with the current contents of "this" one:
476  fuseWith(tempMap);
477 
478  // DONE!!
479 
480  // Observation was successfully inserted into the map
481  // --------------------------------------------------------
482  return true;
483  }
484  // else
485  // if ( CLASS_ID(CObservation2DRangeScan)==obs.GetRuntimeClass() &&
486  // insertionOptions.insert_Landmarks_from_range_scans)
487  // {
488  /********************************************************************
489 
490  OBSERVATION TYPE: CObservation2DRangeScan
491 
492  ********************************************************************/
493  /* CObservation2DRangeScan *o = (CObservation2DRangeScan*) obs;
494  CLandmarksMap tempMap;
495 
496  // Load into the map:
497  tempMap.loadOccupancyFeaturesFrom2DRangeScan(*o, robotPose);
498  fuseWith( tempMap );
499 
500  // Observation was successfully inserted into the map
501  // --------------------------------------------------------
502  return true;
503  } */
504  else if (
506  insertionOptions.insert_SIFTs_from_stereo_images)
507  {
508  /********************************************************************
509  OBSERVATION TYPE: CObservationStereoImages
510  ********************************************************************/
511  const auto& o = dynamic_cast<const CObservationStereoImages&>(obs);
512 
513  // Change coordinates ref:
514  CLandmarksMap auxMap;
515  auxMap.insertionOptions = insertionOptions;
517  o, CLandmarksMap::_mapMaxID, insertionOptions.SIFT_feat_options);
518  auxMap.changeCoordinatesReference(robotPose3D);
519 
520  fuseWith(auxMap);
521 
522  // Observation was successfully inserted into the map
523  // --------------------------------------------------------
524  return true;
525  }
527  {
528  /********************************************************************
529 
530  OBSERVATION TYPE: CObservationVisualLandmarks
531 
532  ********************************************************************/
533  const auto& o = dynamic_cast<const CObservationVisualLandmarks&>(obs);
534 
535  // Change coordinates ref:
536  CLandmarksMap auxMap;
537  CPose3D acumTransform(robotPose3D + o.refCameraPose);
538  auxMap.changeCoordinatesReference(acumTransform, &o.landmarks);
539 
540  // Fuse with current:
541  fuseWith(auxMap, true);
542 
543  // Observation was successfully inserted into the map
544  // --------------------------------------------------------
545  return true;
546  }
547  else
548  {
549  /********************************************************************
550  OBSERVATION TYPE: Unknown
551  ********************************************************************/
552  return false;
553  }
554 
555  MRPT_END
556 }
557 
558 /*---------------------------------------------------------------
559  computeMatchingWith2D
560  ---------------------------------------------------------------*/
561 void CLandmarksMap::computeMatchingWith2D(
562  const mrpt::maps::CMetricMap* otherMap, const CPose2D& otherMapPose,
563  float maxDistForCorrespondence, float maxAngularDistForCorrespondence,
564  const CPose2D& angularDistPivotPoint, TMatchingPairList& correspondences,
565  float& correspondencesRatio, float* sumSqrDist, bool onlyKeepTheClosest,
566  bool onlyUniqueRobust) const
567 {
568  MRPT_UNUSED_PARAM(onlyKeepTheClosest);
569  MRPT_UNUSED_PARAM(onlyUniqueRobust);
570  MRPT_UNUSED_PARAM(sumSqrDist);
571  MRPT_UNUSED_PARAM(angularDistPivotPoint);
572  MRPT_UNUSED_PARAM(maxDistForCorrespondence);
573  MRPT_UNUSED_PARAM(maxAngularDistForCorrespondence);
574 
575  MRPT_START
576 
577  CLandmarksMap auxMap;
578  CPose3D otherMapPose3D(otherMapPose);
579 
580  correspondencesRatio = 0;
581 
582  // Check the other map class:
584  const auto* otherMap2 = dynamic_cast<const CLandmarksMap*>(otherMap);
585  std::vector<bool> otherCorrespondences;
586 
587  // Coordinates change:
588  auxMap.changeCoordinatesReference(otherMapPose3D, otherMap2);
589 
590  //// Use the 3D matching method:
591  computeMatchingWith3DLandmarks(
592  otherMap2, correspondences, correspondencesRatio, otherCorrespondences);
593 
594  MRPT_END
595 }
596 
597 /*---------------------------------------------------------------
598  loadSiftFeaturesFromImageObservation
599  ---------------------------------------------------------------*/
600 void CLandmarksMap::loadSiftFeaturesFromImageObservation(
601  const CObservationImage& obs,
602  const mrpt::vision::CFeatureExtraction::TOptions& feat_options)
603 {
604  CImage corImg;
605  CPointPDFGaussian landmark3DPositionPDF;
606  float d = insertionOptions.SIFTsLoadDistanceOfTheMean;
607  float width = insertionOptions.SIFTsLoadEllipsoidWidth;
608  CMatrixDouble33 P, D;
609  CLandmark lm;
610 
612  vision::CFeatureList siftList; // vision::TSIFTFeatureList siftList;
614  sift; // vision::TSIFTFeatureList::iterator sift;
615 
616  // Timestamp:
617  lm.timestampLastSeen = obs.timestamp;
618  lm.seenTimesCount = 1;
619 
620  // Remove distortion:
621  corImg =
622  obs.image; // obs.image.correctDistortion(obs.intrinsicParams,obs.distortionParams);
623 
624  // Extract SIFT features:
625  fExt.options = feat_options;
626  fExt.detectFeatures(
627  corImg, siftList); // vision::computeSiftFeatures(corImg, siftList );
628 
629  // Save them as 3D landmarks:
630  landmarks.clear(); // resize( siftList.size() );
631 
632  for (sift = siftList.begin(); sift != siftList.end(); sift++)
633  {
634  // Find the 3D position from the pixels
635  // coordinates and the camera intrinsic matrix:
637  sift->keypoint.pt, obs.cameraParams.intrinsicParams);
638 
639  // Compute the mean and covariance of the landmark gaussian 3D position,
640  // from the unitary direction vector and a given distance:
641  // --------------------------------------------------------------------------
642  landmark3DPositionPDF.mean = CPoint3D(dir); // The mean is easy :-)
643  landmark3DPositionPDF.mean *= d;
644 
645  // The covariance:
647 
648  // Diagonal matrix (with the "size" of the ellipsoid)
649  D(0, 0) = square(0.5 * d);
650  D(1, 1) = square(width);
651  D(2, 2) = square(width);
652 
653  // Finally, compute the covariance!
654  landmark3DPositionPDF.cov = mrpt::math::multiply_HCHt(P, D);
655 
656  // Save into the landmarks vector:
657  // --------------------------------------------
658  lm.features.resize(1);
659  lm.features[0] = (*sift);
660 
661  CPoint3D Normal = landmark3DPositionPDF.mean;
662  Normal *= -1 / Normal.norm();
663 
664  lm.normal = Normal.asTPoint();
665 
666  lm.pose_mean = landmark3DPositionPDF.mean.asTPoint();
667 
668  lm.pose_cov_11 = landmark3DPositionPDF.cov(0, 0);
669  lm.pose_cov_22 = landmark3DPositionPDF.cov(1, 1);
670  lm.pose_cov_33 = landmark3DPositionPDF.cov(2, 2);
671  lm.pose_cov_12 = landmark3DPositionPDF.cov(0, 1);
672  lm.pose_cov_13 = landmark3DPositionPDF.cov(0, 2);
673  lm.pose_cov_23 = landmark3DPositionPDF.cov(1, 2);
674 
675  landmarks.push_back(lm);
676  }
677 
678 } // end loadSiftFeaturesFromImageObservation
679 
680 /*---------------------------------------------------------------
681  loadSiftFeaturesFromStereoImagesObservation
682  ---------------------------------------------------------------*/
683 void CLandmarksMap::loadSiftFeaturesFromStereoImageObservation(
685  const mrpt::vision::CFeatureExtraction::TOptions& feat_options)
686 {
687  MRPT_START
688 
690  vision::CFeatureList leftSiftList, rightSiftList;
691  vision::CMatchedFeatureList matchesList;
692  vision::TMatchingOptions matchingOptions;
693  vision::TStereoSystemParams stereoParams;
694 
695  CLandmarksMap landmarkMap;
696 
697  // Extract SIFT features:
698  fExt.options = feat_options; // OLD:
699  // fExt.options.SIFTOptions.implementation =
700  // vision::CFeatureExtraction::Hess;
701 
702  // Default: Hess implementation
703  fExt.detectFeatures(
704  obs.imageLeft, leftSiftList, fID,
705  insertionOptions.SIFTs_numberOfKLTKeypoints);
706  fExt.detectFeatures(
707  obs.imageRight, rightSiftList, fID,
708  insertionOptions.SIFTs_numberOfKLTKeypoints);
709 
710  matchingOptions.matching_method =
712  matchingOptions.epipolar_TH = insertionOptions.SIFTs_epipolar_TH;
713  matchingOptions.EDD_RATIO = insertionOptions.SiftCorrRatioThreshold;
714  matchingOptions.maxEDD_TH = insertionOptions.SiftEDDThreshold;
716  leftSiftList, rightSiftList, matchesList, matchingOptions);
717 
718  if (insertionOptions.PLOT_IMAGES)
719  {
720  std::cerr << "Warning: insertionOptions.PLOT_IMAGES has no effect "
721  "since MRPT 0.9.1\n";
722  }
723 
724  // obs.imageLeft.saveToFile("LImage.jpg");
725  // obs.imageRight.saveToFile("RImage.jpg");
726  // FILE *fmt;
727  // fmt = os::fopen( "matchesRBPF.txt", "at" );
728  // os::fprintf( fmt, "%d\n", (unsigned int)matchesList.size() );
729  // os::fclose(fmt);
730  // matchesList.saveToTextFile("matches.txt");
731 
732  // Feature Projection to 3D
733  // Parameters of the stereo rig
734 
735  stereoParams.K = obs.leftCamera.intrinsicParams;
736  stereoParams.stdPixel = insertionOptions.SIFTs_stdXY;
737  stereoParams.stdDisp = insertionOptions.SIFTs_stdDisparity;
738  stereoParams.baseline = obs.rightCameraPose.x();
739  stereoParams.minZ = 0.0f;
740  stereoParams.maxZ = insertionOptions.SIFTs_stereo_maxDepth;
741 
742  size_t numM = matchesList.size();
743  vision::projectMatchedFeatures(matchesList, stereoParams, *this);
744 
745  // Add Timestamp and the "Seen-Times" counter
747  for (ii = landmarks.begin(); ii != landmarks.end(); ii++)
748  {
749  (*ii).timestampLastSeen = obs.timestamp;
750  (*ii).seenTimesCount = 1;
751  }
752 
753  printf(
754  "%u (out of %u) corrs!\n", static_cast<unsigned>(landmarks.size()),
755  static_cast<unsigned>(numM));
756 
757  // CLandmarksMap::_maxMapID = fID;
758 
759  // Project landmarks according to the ref. camera pose:
760  changeCoordinatesReference(mrpt::poses::CPose3D(obs.cameraPose));
761 
762  MRPT_END
763 }
764 
765 /*---------------------------------------------------------------
766  changeCoordinatesReference
767  ---------------------------------------------------------------*/
768 void CLandmarksMap::changeCoordinatesReference(const CPose3D& newOrg)
769 {
770  TSequenceLandmarks::iterator lm;
771 
772  CMatrixDouble44 HM;
773  newOrg.getHomogeneousMatrix(HM);
774 
775  // Build the rotation only transformation:
776  double R11 = HM(0, 0);
777  double R12 = HM(0, 1);
778  double R13 = HM(0, 2);
779  double R21 = HM(1, 0);
780  double R22 = HM(1, 1);
781  double R23 = HM(1, 2);
782  double R31 = HM(2, 0);
783  double R32 = HM(2, 1);
784  double R33 = HM(2, 2);
785 
786  double c11, c22, c33, c12, c13, c23;
787 
788  // Change the reference of each individual landmark:
789  // ----------------------------------------------------
790  for (lm = landmarks.begin(); lm != landmarks.end(); lm++)
791  {
792  // Transform the pose mean & covariance:
793  // ---------------------------------------------------------
794  newOrg.composePoint(lm->pose_mean, lm->pose_mean);
795 
796  float C11 = lm->pose_cov_11;
797  float C22 = lm->pose_cov_22;
798  float C33 = lm->pose_cov_33;
799  float C12 = lm->pose_cov_12;
800  float C13 = lm->pose_cov_13;
801  float C23 = lm->pose_cov_23;
802 
803  // The covariance: cov = M * cov * (~M);
804  c11 = R11 * (C11 * R11 + C12 * R12 + C13 * R13) +
805  R12 * (C12 * R11 + C22 * R12 + C23 * R13) +
806  R13 * (C13 * R11 + C23 * R12 + C33 * R13);
807  c12 = (C11 * R11 + C12 * R12 + C13 * R13) * R21 +
808  (C12 * R11 + C22 * R12 + C23 * R13) * R22 +
809  (C13 * R11 + C23 * R12 + C33 * R13) * R23;
810  c13 = (C11 * R11 + C12 * R12 + C13 * R13) * R31 +
811  (C12 * R11 + C22 * R12 + C23 * R13) * R32 +
812  (C13 * R11 + C23 * R12 + C33 * R13) * R33;
813  c22 = R21 * (C11 * R21 + C12 * R22 + C13 * R23) +
814  R22 * (C12 * R21 + C22 * R22 + C23 * R23) +
815  R23 * (C13 * R21 + C23 * R22 + C33 * R23);
816  c23 = (C11 * R21 + C12 * R22 + C13 * R23) * R31 +
817  (C12 * R21 + C22 * R22 + C23 * R23) * R32 +
818  (C13 * R21 + C23 * R22 + C33 * R23) * R33;
819  c33 = R31 * (C11 * R31 + C12 * R32 + C13 * R33) +
820  R32 * (C12 * R31 + C22 * R32 + C23 * R33) +
821  R33 * (C13 * R31 + C23 * R32 + C33 * R33);
822 
823  // save into the landmark:
824  lm->pose_cov_11 = c11;
825  lm->pose_cov_22 = c22;
826  lm->pose_cov_33 = c33;
827  lm->pose_cov_12 = c12;
828  lm->pose_cov_13 = c13;
829  lm->pose_cov_23 = c23;
830 
831  // Rotate the normal: lm->normal = rot + lm->normal;
832  // ---------------------------------------------------------
833  float Nx = lm->normal.x;
834  float Ny = lm->normal.y;
835  float Nz = lm->normal.z;
836 
837  lm->normal.x = Nx * R11 + Ny * R12 + Nz * R13;
838  lm->normal.y = Nx * R21 + Ny * R22 + Nz * R23;
839  lm->normal.z = Nx * R31 + Ny * R32 + Nz * R33;
840  }
841 
842  // For updating the KD-Tree
843  landmarks.hasBeenModifiedAll();
844 }
845 
846 /*---------------------------------------------------------------
847  changeCoordinatesReference
848  ---------------------------------------------------------------*/
849 void CLandmarksMap::changeCoordinatesReference(
850  const CPose3D& newOrg, const mrpt::maps::CLandmarksMap* otherMap)
851 {
852  TSequenceLandmarks::const_iterator lm;
853  CLandmark newLandmark;
854 
855  CMatrixDouble44 HM;
856  newOrg.getHomogeneousMatrix(HM);
857 
858  // Build the rotation only transformation:
859  double R11 = HM(0, 0);
860  double R12 = HM(0, 1);
861  double R13 = HM(0, 2);
862  double R21 = HM(1, 0);
863  double R22 = HM(1, 1);
864  double R23 = HM(1, 2);
865  double R31 = HM(2, 0);
866  double R32 = HM(2, 1);
867  double R33 = HM(2, 2);
868 
869  double c11, c22, c33, c12, c13, c23;
870 
871  landmarks.clear();
872 
873  // Change the reference of each individual landmark:
874  // ----------------------------------------------------
875  for (lm = otherMap->landmarks.begin(); lm != otherMap->landmarks.end();
876  lm++)
877  {
878  // Transform the pose mean & covariance:
879  // ---------------------------------------------------------
880  // The mean: mean = newReferenceBase + mean;
881  newOrg.composePoint(lm->pose_mean, newLandmark.pose_mean);
882 
883  float C11 = lm->pose_cov_11;
884  float C22 = lm->pose_cov_22;
885  float C33 = lm->pose_cov_33;
886  float C12 = lm->pose_cov_12;
887  float C13 = lm->pose_cov_13;
888  float C23 = lm->pose_cov_23;
889 
890  // The covariance: cov = M * cov * (~M);
891  c11 = R11 * (C11 * R11 + C12 * R12 + C13 * R13) +
892  R12 * (C12 * R11 + C22 * R12 + C23 * R13) +
893  R13 * (C13 * R11 + C23 * R12 + C33 * R13);
894  c12 = (C11 * R11 + C12 * R12 + C13 * R13) * R21 +
895  (C12 * R11 + C22 * R12 + C23 * R13) * R22 +
896  (C13 * R11 + C23 * R12 + C33 * R13) * R23;
897  c13 = (C11 * R11 + C12 * R12 + C13 * R13) * R31 +
898  (C12 * R11 + C22 * R12 + C23 * R13) * R32 +
899  (C13 * R11 + C23 * R12 + C33 * R13) * R33;
900  c22 = R21 * (C11 * R21 + C12 * R22 + C13 * R23) +
901  R22 * (C12 * R21 + C22 * R22 + C23 * R23) +
902  R23 * (C13 * R21 + C23 * R22 + C33 * R23);
903  c23 = (C11 * R21 + C12 * R22 + C13 * R23) * R31 +
904  (C12 * R21 + C22 * R22 + C23 * R23) * R32 +
905  (C13 * R21 + C23 * R22 + C33 * R23) * R33;
906  c33 = R31 * (C11 * R31 + C12 * R32 + C13 * R33) +
907  R32 * (C12 * R31 + C22 * R32 + C23 * R33) +
908  R33 * (C13 * R31 + C23 * R32 + C33 * R33);
909 
910  // save into the landmark:
911  newLandmark.pose_cov_11 = c11;
912  newLandmark.pose_cov_22 = c22;
913  newLandmark.pose_cov_33 = c33;
914  newLandmark.pose_cov_12 = c12;
915  newLandmark.pose_cov_13 = c13;
916  newLandmark.pose_cov_23 = c23;
917 
918  // Rotate the normal: lm->normal = rot + lm->normal;
919  // ---------------------------------------------------------
920  float Nx = lm->normal.x;
921  float Ny = lm->normal.y;
922  float Nz = lm->normal.z;
923 
924  newLandmark.normal.x = Nx * R11 + Ny * R12 + Nz * R13;
925  newLandmark.normal.y = Nx * R21 + Ny * R22 + Nz * R23;
926  newLandmark.normal.z = Nx * R31 + Ny * R32 + Nz * R33;
927 
928  newLandmark.ID = lm->ID;
929 
930  newLandmark.features = lm->features;
931 
932  newLandmark.timestampLastSeen = lm->timestampLastSeen;
933  newLandmark.seenTimesCount = lm->seenTimesCount;
934 
935  landmarks.push_back(newLandmark);
936  }
937 }
938 
939 /*---------------------------------------------------------------
940  fuseWith
941  ---------------------------------------------------------------*/
942 void CLandmarksMap::fuseWith(CLandmarksMap& other, bool justInsertAllOfThem)
943 {
944  MRPT_START
945 
946  // std::cout << "Entrando en fuseWith" << std::endl;
947 
948  std::vector<bool> otherCorrs(other.size(), false);
949  TMatchingPairList corrs;
950  TMatchingPairList::iterator corrIt;
951  float corrsRatio;
952  CLandmark *thisLM, *otherLM;
953  int i, n;
954  bool verbose = true; // false;
955  TTimeStamp lastestTime;
956  unsigned int nRemoved = 0;
957 
958  if (!justInsertAllOfThem)
959  {
960  // 1) Compute matching between the global and the new map:
961  // ---------------------------------------------------------
962  computeMatchingWith3DLandmarks(&other, corrs, corrsRatio, otherCorrs);
963 
964  // 2) Fuse correspondences
965  // ---------------------------------------------------------
966  for (corrIt = corrs.begin(); corrIt != corrs.end(); corrIt++)
967  {
968  thisLM = landmarks.get(corrIt->this_idx);
969  otherLM = other.landmarks.get(corrIt->other_idx);
970 
971  // Fuse their poses:
972  CPointPDFGaussian P, P1, P2;
973 
974  thisLM->getPose(P1);
975  otherLM->getPose(P2);
976 
977  P.bayesianFusion(P1, P2);
978 
979  landmarks.isToBeModified(corrIt->this_idx);
980  thisLM->setPose(P);
981 
982  // Update "seen" data:
983  thisLM->seenTimesCount++;
984  thisLM->timestampLastSeen = otherLM->timestampLastSeen;
985 
986  landmarks.hasBeenModified(corrIt->this_idx);
987 
988  } // end foreach corrs
989  }
990 
991  // 3) Add new landmarks from the other map:
992  // ---------------------------------------------------------
993  n = other.size();
994  for (i = 0; i < n; i++)
995  {
996  // Find the lastest time.
997  lastestTime =
998  max(lastestTime, other.landmarks.get(i)->timestampLastSeen);
999 
1000  if (!otherCorrs[i])
1001  {
1002  // No corrs: A NEW LANDMARK!
1003  landmarks.push_back(*other.landmarks.get(i));
1004  }
1005  } // end foreach other landmark
1006 
1007  if (!justInsertAllOfThem)
1008  {
1009  // 4) Remove landmarks that have been not seen the required
1010  // number of times:
1011  // ---------------------------------------------------------
1012  n = landmarks.size();
1013  for (i = n - 1; i >= 0; i--)
1014  {
1015  if (landmarks.get(i)->getType() !=
1016  featNotDefined) // Occupancy features
1017  {
1018  const double dt =
1019  1e-3 *
1020  std::chrono::duration_cast<std::chrono::milliseconds>(
1021  lastestTime - landmarks.get(i)->timestampLastSeen)
1022  .count();
1023  if (dt > fuseOptions.ellapsedTime &&
1024  landmarks.get(i)->seenTimesCount < fuseOptions.minTimesSeen)
1025  {
1026  landmarks.erase(i);
1027  nRemoved++;
1028  }
1029  }
1030  }
1031  }
1032 
1033  if (verbose)
1034  {
1035  printf(
1036  "[CLandmarksMap::fuseWith] %u fused/ %u new/ %u removed -> %u "
1037  "total\n",
1038  static_cast<unsigned int>(corrs.size()),
1039  static_cast<unsigned int>(other.size() - corrs.size()),
1040  static_cast<unsigned int>(nRemoved),
1041  static_cast<unsigned int>(landmarks.size()));
1042  FILE* f = os::fopen("Fused.txt", "at");
1043  fprintf(
1044  f, "%u\t%u\t%u\t%u\n", static_cast<unsigned int>(corrs.size()),
1045  static_cast<unsigned int>(other.size() - corrs.size()),
1046  static_cast<unsigned int>(nRemoved),
1047  static_cast<unsigned int>(landmarks.size()));
1048  os::fclose(f);
1049  }
1050 
1051  MRPT_END
1052 }
1053 
1054 /*---------------------------------------------------------------
1055  computeMatchingWith3DLandmarks
1056  ---------------------------------------------------------------*/
1057 void CLandmarksMap::computeMatchingWith3DLandmarks(
1058  const mrpt::maps::CLandmarksMap* anotherMap,
1059  TMatchingPairList& correspondences, float& correspondencesRatio,
1060  std::vector<bool>& otherCorrespondences) const
1061 {
1062  MRPT_START
1063 
1064  TSequenceLandmarks::const_iterator thisIt, otherIt;
1065  unsigned int nThis, nOther;
1066  int maxIdx;
1067  float desc;
1068  unsigned int i, n, j, k;
1069  TMatchingPair match;
1070  double lik_dist, lik_desc, lik, maxLik;
1071  // double maxLikDist = -1, maxLikDesc =
1072  // -1;
1073  CPointPDFGaussian pointPDF_k, pointPDF_j;
1074  std::vector<bool> thisLandmarkAssigned;
1075  double K_desc = 0.0;
1076  double K_dist = 0.0;
1077 
1078  // FILE *f = os::fopen( "flik.txt", "wt"
1079  //);
1080 
1081  // Get the number of landmarks:
1082  nThis = landmarks.size();
1083  nOther = anotherMap->landmarks.size();
1084 
1085  // Initially no LM has a correspondence:
1086  thisLandmarkAssigned.resize(nThis, false);
1087 
1088  // Initially, set all landmarks without correspondences:
1089  correspondences.clear();
1090  otherCorrespondences.clear();
1091  otherCorrespondences.resize(nOther, false);
1092  correspondencesRatio = 0;
1093 
1094  // Method selection:
1095  // 0. Our Method.
1096  // 1. Sim, Elinas, Griffin, Little.
1097 
1098  switch (insertionOptions.SIFTMatching3DMethod)
1099  {
1100  case 0:
1101  // Our method: Filter out by the likelihood of the 3D position and
1102  // compute the likelihood of the Euclidean descriptor distance
1103 
1104  // "Constants" for the distance computation
1105  K_desc =
1106  -0.5 / square(likelihoodOptions.SIFTs_sigma_descriptor_dist);
1107  K_dist = -0.5 / square(likelihoodOptions.SIFTs_mahaDist_std);
1108 
1109  // CDynamicGrid<std::vector<int32_t>> *gridLandmarks =
1110  // landmarks.getGrid();
1111  // std::vector<int32_t> closeLandmarksList;
1112 
1113  for (k = 0, otherIt = anotherMap->landmarks.begin();
1114  otherIt != anotherMap->landmarks.end(); otherIt++, k++)
1115  {
1116  // Load into "pointPDF_k" the PDF of landmark "otherIt":
1117  otherIt->getPose(pointPDF_k);
1118 
1119  if (otherIt->getType() == featSIFT)
1120  {
1121  // minDist = minDist2 = 1e10f;
1122  maxLik = -1;
1123  maxIdx = -1;
1124 
1125  for (j = 0, thisIt = landmarks.begin();
1126  thisIt != landmarks.end(); thisIt++, j++)
1127  {
1128  if (thisIt->getType() == featSIFT &&
1129  thisIt->features.size() ==
1130  otherIt->features.size() &&
1131  !thisIt->features.empty() &&
1132  thisIt->features[0].descriptors.SIFT->size() ==
1133  otherIt->features[0].descriptors.SIFT->size())
1134  {
1135  // Compute "coincidence probability":
1136  // --------------------------------------
1137  // Load into "pointPDF_j" the PDF of landmark
1138  // "otherIt":
1139  thisIt->getPose(pointPDF_j);
1140 
1141  // Compute lik:
1142  // lik_dist =
1143  // pointPDF_k.productIntegralNormalizedWith(
1144  // &pointPDF_j );
1145  CMatrixDouble dij(1, 3), Cij(3, 3), Cij_1;
1146  double distMahaFlik2;
1147 
1148  // Distance between means:
1149  dij(0, 0) =
1150  pointPDF_k.mean.x() - pointPDF_j.mean.x();
1151  dij(0, 1) =
1152  pointPDF_k.mean.y() - pointPDF_j.mean.y();
1153  dij(0, 2) =
1154  pointPDF_k.mean.z() - pointPDF_j.mean.z();
1155 
1156  // Equivalent covariance from "i" to "j":
1157  Cij =
1158  CMatrixDouble(pointPDF_k.cov + pointPDF_j.cov);
1159  Cij_1 = Cij.inverse_LLt();
1160 
1161  distMahaFlik2 =
1163 
1164  lik_dist = exp(K_dist * distMahaFlik2);
1165  // Likelihood regarding the spatial distance
1166 
1167  if (lik_dist > 1e-2)
1168  {
1169  // Compute distance between descriptors:
1170  // --------------------------------------
1171 
1172  // MODIFICATION 19-SEPT-2007
1173  // ONLY COMPUTE THE EUCLIDEAN DISTANCE BETWEEN
1174  // DESCRIPTORS IF IT HAS NOT BEEN COMPUTED
1175  // BEFORE
1176  // Make the pair of points
1177  std::pair<
1180  mPair(thisIt->ID, otherIt->ID);
1181 
1182  if (CLandmarksMap::_mEDD[mPair] == 0)
1183  {
1184  n = otherIt->features[0]
1185  .descriptors.SIFT->size();
1186  desc = 0;
1187  for (i = 0; i < n; i++)
1188  desc += square(
1189  (*otherIt->features[0]
1190  .descriptors.SIFT)[i] -
1191  (*thisIt->features[0]
1192  .descriptors.SIFT)[i]);
1193 
1194  CLandmarksMap::_mEDD[mPair] = desc;
1195  } // end if
1196  else
1197  {
1198  desc = CLandmarksMap::_mEDD[mPair];
1199  }
1200 
1201  lik_desc = exp(K_desc * desc); // Likelihood
1202  // regarding the
1203  // descriptor
1204  }
1205  else
1206  {
1207  lik_desc = 1e-3;
1208  }
1209 
1210  // Likelihood of the correspondence
1211  // --------------------------------------
1212  lik = lik_dist * lik_desc;
1213 
1214  // os::fprintf( f,
1215  //"%i\t%i\t%f\t%f\t%f\n", k, j, lik_desc, lik_dist,
1216  // lik );
1217 
1218  if (lik > maxLik)
1219  {
1220  // maxLikDist =
1221  // lik_dist;
1222  // maxLikDesc =
1223  // lik_desc;
1224  maxLik = lik;
1225  maxIdx = j;
1226  }
1227 
1228  } // end of this landmark is SIFT
1229 
1230  } // End of for each "this", j
1231  // os::fprintf(f, "%i\t%i\t%f\t%f\t%f\n", maxIdx, k,
1232  // maxLikDist, maxLikDesc, maxLik);
1233 
1234  // Is it a correspondence?
1235  if (maxLik > insertionOptions.SiftLikelihoodThreshold)
1236  {
1237  // If a previous correspondence for this LM was found,
1238  // discard this one!
1239  if (!thisLandmarkAssigned[maxIdx])
1240  {
1241  thisLandmarkAssigned[maxIdx] = true;
1242 
1243  // OK: A correspondence found!!
1244  otherCorrespondences[k] = true;
1245 
1246  match.this_idx = maxIdx;
1247  match.this_x = landmarks.get(maxIdx)->pose_mean.x;
1248  match.this_y = landmarks.get(maxIdx)->pose_mean.y;
1249  match.this_z = landmarks.get(maxIdx)->pose_mean.z;
1250 
1251  match.other_idx = k;
1252  match.other_x =
1253  anotherMap->landmarks.get(k)->pose_mean.x;
1254  match.other_y =
1255  anotherMap->landmarks.get(k)->pose_mean.y;
1256  match.other_z =
1257  anotherMap->landmarks.get(k)->pose_mean.z;
1258 
1259  correspondences.push_back(match);
1260  }
1261  }
1262 
1263  } // end of "otherIt" is SIFT
1264 
1265  } // end of other it., k
1266 
1267  // Compute the corrs ratio:
1268  correspondencesRatio = correspondences.size() / d2f(nOther);
1269  // os::fclose(f);
1270 
1271  break;
1272 
1273  case 1:
1274 
1275  // IMPLEMENTATION OF THE METHOD DESCRIBED IN [VISION-BASED SLAM
1276  // USING THE RBPF][SIM, ELINAS, GRIFFIN, LITTLE]
1277  // 1. Compute Euclidean descriptor distance (EDD).
1278  // 2. Matching based on a Threshold.
1279  // 3. Compute likelihood based only on the position of the 3D
1280  // landmarks.
1281 
1282  // 1.- COMPUTE EDD
1283 
1284  ASSERT_(!anotherMap->landmarks.begin()->features.empty());
1285  ASSERT_(!landmarks.begin()->features.empty());
1286  unsigned int dLen = anotherMap->landmarks.begin()
1287  ->features[0]
1288  .descriptors.SIFT->size();
1289  for (k = 0, otherIt = anotherMap->landmarks.begin();
1290  otherIt != anotherMap->landmarks.end(); otherIt++, k++)
1291  {
1292  double mEDD = -1.0;
1293  unsigned int mEDDidx = 0;
1294  for (j = 0, thisIt = landmarks.begin();
1295  thisIt != landmarks.end(); thisIt++, j++)
1296  {
1297  // Compute EDD
1298  double EDD = 0.0;
1299  for (i = 0; i < dLen; i++)
1300  EDD += square(
1301  (*otherIt->features[0].descriptors.SIFT)[i] -
1302  (*thisIt->features[0].descriptors.SIFT)[i]);
1303 
1304  EDD = sqrt(EDD);
1305 
1306  if (EDD > mEDD)
1307  {
1308  mEDD = EDD;
1309  mEDDidx = j;
1310  } // end if
1311  } // end for j
1312 
1313  if (mEDD > insertionOptions.SiftEDDThreshold)
1314  {
1315  // There is a correspondence
1316  if (!thisLandmarkAssigned[mEDDidx]) // If there is not
1317  // multiple
1318  // correspondence
1319  {
1320  thisLandmarkAssigned[mEDDidx] = true;
1321 
1322  // OK: A correspondence found!!
1323  otherCorrespondences[k] = true;
1324 
1325  otherIt->getPose(pointPDF_k);
1326  thisIt->getPose(pointPDF_j);
1327 
1328  match.this_idx = j;
1329  match.this_x = landmarks.get(mEDDidx)->pose_mean.x;
1330  match.this_y = landmarks.get(mEDDidx)->pose_mean.y;
1331  match.this_z = landmarks.get(mEDDidx)->pose_mean.z;
1332 
1333  match.other_idx = k;
1334  match.other_x =
1335  anotherMap->landmarks.get(k)->pose_mean.x;
1336  match.other_y =
1337  anotherMap->landmarks.get(k)->pose_mean.y;
1338  match.other_z =
1339  anotherMap->landmarks.get(k)->pose_mean.z;
1340 
1341  correspondences.push_back(match);
1342 
1343  } // end if multiple correspondence
1344 
1345  } // end if mEDD
1346 
1347  } // end for k
1348 
1349  correspondencesRatio = correspondences.size() / d2f(nOther);
1350 
1351  break;
1352 
1353  } // end switch
1354 
1355  MRPT_END
1356 }
1357 
1358 /*---------------------------------------------------------------
1359  saveToTextFile
1360  ---------------------------------------------------------------*/
1361 bool CLandmarksMap::saveToTextFile(std::string file)
1362 {
1363  MRPT_START
1364 
1365  FILE* f = os::fopen(file.c_str(), "wt");
1366  if (!f) return false;
1367 
1368  // os::fprintf(f,"%% Map of landmarks - file dumped by
1369  // mrpt::maps::CLandmarksMap\n");
1370  // os::fprintf(f,"%% Columns are: X Y Z TYPE(TKeyPointMethod) TIMES_SEEN
1371  // TIME_OF_LAST_OBSERVATION [SIFT DESCRIPTOR] ID\n");
1372  // os::fprintf(f,"%%
1373  // -----------------------------------------------------------------------------------------------------\n");
1374 
1375  for (auto it = landmarks.begin(); it != landmarks.end(); ++it)
1376  {
1377  os::fprintf(
1378  f, "%10f %10f %10f %4i %4u %10f", it->pose_mean.x, it->pose_mean.y,
1379  it->pose_mean.z, static_cast<int>(it->getType()),
1380  it->seenTimesCount,
1381  it->timestampLastSeen == INVALID_TIMESTAMP
1382  ? 0
1384  it->timestampLastSeen));
1385 
1386  if (it->getType() == featSIFT)
1387  {
1388  ASSERT_(!it->features.empty());
1389  for (unsigned char i : *it->features[0].descriptors.SIFT)
1390  os::fprintf(f, " %u ", i);
1391  }
1392  os::fprintf(f, " %i ", (int)it->ID);
1393 
1394  os::fprintf(f, "\n");
1395  }
1396 
1397  os::fclose(f);
1398 
1399  return true;
1400 
1401  MRPT_END
1402 }
1403 
1404 /*---------------------------------------------------------------
1405  saveToMATLABScript3D
1406  ---------------------------------------------------------------*/
1407 bool CLandmarksMap::saveToMATLABScript3D(
1408  std::string file, const char* style, float confInterval) const
1409 {
1410  FILE* f = os::fopen(file.c_str(), "wt");
1411  if (!f) return false;
1412 
1413  // Header:
1414  os::fprintf(
1415  f, "%%-------------------------------------------------------\n");
1416  os::fprintf(f, "%% File automatically generated using the MRPT method:\n");
1417  os::fprintf(f, "%% 'CLandmarksMap::saveToMATLABScript3D'\n");
1418  os::fprintf(f, "%%\n");
1419  os::fprintf(f, "%% ~ MRPT ~\n");
1420  os::fprintf(
1421  f, "%% Jose Luis Blanco Claraco, University of Malaga @ 2006\n");
1422  os::fprintf(f, "%% http://www.isa.uma.es/ \n");
1423  os::fprintf(
1424  f, "%%-------------------------------------------------------\n\n");
1425 
1426  // Main code:
1427  os::fprintf(f, "hold on;\n\n");
1428 
1429  for (const auto& landmark : landmarks)
1430  {
1431  os::fprintf(
1432  f, "m=[%.4f %.4f %.4f];", landmark.pose_mean.x,
1433  landmark.pose_mean.y, landmark.pose_mean.z);
1434  os::fprintf(
1435  f, "c=[%.8f %.8f %.8f;%.8f %.8f %.8f;%.8f %.8f %.8f]; ",
1436  landmark.pose_cov_11, landmark.pose_cov_12, landmark.pose_cov_13,
1437  landmark.pose_cov_12, landmark.pose_cov_22, landmark.pose_cov_23,
1438  landmark.pose_cov_13, landmark.pose_cov_23, landmark.pose_cov_33);
1439 
1440  os::fprintf(
1441  f,
1442  "error_ellipse(c,m,'conf',%f,'style','%s','numPointsEllipse',10);"
1443  "\n",
1444  confInterval, style);
1445  }
1446 
1447  os::fprintf(f, "axis equal;grid on;xlabel('x'); ylabel('y'); zlabel('z');");
1448 
1449  os::fclose(f);
1450  return true;
1451 }
1452 /**/
1453 
1454 /*---------------------------------------------------------------
1455  saveToMATLABScript2D
1456  ---------------------------------------------------------------*/
1457 bool CLandmarksMap::saveToMATLABScript2D(
1458  std::string file, const char* style, float stdCount)
1459 {
1460  FILE* f = os::fopen(file.c_str(), "wt");
1461  if (!f) return false;
1462 
1463  const int ELLIPSE_POINTS = 30;
1464  std::vector<float> X, Y, COS, SIN;
1465  std::vector<float>::iterator x, y, Cos, Sin;
1466  double ang;
1467  CMatrixDouble22 cov, eigVal, eigVec, M;
1468 
1469  X.resize(ELLIPSE_POINTS);
1470  Y.resize(ELLIPSE_POINTS);
1471  COS.resize(ELLIPSE_POINTS);
1472  SIN.resize(ELLIPSE_POINTS);
1473 
1474  // Fill the angles:
1475  for (Cos = COS.begin(), Sin = SIN.begin(), ang = 0; Cos != COS.end();
1476  Cos++, Sin++, ang += (M_2PI / (ELLIPSE_POINTS - 1)))
1477  {
1478  *Cos = cos(ang);
1479  *Sin = sin(ang);
1480  }
1481 
1482  // Header:
1483  os::fprintf(
1484  f, "%%-------------------------------------------------------\n");
1485  os::fprintf(f, "%% File automatically generated using the MRPT method:\n");
1486  os::fprintf(f, "%% 'CLandmarksMap::saveToMATLABScript2D'\n");
1487  os::fprintf(f, "%%\n");
1488  os::fprintf(f, "%% ~ MRPT ~\n");
1489  os::fprintf(
1490  f, "%% Jose Luis Blanco Claraco, University of Malaga @ 2006\n");
1491  os::fprintf(f, "%% http://www.isa.uma.es/ \n");
1492  os::fprintf(
1493  f, "%%-------------------------------------------------------\n\n");
1494 
1495  // Main code:
1496  os::fprintf(f, "hold on;\n\n");
1497 
1498  for (auto& landmark : landmarks)
1499  {
1500  // Compute the eigen-vectors & values:
1501  cov(0, 0) = landmark.pose_cov_11;
1502  cov(1, 1) = landmark.pose_cov_22;
1503  cov(0, 1) = cov(1, 0) = landmark.pose_cov_12;
1504 
1505  std::vector<double> eigvals;
1506  cov.eig_symmetric(eigVec, eigvals);
1507  eigVal.setZero();
1508  eigVal.setDiagonal(eigvals);
1509  eigVal = eigVal.array().sqrt().matrix();
1510  M = eigVal.asEigen() * eigVec.transpose();
1511 
1512  // Compute the points of the ellipsoid:
1513  // ----------------------------------------------
1514  for (x = X.begin(), y = Y.begin(), Cos = COS.begin(), Sin = SIN.begin();
1515  x != X.end(); x++, y++, Cos++, Sin++)
1516  {
1517  *x =
1518  (landmark.pose_mean.x +
1519  stdCount * (*Cos * M(0, 0) + *Sin * M(1, 0)));
1520  *y =
1521  (landmark.pose_mean.y +
1522  stdCount * (*Cos * M(0, 1) + *Sin * M(1, 1)));
1523  }
1524 
1525  // Save the code to plot the ellipsoid:
1526  // ----------------------------------------------
1527  os::fprintf(f, "plot([ ");
1528  for (x = X.begin(); x != X.end(); x++)
1529  {
1530  os::fprintf(f, "%.4f", *x);
1531  if (x != (X.end() - 1)) os::fprintf(f, ",");
1532  }
1533  os::fprintf(f, "],[ ");
1534  for (y = Y.begin(); y != Y.end(); y++)
1535  {
1536  os::fprintf(f, "%.4f", *y);
1537  if (y != (Y.end() - 1)) os::fprintf(f, ",");
1538  }
1539 
1540  os::fprintf(f, "],'%s');\n", style);
1541 
1542  // os::fprintf(f,"error_ellipse(c,m,'conf',0.99,'style','%s','numPointsEllipse',10);\n",style);
1543  }
1544 
1545  os::fprintf(f, "\naxis equal;\n");
1546  os::fclose(f);
1547  return true;
1548 }
1549 
1550 /*---------------------------------------------------------------
1551  loadOccupancyFeaturesFrom2DRangeScan
1552  ---------------------------------------------------------------*/
1553 void CLandmarksMap::loadOccupancyFeaturesFrom2DRangeScan(
1554  const CObservation2DRangeScan& obs, const CPose3D* robotPose,
1555  unsigned int downSampleFactor)
1556 {
1557  unsigned int i, n = obs.getScanSize();
1558  double Th, dTh; // angle of the ray
1559  double J11, J12, J21, J22; // The jacobian elements.
1560  double d;
1561  CPose3D sensorGlobalPose;
1562 
1563  // Empty the map:
1564  this->clear();
1565 
1566  // Sensor pose in 3D:
1567  if (!robotPose)
1568  sensorGlobalPose = obs.sensorPose;
1569  else
1570  sensorGlobalPose = *robotPose + obs.sensorPose;
1571 
1572  // Starting direction:
1573  if (obs.rightToLeft)
1574  {
1575  Th = -0.5 * obs.aperture;
1576  dTh = obs.aperture / n;
1577  }
1578  else
1579  {
1580  Th = +0.5 * obs.aperture;
1581  dTh = -obs.aperture / n;
1582  }
1583 
1584  // Measurement uncertainties:
1585  double var_d = square(0.005); // square(obs.stdError);
1586  double var_th = square(dTh / 10.0);
1587 
1588  // For each range:
1589  for (i = 0; i < n; i += downSampleFactor, Th += downSampleFactor * dTh)
1590  {
1591  // If it is a valid ray:
1592  if (obs.getScanRangeValidity(i))
1593  {
1594  CLandmark newLandmark;
1595 
1596  // Timestamp:
1597  newLandmark.timestampLastSeen = obs.timestamp;
1598  newLandmark.seenTimesCount = 1;
1599 
1600  newLandmark.createOneFeature();
1601  newLandmark.features[0].type = featNotDefined;
1602 
1603  d = obs.getScanRange(i);
1604 
1605  // Compute the landmark in 2D:
1606  // -----------------------------------------------
1607  // Descriptor:
1608  newLandmark.features[0].orientation = Th;
1609  newLandmark.features[0].keypoint.octave = d;
1610 
1611  // Mean:
1612  newLandmark.pose_mean.x = (cos(Th) * d);
1613  newLandmark.pose_mean.y = (sin(Th) * d);
1614  newLandmark.pose_mean.z = 0;
1615 
1616  // Normal direction:
1617  newLandmark.normal = newLandmark.pose_mean;
1618  newLandmark.normal *= -1.0f / newLandmark.pose_mean.norm();
1619 
1620  // Jacobian:
1621  J11 = -d * sin(Th);
1622  J12 = cos(Th);
1623  J21 = d * cos(Th);
1624  J22 = sin(Th);
1625 
1626  // Covariance matrix:
1627  newLandmark.pose_cov_11 = (J11 * J11 * var_th + J12 * J12 * var_d);
1628  newLandmark.pose_cov_12 = (J11 * J21 * var_th + J12 * J22 * var_d);
1629  newLandmark.pose_cov_22 = (J21 * J21 * var_th + J22 * J22 * var_d);
1630  newLandmark.pose_cov_33 = (square(0.005)); // var_d;
1631  newLandmark.pose_cov_13 = newLandmark.pose_cov_23 = 0;
1632 
1633  // Append it:
1634  // -----------------------------------------------
1635  landmarks.push_back(newLandmark);
1636 
1637  } // end of valid ray.
1638 
1639  } // end for n
1640 
1641  // Take landmarks to 3D according to the robot & sensor 3D poses:
1642  // -----------------------------------------------
1643  changeCoordinatesReference(sensorGlobalPose);
1644 }
1645 
1646 /*---------------------------------------------------------------
1647  METHOD DESCRIBED IN PAPER
1648  -------------------------
1649 
1650  ICRA 2007,....
1651 
1652  ---------------------------------------------------------------*/
1653 double CLandmarksMap::computeLikelihood_RSLC_2007(
1654  const CLandmarksMap* s, const CPose2D& sensorPose)
1655 {
1656  MRPT_UNUSED_PARAM(sensorPose);
1657  MRPT_START
1658 
1659  double lik = 1.0;
1660  TSequenceLandmarks::const_iterator itOther;
1661  CLandmark* lm; //*itClosest;
1662  double corr;
1663  double PrNoCorr;
1664  CPointPDFGaussian poseThis, poseOther;
1665  // double STD_THETA = 0.15_deg;
1666  // double STD_DIST = 0.5f;
1667  double nFoundCorrs = 0;
1668  std::vector<int32_t>* corrs;
1669  unsigned int cx, cy, cx_1, cx_2, cy_1, cy_2;
1670 
1671  // s->saveToMATLABScript2D(std::string("ver_sensed.m"));
1672  // saveToMATLABScript2D(std::string("ver_ref.m"),"r");
1673 
1674  CDynamicGrid<std::vector<int32_t>>* grid = landmarks.getGrid();
1675  // grid->saveToTextFile( "debug_grid.txt" );
1676 
1677  // For each landmark in the observations:
1678  for (itOther = s->landmarks.begin(); itOther != s->landmarks.end();
1679  itOther++)
1680  {
1681  itOther->getPose(poseOther);
1682 
1683  cx = cy = grid->y2idx(itOther->pose_mean.y);
1684 
1685  cx_1 = max(0, grid->x2idx(itOther->pose_mean.x - 0.10f));
1686  cx_2 =
1687  min(static_cast<int>(grid->getSizeX()) - 1,
1688  grid->x2idx(itOther->pose_mean.x + 0.10f));
1689  cy_1 = max(0, grid->y2idx(itOther->pose_mean.y - 0.10f));
1690  cy_2 =
1691  min(static_cast<int>(grid->getSizeY()) - 1,
1692  grid->y2idx(itOther->pose_mean.y + 0.10f));
1693 
1694  // The likelihood of no correspondence starts at "1" and will be
1695  // modified next:
1696  PrNoCorr = 1;
1697 
1698  // For each landmark in this map: Compute its correspondence likelihood
1699  // and conditioned observation likelihood:
1700  // itClosest = nullptr;
1701 
1702  // Look at landmarks in sourronding cells only:
1703  for (cx = cx_1; cx <= cx_2; cx++)
1704  for (cy = cy_1; cy <= cy_2; cy++)
1705  {
1706  corrs = grid->cellByIndex(cx, cy);
1707  ASSERT_(corrs != nullptr);
1708  if (!corrs->empty())
1709  for (int& it : *corrs)
1710  {
1711  lm = landmarks.get(it);
1712 
1713  // Compute the "correspondence" in the range [0,1]:
1714  // -------------------------------------------------------------
1715 
1716  // Shortcut:
1717  if (fabs(lm->pose_mean.x - itOther->pose_mean.x) >
1718  0.15f ||
1719  fabs(lm->pose_mean.y - itOther->pose_mean.y) >
1720  0.15f)
1721  {
1722  // Absolutely no correspondence, not need to compute
1723  // it:
1724  corr = 0;
1725  }
1726  else
1727  {
1728  lm->getPose(poseThis);
1729  corr = poseOther.productIntegralNormalizedWith2D(
1730  poseThis);
1731  }
1732 
1733  // The likelihood of no corresp. is proportional to the
1734  // product of all "1-CORRij":
1735  // -------------------------------------------------------------
1736  PrNoCorr *= 1 - corr;
1737 
1738  } // end of each landmark in this map.
1739  }
1740 
1741  // Only consider this "point" if it has some real chance to has a
1742  // correspondence:
1743  nFoundCorrs += 1 - PrNoCorr;
1744 
1745  /**** DEBUG **** /
1746  {
1747  //FILE *f=os::fopen("debug_corrs.txt","wt");
1748  //for (Cij=v_Cij.begin(),pZj=v_pZj.begin(); pZj!=v_pZj.end();
1749  Cij++,pZj++)
1750  //{
1751  // os::fprintf(f,"%e %e\n", *Cij, *pZj);
1752  //}
1753 
1754  //os::fprintf(f,"\n INDIV LIK=%e\n lik=%e\n
1755  closestObstacleInLine=%e\n measured
1756  range=%e\n",indivLik,lik,closestObstacleInLine,
1757  itOther.descriptors.SIFT[1]);
1758  //os::fprintf(f,"
1759  closestObstacleDirection=%e\n",closestObstacleDirection);
1760  //os::fclose(f);
1761 
1762  printf("\n lik=%e\n closestObstacleInLine=%e\n measured
1763  range=%e\n",lik,closestObstacleInLine, itOther.descriptors.SIFT[1]);
1764  if (itClosest)
1765  printf(" closest=(%.03f,%.03f)\n", itClosest->pose_mean.x,
1766  itClosest->pose_mean.y);
1767  else printf(" closest=nullptr\n");
1768 
1769  printf(" P(no corrs)=%e\n", PrNoCorr );
1770  mrpt::system::pause();
1771  }
1772  / ***************/
1773 
1774  lik *= 1 - PrNoCorr;
1775 
1776  } // enf for each landmark in the other map.
1777 
1778  lik = nFoundCorrs / static_cast<double>(s->size());
1779 
1780  lik = log(lik);
1781 
1783  return lik;
1784 
1785  MRPT_END
1786 }
1787 
1788 /*---------------------------------------------------------------
1789 
1790  TCustomSequenceLandmarks
1791 
1792  ---------------------------------------------------------------*/
1793 CLandmarksMap::TCustomSequenceLandmarks::TCustomSequenceLandmarks()
1794  : m_landmarks(), m_grid(-10.0f, 10.0f, -10.0f, 10.f, 0.20f)
1795 
1796 {
1797 }
1798 
1800 {
1801  m_landmarks.clear();
1802 
1803  // Erase the grid:
1804  m_grid.clear();
1805 
1806  m_largestDistanceFromOriginIsUpdated = false;
1807 }
1808 
1810 {
1811  // Resize grid if necesary:
1812  std::vector<int32_t> dummyEmpty;
1813 
1814  m_grid.resize(
1815  min(m_grid.getXMin(), l.pose_mean.x - 0.1),
1816  max(m_grid.getXMax(), l.pose_mean.x + 0.1),
1817  min(m_grid.getYMin(), l.pose_mean.y - 0.1),
1818  max(m_grid.getYMax(), l.pose_mean.y + 0.1), dummyEmpty);
1819 
1820  m_landmarks.push_back(l);
1821 
1822  // Add to the grid:
1823  std::vector<int32_t>* cell = m_grid.cellByPos(l.pose_mean.x, l.pose_mean.y);
1824  ASSERT_(cell);
1825  cell->push_back(m_landmarks.size() - 1);
1826 
1827  m_largestDistanceFromOriginIsUpdated = false;
1828 }
1829 
1831 {
1832  return &m_landmarks[indx];
1833 }
1834 
1836  unsigned int indx) const
1837 {
1838  return &m_landmarks[indx];
1839 }
1840 
1842 {
1843  std::vector<int32_t>* cell = m_grid.cellByPos(
1844  m_landmarks[indx].pose_mean.x, m_landmarks[indx].pose_mean.y);
1845 
1846  std::vector<int32_t>::iterator it;
1847  for (it = cell->begin(); it != cell->end(); it++)
1848  {
1849  if (*it == static_cast<int>(indx))
1850  {
1851  cell->erase(it);
1852  return;
1853  }
1854  }
1855 
1856  m_largestDistanceFromOriginIsUpdated = false;
1857 }
1858 
1860 {
1861  m_landmarks.erase(m_landmarks.begin() + indx);
1862  m_largestDistanceFromOriginIsUpdated = false;
1863 }
1864 
1866 {
1867  std::vector<int32_t> dummyEmpty;
1868 
1869  // Resize grid if necesary:
1870  m_grid.resize(
1871  min(m_grid.getXMin(), m_landmarks[indx].pose_mean.x),
1872  max(m_grid.getXMax(), m_landmarks[indx].pose_mean.x),
1873  min(m_grid.getYMin(), m_landmarks[indx].pose_mean.y),
1874  max(m_grid.getYMax(), m_landmarks[indx].pose_mean.y), dummyEmpty);
1875 
1876  // Add to the grid:
1877  std::vector<int32_t>* cell = m_grid.cellByPos(
1878  m_landmarks[indx].pose_mean.x, m_landmarks[indx].pose_mean.y);
1879  cell->push_back(indx);
1880  m_largestDistanceFromOriginIsUpdated = false;
1881 }
1882 
1884 {
1885  MRPT_START
1886 
1887  TSequenceLandmarks::iterator it;
1888  unsigned int idx;
1889  double min_x = -10.0, max_x = 10.0;
1890  double min_y = -10.0, max_y = 10.0;
1891  std::vector<int32_t> dummyEmpty;
1892 
1893  // Clear cells:
1894  m_grid.clear();
1895 
1896  // Resize the grid to the outer limits of landmarks:
1897  for (idx = 0, it = m_landmarks.begin(); it != m_landmarks.end();
1898  idx++, it++)
1899  {
1900  min_x = min(min_x, it->pose_mean.x);
1901  max_x = max(max_x, it->pose_mean.x);
1902  min_y = min(min_y, it->pose_mean.y);
1903  max_y = max(max_y, it->pose_mean.y);
1904  }
1905  m_grid.resize(min_x, max_x, min_y, max_y, dummyEmpty);
1906 
1907  // Add landmarks to cells:
1908  for (idx = 0, it = m_landmarks.begin(); it != m_landmarks.end();
1909  idx++, it++)
1910  {
1911  std::vector<int32_t>* cell =
1912  m_grid.cellByPos(it->pose_mean.x, it->pose_mean.y);
1913  cell->push_back(idx);
1914  }
1915 
1916  m_largestDistanceFromOriginIsUpdated = false;
1917  MRPT_END
1918 }
1919 
1920 /*---------------------------------------------------------------
1921  getLargestDistanceFromOrigin
1922 ---------------------------------------------------------------*/
1924  const
1925 {
1926  // Updated?
1927  if (!m_largestDistanceFromOriginIsUpdated)
1928  {
1929  // NO: Update it:
1930  float maxDistSq = 0, d;
1931  for (const auto& it : *this)
1932  {
1933  d = square(it.pose_mean.x) + square(it.pose_mean.y) +
1934  square(it.pose_mean.z);
1935  maxDistSq = max(d, maxDistSq);
1936  }
1937 
1938  m_largestDistanceFromOrigin = sqrt(maxDistSq);
1939  m_largestDistanceFromOriginIsUpdated = true;
1940  }
1941  return m_largestDistanceFromOrigin;
1942 }
1943 
1944 /*---------------------------------------------------------------
1945  computeLikelihood_SIFT_LandmarkMap
1946  ---------------------------------------------------------------*/
1948  CLandmarksMap* theMap, TMatchingPairList* correspondences,
1949  std::vector<bool>* otherCorrespondences)
1950 {
1951  double lik = 0; // For 'traditional'
1952  double lik_i;
1953  unsigned long distDesc;
1954  double likByDist, likByDesc;
1955 
1956  std::vector<unsigned char>::iterator it1, it2;
1957  double K_dist = -0.5 / square(likelihoodOptions.SIFTs_mahaDist_std);
1958  double K_desc =
1960 
1961  unsigned int idx1, idx2;
1962  CPointPDFGaussian lm1_pose, lm2_pose;
1963  CMatrixD dij(1, 3), Cij(3, 3), Cij_1;
1964  double distMahaFlik2;
1965  int decimation = likelihoodOptions.SIFTs_decimation;
1966 
1967  // USE INSERTOPTIONS METHOD
1969  {
1970  case 0: // Our method
1971  {
1972  // lik = 1e-9; // For consensus
1973  lik = 1.0; // For traditional
1974 
1975  TSequenceLandmarks::iterator lm1, lm2;
1976  for (idx1 = 0, lm1 = theMap->landmarks.begin();
1977  lm1 < theMap->landmarks.end();
1978  lm1 += decimation, idx1 += decimation) // Other theMap LM1
1979  {
1980  if (lm1->getType() == featSIFT)
1981  {
1982  // Get the pose of lm1 as an object:
1983  lm1->getPose(lm1_pose);
1984 
1985  lik_i = 0; // Counter
1986 
1987  for (idx2 = 0, lm2 = landmarks.begin();
1988  lm2 != landmarks.end();
1989  lm2++, idx2++) // This theMap LM2
1990  {
1991  if (lm2->getType() == featSIFT)
1992  {
1993  // Get the pose of lm2 as an object:
1994  lm2->getPose(lm2_pose);
1995 
1996  // Compute the likelihood according to mahalanobis
1997  // distance:
1998  // Distance between means:
1999  dij(0, 0) = lm1->pose_mean.x - lm2->pose_mean.x;
2000  dij(0, 1) = lm1->pose_mean.y - lm2->pose_mean.y;
2001  dij(0, 2) = lm1->pose_mean.z - lm2->pose_mean.z;
2002 
2003  // std::cout << "ED POSICION: " << sqrt(
2004  // dij(0,0)*dij(0,0) + dij(0,1)*dij(0,1) +
2005  // dij(0,2)*dij(0,2) ) << std::endl;
2006  // Equivalent covariance from "i" to "j":
2007  Cij = CMatrixDouble(lm1_pose.cov + lm2_pose.cov);
2008  Cij_1 = Cij.inverse_LLt();
2009 
2010  distMahaFlik2 =
2012 
2013  likByDist = exp(K_dist * distMahaFlik2);
2014 
2015  if (likByDist > 1e-2)
2016  {
2017  // If the EUCLIDEAN distance is not too large,
2018  // we compute the Descriptor distance
2019  // Compute Likelihood by descriptor
2020  // Compute distance between descriptors
2021 
2022  // IF the EDD has been already computed, we skip
2023  // this step!
2024  std::pair<
2027  mPair(lm2->ID, lm1->ID);
2028  // std::cout << "Par: (" << lm2->ID << "," <<
2029  // lm1->ID << ") -> ";
2030 
2031  if (CLandmarksMap::_mEDD[mPair] == 0)
2032  {
2033  distDesc = 0;
2034  ASSERT_(
2035  !lm1->features.empty() &&
2036  !lm2->features.empty());
2037  ASSERT_(
2038  lm1->features[0]
2039  .descriptors.SIFT->size() ==
2040  lm2->features[0]
2041  .descriptors.SIFT->size());
2042 
2043  for (it1 = lm1->features[0]
2044  .descriptors.SIFT->begin(),
2045  it2 = lm2->features[0]
2046  .descriptors.SIFT->begin();
2047  it1 != lm1->features[0]
2048  .descriptors.SIFT->end();
2049  it1++, it2++)
2050  distDesc += square(*it1 - *it2);
2051 
2052  // Insert into the vector of Euclidean
2053  // distances
2054  CLandmarksMap::_mEDD[mPair] = distDesc;
2055  } // end if
2056  else
2057  {
2058  distDesc = (unsigned long)
2059  CLandmarksMap::_mEDD[mPair];
2060  }
2061  likByDesc = exp(K_desc * distDesc);
2062  lik_i += likByDist *
2063  likByDesc; // Cumulative Likelihood
2064  }
2065  else
2066  {
2067  // If the EUCLIDEAN distance is too large, we
2068  // assume that the cumulative likelihood is
2069  // (almost) zero.
2070  lik_i += 1e-10f;
2071  }
2072  } // end if
2073  } // end for "lm2"
2074  lik *= (0.1 + 0.9 * lik_i); // (TRADITIONAL) Total
2075  }
2076  } // end for "lm1"
2077  }
2078  break;
2079 
2080  case 1: // SIM, ELINAS, GRIFFIN, LITTLE
2081  double dist;
2082  TMatchingPairList::iterator itCorr;
2083 
2084  lik = 1.0f;
2085 
2086  // Check if the Matches are inserted into the function
2087  if (correspondences == nullptr)
2089  "When using this method with SIFTLikelihoodMethod = 1, "
2090  "TMatchingPairList *correspondence can not be NULL");
2091 
2092  if (otherCorrespondences == nullptr)
2094  "When using this method with SIFTLikelihoodMethod = 1, "
2095  "std::vector<bool> *otherCorrespondences can not be NULL");
2096 
2097  for (itCorr = correspondences->begin();
2098  itCorr != correspondences->end(); itCorr++)
2099  {
2100  CLandmark* lm1 = theMap->landmarks.get(itCorr->other_idx);
2101  CLandmark* lm2 = landmarks.get(itCorr->this_idx);
2102 
2103  dij(0, 0) = lm1->pose_mean.x - lm2->pose_mean.x;
2104  dij(0, 1) = lm1->pose_mean.y - lm2->pose_mean.y;
2105  dij(0, 2) = lm1->pose_mean.z - lm2->pose_mean.z;
2106 
2107  // Equivalent covariance from "i" to "j":
2108  Cij = CMatrixDouble(lm1_pose.cov + lm2_pose.cov);
2109  Cij_1 = Cij.inverse_LLt();
2110 
2111  distMahaFlik2 = mrpt::math::multiply_HCHt_scalar(dij, Cij_1);
2112 
2113  dist = min(
2115  distMahaFlik2);
2116 
2117  lik *= exp(-0.5 * dist);
2118 
2119  } // end for correspondences
2120 
2121  // We complete the likelihood with the null correspondences
2122  for (size_t k = 1; k <= (theMap->size() - correspondences->size());
2123  k++)
2125 
2126  break;
2127 
2128  } // end switch
2129 
2130  lik = log(lik);
2132  return lik;
2133 }
2134 
2135 /*---------------------------------------------------------------
2136  TInsertionOptions
2137  ---------------------------------------------------------------*/
2139  :
2140 
2141  SIFT_feat_options(vision::featSIFT)
2142 {
2143 }
2144 
2145 /*---------------------------------------------------------------
2146  dumpToTextStream
2147  ---------------------------------------------------------------*/
2149 {
2150  out << "\n----------- [CLandmarksMap::TInsertionOptions] ------------ \n\n";
2151 
2152  out << mrpt::format(
2153  "insert_SIFTs_from_monocular_images = %c\n",
2154  insert_SIFTs_from_monocular_images ? 'Y' : 'N');
2155  out << mrpt::format(
2156  "insert_SIFTs_from_stereo_images = %c\n",
2157  insert_SIFTs_from_stereo_images ? 'Y' : 'N');
2158  out << mrpt::format(
2159  "insert_Landmarks_from_range_scans = %c\n",
2160  insert_Landmarks_from_range_scans ? 'Y' : 'N');
2161  out << "\n";
2162  out << mrpt::format(
2163  "SiftCorrRatioThreshold = %f\n",
2164  SiftCorrRatioThreshold);
2165  out << mrpt::format(
2166  "SiftLikelihoodThreshold = %f\n",
2167  SiftLikelihoodThreshold);
2168  out << mrpt::format(
2169  "SiftEDDThreshold = %f\n", SiftEDDThreshold);
2170  out << mrpt::format(
2171  "SIFTMatching3DMethod = %d\n", SIFTMatching3DMethod);
2172  out << mrpt::format(
2173  "SIFTLikelihoodMethod = %d\n", SIFTLikelihoodMethod);
2174 
2175  out << mrpt::format(
2176  "SIFTsLoadDistanceOfTheMean = %f\n",
2177  SIFTsLoadDistanceOfTheMean);
2178  out << mrpt::format(
2179  "SIFTsLoadEllipsoidWidth = %f\n",
2180  SIFTsLoadEllipsoidWidth);
2181  out << "\n";
2182  out << mrpt::format(
2183  "SIFTs_stdXY = %f\n", SIFTs_stdXY);
2184  out << mrpt::format(
2185  "SIFTs_stdDisparity = %f\n", SIFTs_stdDisparity);
2186  out << "\n";
2187  out << mrpt::format(
2188  "SIFTs_numberOfKLTKeypoints = %i\n",
2189  SIFTs_numberOfKLTKeypoints);
2190  out << mrpt::format(
2191  "SIFTs_stereo_maxDepth = %f\n",
2192  SIFTs_stereo_maxDepth);
2193  out << mrpt::format(
2194  "SIFTs_epipolar_TH = %f\n", SIFTs_epipolar_TH);
2195  out << mrpt::format(
2196  "PLOT_IMAGES = %c\n",
2197  PLOT_IMAGES ? 'Y' : 'N');
2198 
2199  SIFT_feat_options.dumpToTextStream(out);
2200 
2201  out << "\n";
2202 }
2203 
2204 /*---------------------------------------------------------------
2205  loadFromConfigFile
2206  ---------------------------------------------------------------*/
2208  const mrpt::config::CConfigFileBase& iniFile, const std::string& section)
2209 {
2210  insert_SIFTs_from_monocular_images = iniFile.read_bool(
2211  section.c_str(), "insert_SIFTs_from_monocular_images",
2212  insert_SIFTs_from_monocular_images);
2213  insert_SIFTs_from_stereo_images = iniFile.read_bool(
2214  section.c_str(), "insert_SIFTs_from_stereo_images",
2215  insert_SIFTs_from_stereo_images);
2216  insert_Landmarks_from_range_scans = iniFile.read_bool(
2217  section.c_str(), "insert_Landmarks_from_range_scans",
2218  insert_Landmarks_from_range_scans);
2219  SiftCorrRatioThreshold = iniFile.read_float(
2220  section.c_str(), "SiftCorrRatioThreshold", SiftCorrRatioThreshold);
2221  SiftLikelihoodThreshold = iniFile.read_float(
2222  section.c_str(), "SiftLikelihoodThreshold", SiftLikelihoodThreshold);
2223  SiftEDDThreshold = iniFile.read_float(
2224  section.c_str(), "SiftEDDThreshold", SiftEDDThreshold);
2225  SIFTMatching3DMethod = iniFile.read_int(
2226  section.c_str(), "SIFTMatching3DMethod", SIFTMatching3DMethod);
2227  SIFTLikelihoodMethod = iniFile.read_int(
2228  section.c_str(), "SIFTLikelihoodMethod", SIFTLikelihoodMethod);
2229  SIFTsLoadDistanceOfTheMean = iniFile.read_float(
2230  section.c_str(), "SIFTsLoadDistanceOfTheMean",
2231  SIFTsLoadDistanceOfTheMean);
2232  SIFTsLoadEllipsoidWidth = iniFile.read_float(
2233  section.c_str(), "SIFTsLoadEllipsoidWidth", SIFTsLoadEllipsoidWidth);
2234  SIFTs_stdXY =
2235  iniFile.read_float(section.c_str(), "SIFTs_stdXY", SIFTs_stdXY);
2236  SIFTs_stdDisparity = iniFile.read_float(
2237  section.c_str(), "SIFTs_stdDisparity", SIFTs_stdDisparity);
2238  SIFTs_numberOfKLTKeypoints = iniFile.read_int(
2239  section.c_str(), "SIFTs_numberOfKLTKeypoints",
2240  SIFTs_numberOfKLTKeypoints);
2241  SIFTs_stereo_maxDepth = iniFile.read_float(
2242  section.c_str(), "SIFTs_stereo_maxDepth", SIFTs_stereo_maxDepth);
2243  SIFTs_epipolar_TH = iniFile.read_float(
2244  section.c_str(), "SIFTs_epipolar_TH", SIFTs_epipolar_TH);
2245  PLOT_IMAGES =
2246  iniFile.read_bool(section.c_str(), "PLOT_IMAGES", PLOT_IMAGES);
2247 
2248  SIFT_feat_options.loadFromConfigFile(iniFile, section);
2249 }
2250 
2251 /*---------------------------------------------------------------
2252  TLikelihoodOptions
2253  ---------------------------------------------------------------*/
2255  : SIFT_feat_options(vision::featSIFT),
2256 
2257  GPSOrigin()
2258 
2259 {
2260 }
2261 
2263 
2264  = default;
2265 
2266 /*---------------------------------------------------------------
2267  dumpToTextStream
2268  ---------------------------------------------------------------*/
2270  std::ostream& out) const
2271 {
2272  out << "\n----------- [CLandmarksMap::TLikelihoodOptions] ------------ "
2273  "\n\n";
2274 
2275  out << mrpt::format(
2276  "rangeScan2D_decimation = %i\n",
2277  rangeScan2D_decimation);
2278  out << mrpt::format(
2279  "SIFTs_sigma_euclidean_dist = %f\n",
2280  SIFTs_sigma_euclidean_dist);
2281  out << mrpt::format(
2282  "SIFTs_sigma_descriptor_dist = %f\n",
2283  SIFTs_sigma_descriptor_dist);
2284  out << mrpt::format(
2285  "SIFTs_mahaDist_std = %f\n", SIFTs_mahaDist_std);
2286  out << mrpt::format(
2287  "SIFTs_decimation = %i\n", SIFTs_decimation);
2288  out << mrpt::format(
2289  "SIFTnullCorrespondenceDistance = %f\n",
2290  SIFTnullCorrespondenceDistance);
2291  out << mrpt::format(
2292  "beaconRangesStd = %f\n", beaconRangesStd);
2293  out << mrpt::format(
2294  "beaconRangesUseObservationStd = %c\n",
2295  beaconRangesUseObservationStd ? 'Y' : 'N');
2296  out << mrpt::format(
2297  "extRobotPoseStd = %f\n", extRobotPoseStd);
2298 
2299  out << mrpt::format(
2300  "GPSOrigin:LATITUDE = %f\n", GPSOrigin.latitude);
2301  out << mrpt::format(
2302  "GPSOrigin:LONGITUDE = %f\n", GPSOrigin.longitude);
2303  out << mrpt::format(
2304  "GPSOrigin:ALTITUDE = %f\n", GPSOrigin.altitude);
2305  out << mrpt::format(
2306  "GPSOrigin:Rotation_Angle = %f\n", GPSOrigin.ang);
2307  out << mrpt::format(
2308  "GPSOrigin:x_shift = %f\n", GPSOrigin.x_shift);
2309  out << mrpt::format(
2310  "GPSOrigin:y_shift = %f\n", GPSOrigin.y_shift);
2311  out << mrpt::format(
2312  "GPSOrigin:min_sat = %i\n", GPSOrigin.min_sat);
2313 
2314  out << mrpt::format(
2315  "GPS_sigma = %f (m)\n", GPS_sigma);
2316 
2317  SIFT_feat_options.dumpToTextStream(out);
2318 
2319  out << "\n";
2320 }
2321 
2322 /*---------------------------------------------------------------
2323  loadFromConfigFile
2324  ---------------------------------------------------------------*/
2326  const mrpt::config::CConfigFileBase& iniFile, const std::string& section)
2327 {
2328  rangeScan2D_decimation = iniFile.read_int(
2329  section.c_str(), "rangeScan2D_decimation", rangeScan2D_decimation);
2330  SIFTs_sigma_euclidean_dist = iniFile.read_double(
2331  section.c_str(), "SIFTs_sigma_euclidean_dist",
2332  SIFTs_sigma_euclidean_dist);
2333  SIFTs_sigma_descriptor_dist = iniFile.read_double(
2334  section.c_str(), "SIFTs_sigma_descriptor_dist",
2335  SIFTs_sigma_descriptor_dist);
2336  SIFTs_mahaDist_std = iniFile.read_float(
2337  section.c_str(), "SIFTs_mahaDist_std", SIFTs_mahaDist_std);
2338  SIFTs_decimation =
2339  iniFile.read_int(section.c_str(), "SIFTs_decimation", SIFTs_decimation);
2340  SIFTnullCorrespondenceDistance = iniFile.read_float(
2341  section.c_str(), "SIFTnullCorrespondenceDistance",
2342  SIFTnullCorrespondenceDistance);
2343 
2344  GPSOrigin.latitude = iniFile.read_double(
2345  section.c_str(), "GPSOriginLatitude", GPSOrigin.latitude);
2346  GPSOrigin.longitude = iniFile.read_double(
2347  section.c_str(), "GPSOriginLongitude", GPSOrigin.longitude);
2348  GPSOrigin.altitude = iniFile.read_double(
2349  section.c_str(), "GPSOriginAltitude", GPSOrigin.altitude);
2350  GPSOrigin.ang =
2351  iniFile.read_double(section.c_str(), "GPSOriginAngle", GPSOrigin.ang) *
2352  M_PI / 180;
2353  GPSOrigin.x_shift = iniFile.read_double(
2354  section.c_str(), "GPSOriginXshift", GPSOrigin.x_shift);
2355  GPSOrigin.y_shift = iniFile.read_double(
2356  section.c_str(), "GPSOriginYshift", GPSOrigin.y_shift);
2357  GPSOrigin.min_sat =
2358  iniFile.read_int(section.c_str(), "GPSOriginMinSat", GPSOrigin.min_sat);
2359 
2360  GPS_sigma = iniFile.read_float(section.c_str(), "GPSSigma", GPS_sigma);
2361 
2362  beaconRangesStd =
2363  iniFile.read_float(section.c_str(), "beaconRangesStd", beaconRangesStd);
2364  beaconRangesUseObservationStd = iniFile.read_bool(
2365  section.c_str(), "beaconRangesUseObservationStd",
2366  beaconRangesUseObservationStd);
2367 
2368  extRobotPoseStd =
2369  iniFile.read_float(section.c_str(), "extRobotPoseStd", extRobotPoseStd);
2370 
2371  SIFT_feat_options.loadFromConfigFile(iniFile, section);
2372 }
2373 
2374 /*---------------------------------------------------------------
2375  TFuseOptions
2376  ---------------------------------------------------------------*/
2378 
2379  = default;
2380 
2381 /*---------------------------------------------------------------
2382  isEmpty
2383  ---------------------------------------------------------------*/
2384 bool CLandmarksMap::isEmpty() const { return size() == 0; }
2385 /*---------------------------------------------------------------
2386  simulateBeaconReadings
2387  ---------------------------------------------------------------*/
2389  const CPose3D& in_robotPose, const CPoint3D& in_sensorLocationOnRobot,
2390  mrpt::obs::CObservationBeaconRanges& out_Observations) const
2391 {
2392  TSequenceLandmarks::const_iterator it;
2394  CPoint3D point3D, beacon3D;
2395  CPointPDFGaussian beaconPDF;
2396 
2397  // Compute the 3D position of the sensor:
2398  point3D = in_robotPose + in_sensorLocationOnRobot;
2399 
2400  // Clear output data:
2401  out_Observations.sensedData.clear();
2402  out_Observations.timestamp = mrpt::system::getCurrentTime();
2403 
2404  // For each BEACON landmark in the map:
2405  for (it = landmarks.begin(); it != landmarks.end(); it++)
2406  {
2407  if (it->getType() == featBeacon)
2408  {
2409  // Get the 3D position of the beacon (just the mean value):
2410  it->getPose(beaconPDF);
2411  beacon3D = beaconPDF.mean;
2412 
2413  float range = point3D.distanceTo(beacon3D);
2414 
2415  // Add noise:
2416  range += out_Observations.stdError *
2418  range = max(0.0f, range);
2419 
2420  if (range >= out_Observations.minSensorDistance &&
2421  range <= out_Observations.maxSensorDistance)
2422  {
2423  // Fill out:
2424  newMeas.beaconID = it->ID;
2425  newMeas.sensorLocationOnRobot = in_sensorLocationOnRobot;
2426  newMeas.sensedDistance = range;
2427 
2428  // Insert:
2429  out_Observations.sensedData.push_back(newMeas);
2430  }
2431  } // end if beacon
2432  } // end for it
2433  // Done!
2434 }
2435 
2436 /*---------------------------------------------------------------
2437  saveMetricMapRepresentationToFile
2438  ---------------------------------------------------------------*/
2440  const std::string& filNamePrefix) const
2441 {
2442  MRPT_START
2443 
2444  // Matlab:
2445  std::string fil1(filNamePrefix + std::string("_3D.m"));
2446  saveToMATLABScript3D(fil1);
2447 
2448  // 3D Scene:
2449  opengl::COpenGLScene scene;
2452  getAs3DObject(obj3D);
2453 
2454  opengl::CGridPlaneXY::Ptr objGround =
2455  std::make_shared<opengl::CGridPlaneXY>(-100, 100, -100, 100, 0, 1);
2456 
2457  scene.insert(obj3D);
2458  scene.insert(objGround);
2459 
2460  std::string fil2(filNamePrefix + std::string("_3D.3Dscene"));
2461  scene.saveToFile(fil2);
2462 
2463  MRPT_END
2464 }
2465 
2466 /*---------------------------------------------------------------
2467  getAs3DObject
2468  ---------------------------------------------------------------*/
2470  mrpt::opengl::CSetOfObjects::Ptr& outObj) const
2471 {
2473 
2474  // TODO: Generate patchs in 3D, etc...
2475 
2476  // Save 3D ellipsoids
2477  CPointPDFGaussian pointGauss;
2478  for (const auto& landmark : landmarks)
2479  {
2481  std::make_shared<opengl::CEllipsoid3D>();
2482 
2483  landmark.getPose(pointGauss);
2484 
2485  ellip->setPose(pointGauss.mean);
2486  ellip->setCovMatrix(pointGauss.cov);
2487  ellip->enableDrawSolid3D(false);
2488  ellip->setQuantiles(3.0);
2489  ellip->set3DsegmentsCount(10);
2490  ellip->setColor(0, 0, 1);
2491  ellip->setName(
2492  mrpt::format("LM.ID=%u", static_cast<unsigned int>(landmark.ID)));
2493  ellip->enableShowName(true);
2494 
2495  outObj->insert(ellip);
2496  }
2497 }
2498 /**** FAMD ****/
2500 {
2501  return _mapMaxID;
2502 }
2503 /**** END FAMD ****/
2504 
2506  CLandmark::TLandmarkID ID) const
2507 {
2508  for (const auto& m_landmark : m_landmarks)
2509  {
2510  if (m_landmark.ID == ID) return &m_landmark;
2511  }
2512  return nullptr;
2513 }
2514 
2515 // CLandmark* CLandmarksMap::TCustomSequenceLandmarks::getByID(
2516 // CLandmark::TLandmarkID ID )
2517 //{
2518 // for(size_t indx = 0; indx < m_landmarks.size(); indx++)
2519 // {
2520 // if( m_landmarks[indx].ID == ID )
2521 // return &m_landmarks[indx];
2522 // }
2523 // return nullptr;
2524 //}
2525 
2527  unsigned int ID) const
2528 {
2529  for (const auto& m_landmark : m_landmarks)
2530  {
2531  if (m_landmark.ID == ID) return &m_landmark;
2532  }
2533  return nullptr;
2534 }
2535 
2536 /*---------------------------------------------------------------
2537  Computes the ratio in [0,1] of correspondences between "this" and the
2538  "otherMap" map, whose 6D pose relative to "this" is "otherMapPose"
2539  * In the case of a multi-metric map, this returns the average between the
2540  maps. This method always return 0 for grid maps.
2541  * \param otherMap [IN] The other map to compute the matching
2542  with.
2543  * \param otherMapPose [IN] The 6D pose of the other map as seen
2544  from "this".
2545  * \param maxDistForCorr [IN] The minimum distance between 2
2546  non-probabilistic map elements for counting them as a correspondence.
2547  * \param maxMahaDistForCorr [IN] The minimum Mahalanobis distance
2548  between 2 probabilistic map elements for counting them as a correspondence.
2549  *
2550  * \return The matching ratio [0,1]
2551  * \sa computeMatchingWith2D
2552  ----------------------------------------------------------------*/
2554  const mrpt::maps::CMetricMap* otherMap2,
2555  const mrpt::poses::CPose3D& otherMapPose,
2556  const TMatchingRatioParams& params) const
2557 {
2558  MRPT_START
2559 
2560  // Compare to a similar map only:
2561  const CLandmarksMap* otherMap = nullptr;
2562 
2563  if (otherMap2->GetRuntimeClass() == CLASS_ID(CLandmarksMap))
2564  otherMap = dynamic_cast<const CLandmarksMap*>(otherMap2);
2565 
2566  if (!otherMap) return 0;
2567 
2569  std::deque<CPointPDFGaussian::Ptr> poses3DThis, poses3DOther;
2570  std::deque<CPointPDFGaussian::Ptr>::iterator itPoseThis, itPoseOther;
2571  CPointPDFGaussian tempPose;
2572  size_t nThis = landmarks.size();
2573  size_t nOther = otherMap->landmarks.size();
2574  size_t otherLandmarkWithCorrespondence = 0;
2575 
2576  // Checks:
2577  if (!nThis) return 0;
2578  if (!nOther) return 0;
2579 
2580  // The transformation:
2581  CMatrixDouble44 pose3DMatrix;
2582  otherMapPose.getHomogeneousMatrix(pose3DMatrix);
2583  float Tx = pose3DMatrix(0, 3);
2584  float Ty = pose3DMatrix(1, 3);
2585  float Tz = pose3DMatrix(2, 3);
2586 
2587  // ---------------------------------------------------------------------------------------------------------------
2588  // Is there any "contact" between the spheres that contain all the points
2589  // from each map after translating them??
2590  // (Note that we can avoid computing the rotation of all the points if this
2591  // test fail, with a great speed up!)
2592  // ---------------------------------------------------------------------------------------------------------------
2593  if (sqrt(square(Tx) + square(Ty) + square(Tz)) >=
2595  otherMap->landmarks.getLargestDistanceFromOrigin() + 1.0f))
2596  return 0; // There is no contact!
2597 
2598  // Prepare:
2599  poses3DOther.resize(nOther);
2600  for (size_t i = 0; i < nOther; i++)
2601  poses3DOther[i] = std::make_shared<CPointPDFGaussian>();
2602 
2603  poses3DThis.resize(nThis);
2604  for (size_t i = 0; i < nThis; i++)
2605  poses3DThis[i] = std::make_shared<CPointPDFGaussian>();
2606 
2607  // Save 3D poses of the other map with transformed coordinates:
2608  for (itOther = otherMap->landmarks.begin(),
2609  itPoseOther = poses3DOther.begin();
2610  itOther != otherMap->landmarks.end(); itOther++, itPoseOther++)
2611  {
2612  itOther->getPose(**itPoseOther);
2613  (*itPoseOther)->changeCoordinatesReference(otherMapPose);
2614  }
2615 
2616  // And the 3D poses of "this" map:
2617  for (itThis = landmarks.begin(), itPoseThis = poses3DThis.begin();
2618  itThis != landmarks.end(); itThis++, itPoseThis++)
2619  {
2620  itThis->getPose(**itPoseThis);
2621  }
2622 
2623  // Check whether each "other"'s LM has a correspondence or not:
2624  for (itOther = otherMap->landmarks.begin(),
2625  itPoseOther = poses3DOther.begin();
2626  itOther != otherMap->landmarks.end(); itOther++, itPoseOther++)
2627  {
2628  for (itThis = landmarks.begin(), itPoseThis = poses3DThis.begin();
2629  itThis != landmarks.end(); itThis++, itPoseThis++)
2630  {
2631  CMatrixDouble COV =
2632  CMatrixDouble((*itPoseThis)->cov + (*itPoseOther)->cov);
2633  TPoint3D D(
2634  (*itPoseThis)->mean.x() - (*itPoseOther)->mean.x(),
2635  (*itPoseThis)->mean.y() - (*itPoseOther)->mean.y(),
2636  (*itPoseThis)->mean.z() - (*itPoseOther)->mean.z());
2637  CMatrixDouble d(1, 3);
2638  d(0, 0) = D.x;
2639  d(0, 1) = D.y;
2640  d(0, 2) = D.z;
2641 
2642  float distMaha =
2644 
2645  if (distMaha < params.maxMahaDistForCorr)
2646  {
2647  // Now test the SIFT descriptors:
2648  if (!itThis->features.empty() && !itOther->features.empty() &&
2649  itThis->features[0].descriptors.SIFT->size() ==
2650  itOther->features[0].descriptors.SIFT->size())
2651  {
2652  unsigned long descrDist = 0;
2653  std::vector<unsigned char>::const_iterator it1, it2;
2654  for (it1 = itThis->features[0].descriptors.SIFT->begin(),
2655  it2 = itOther->features[0].descriptors.SIFT->begin();
2656  it1 != itThis->features[0].descriptors.SIFT->end();
2657  it1++, it2++)
2658  descrDist += square(*it1 - *it2);
2659 
2660  float descrDist_f =
2661  sqrt(d2f(descrDist)) /
2662  itThis->features[0].descriptors.SIFT->size();
2663 
2664  if (descrDist_f < 1.5f)
2665  {
2666  otherLandmarkWithCorrespondence++;
2667  break; // Go to the next "other" LM
2668  }
2669  }
2670  }
2671  } // for each in "this"
2672 
2673  } // for each in "other"
2674 
2675  return d2f(otherLandmarkWithCorrespondence) / nOther;
2676 
2677  MRPT_END
2678 }
2679 
2680 /*---------------------------------------------------------------
2681  auxParticleFilterCleanUp
2682  ---------------------------------------------------------------*/
2684 {
2685  _mEDD.clear();
2686  _maxIDUpdated = false;
2687 }
2688 
2689 /*---------------------------------------------------------------
2690  simulateRangeBearingReadings
2691  ---------------------------------------------------------------*/
2693  const CPose3D& in_robotPose, const CPose3D& in_sensorLocationOnRobot,
2694  CObservationBearingRange& out_Observations, bool sensorDetectsIDs,
2695  const float in_stdRange, const float in_stdYaw, const float in_stdPitch,
2696  std::vector<size_t>* out_real_associations,
2697  const double spurious_count_mean, const double spurious_count_std) const
2698 {
2699  TSequenceLandmarks::const_iterator it;
2700  size_t idx;
2702  CPoint3D beacon3D;
2703  CPointPDFGaussian beaconPDF;
2704 
2705  if (out_real_associations) out_real_associations->clear();
2706 
2707  // Compute the 3D position of the sensor:
2708  const CPose3D point3D = in_robotPose + CPose3D(in_sensorLocationOnRobot);
2709 
2710  // Clear output data:
2711  out_Observations.validCovariances = false;
2712  out_Observations.sensor_std_range = in_stdRange;
2713  out_Observations.sensor_std_yaw = in_stdYaw;
2714  out_Observations.sensor_std_pitch = in_stdPitch;
2715 
2716  out_Observations.sensedData.clear();
2717  out_Observations.timestamp = mrpt::system::getCurrentTime();
2718  out_Observations.sensorLocationOnRobot = in_sensorLocationOnRobot;
2719 
2720  // For each BEACON landmark in the map:
2721  // ------------------------------------------
2722  for (idx = 0, it = landmarks.begin(); it != landmarks.end(); ++it, ++idx)
2723  {
2724  // Get the 3D position of the beacon (just the mean value):
2725  it->getPose(beaconPDF);
2726  beacon3D = CPoint3D(beaconPDF.mean);
2727 
2728  // Compute yaw,pitch,range:
2729  double range, yaw, pitch;
2730  point3D.sphericalCoordinates(beacon3D.asTPoint(), range, yaw, pitch);
2731 
2732  // Add noises:
2733  range += in_stdRange * getRandomGenerator().drawGaussian1D_normalized();
2734  yaw += in_stdYaw * getRandomGenerator().drawGaussian1D_normalized();
2735  pitch += in_stdPitch * getRandomGenerator().drawGaussian1D_normalized();
2736 
2737  yaw = math::wrapToPi(yaw);
2738  range = max(0.0, range);
2739 
2740  if (range >= out_Observations.minSensorDistance &&
2741  range <= out_Observations.maxSensorDistance &&
2742  fabs(yaw) <= 0.5f * out_Observations.fieldOfView_yaw &&
2743  fabs(pitch) <= 0.5f * out_Observations.fieldOfView_pitch)
2744  {
2745  // Fill out:
2746  if (sensorDetectsIDs)
2747  newMeas.landmarkID = it->ID;
2748  else
2749  newMeas.landmarkID = INVALID_LANDMARK_ID;
2750  newMeas.range = range;
2751  newMeas.yaw = yaw;
2752  newMeas.pitch = pitch;
2753 
2754  // Insert:
2755  out_Observations.sensedData.push_back(newMeas);
2756 
2757  if (out_real_associations)
2758  out_real_associations->push_back(idx); // Real indices.
2759  }
2760  } // end for it
2761 
2762  const double fSpurious = getRandomGenerator().drawGaussian1D(
2763  spurious_count_mean, spurious_count_std);
2764  size_t nSpurious = 0;
2765  if (spurious_count_std != 0 || spurious_count_mean != 0)
2766  nSpurious =
2767  static_cast<size_t>(mrpt::round_long(std::max(0.0, fSpurious)));
2768 
2769  // For each spurios reading to generate:
2770  // ------------------------------------------
2771  for (size_t i = 0; i < nSpurious; i++)
2772  {
2773  // Make up yaw,pitch,range out from thin air:
2774  // (the conditionals on yaw & pitch are to generate 2D observations if
2775  // we are in 2D, which we learn from a null std.dev.)
2776  const double range = getRandomGenerator().drawUniform(
2777  out_Observations.minSensorDistance,
2778  out_Observations.maxSensorDistance);
2779  const double yaw = (out_Observations.sensor_std_yaw == 0)
2780  ? 0
2782  -0.5f * out_Observations.fieldOfView_yaw,
2783  0.5f * out_Observations.fieldOfView_yaw);
2784  const double pitch =
2785  (out_Observations.sensor_std_pitch == 0)
2786  ? 0
2788  -0.5f * out_Observations.fieldOfView_pitch,
2789  0.5f * out_Observations.fieldOfView_pitch);
2790 
2791  // Fill out:
2792  newMeas.landmarkID =
2793  INVALID_LANDMARK_ID; // Always invalid ID since it's spurious
2794  newMeas.range = range;
2795  newMeas.yaw = yaw;
2796  newMeas.pitch = pitch;
2797 
2798  // Insert:
2799  out_Observations.sensedData.push_back(newMeas);
2800 
2801  if (out_real_associations)
2802  out_real_associations->push_back(
2803  std::string::npos); // Real index: spurious
2804  } // end for it
2805 
2806  // Done!
2807 }
void getAs3DObject(mrpt::opengl::CSetOfObjects::Ptr &outObj) const override
Returns a 3D object representing the map.
A namespace of pseudo-random numbers generators of diferent distributions.
float fieldOfView_yaw
Information about the.
float EDD_RATIO
Boundary Ratio between the two lowest EDD.
internal::TSequenceLandmarks::iterator iterator
Virtual base for specifying the kind and parameters of one map (normally, to be inserted into mrpt::m...
Parameters for CMetricMap::compute3DMatchingRatio()
Declares a class derived from "CObservation" that encapsules an image from a camera, whose relative pose to robot is also stored.
size_t size() const
Returns the stored landmarks count.
mrpt::maps::CLandmarksMap::TInsertionOptions insertionOpts
#define MRPT_START
Definition: exceptions.h:241
int y2idx(double y) const
Definition: CDynamicGrid.h:260
A 2D grid of dynamic size which stores any kind of data at each cell.
Definition: CDynamicGrid.h:38
This class is a "CSerializable" wrapper for "CMatrixDynamic<double>".
Definition: CMatrixD.h:23
void createOneFeature()
Creates one feature in the vector "features", calling the appropriate constructor of the smart pointe...
Definition: CLandmark.h:112
float range
The sensed landmark distance, in meters.
double latitude_degrees
The measured latitude, in degrees (North:+ , South:-)
TInternalFeatList::iterator iterator
Definition: CFeature.h:331
mrpt::img::CImage imageLeft
Image from the left camera (this image will be ALWAYS present)
#define M_2PI
Definition: common.h:58
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
unsigned int SIFTLikelihoodMethod
[For SIFT landmarks only] Method to compute the likelihood (Default = 0 (Our method)) 0: Our method -...
Non-defined feature (also used for Occupancy features)
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
bool enableSaveAs3DObject
(Default=true) If false, calling CMetricMap::getAs3DObject() will have no effects ...
size_t size(const MATRIXLIKE &m, const int dim)
const CLandmark * getByID(CLandmark::TLandmarkID ID) const
Returns the landmark with a given landmrk ID, or nullptr if not found.
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:275
mrpt::system::TTimeStamp getCurrentTime()
Returns the current (UTC) system time.
Definition: datetime.h:82
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
To be added to all CSerializable-classes implementation files.
CPoint3D mean
The mean value.
void detectFeatures(const mrpt::img::CImage &img, CFeatureList &feats, const unsigned int init_ID=0, const unsigned int nDesiredFeatures=0, const TImageROI &ROI=TImageROI())
Extract features from the image based on the method defined in TOptions.
long round_long(const T value)
Returns the closer integer (long) to x.
Definition: round.h:39
Declares a class derived from "CObservation" that stores a Landmarks Map as seen from a stereo camera...
uint32_t satellitesUsed
The number of satelites used to compute this estimation.
TOptions options
Set all the parameters of the desired method here before calling detectFeatures() ...
double extractDayTimeFromTimestamp(const mrpt::system::TTimeStamp t)
Returns the number of seconds ellapsed from midnight in the given timestamp.
Definition: datetime.cpp:197
An observation providing an alternative robot pose from an external source.
double pitch() const
Get the PITCH angle (in radians)
Definition: CPose3D.h:552
double yaw() const
Get the YAW angle (in radians)
Definition: CPose3D.h:546
mrpt::vision::TStereoCalibParams params
The set of parameters for all the detectors & descriptor algorithms.
Declares a class derived from "CObservation" that represents one (or more) range measurements to labe...
This file implements miscelaneous matrix and matrix/vector operations, and internal functions in mrpt...
Scale Invariant Feature Transform [LOWE&#39;04].
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
MAT_C::Scalar multiply_HCHt_scalar(const VECTOR_H &H, const MAT_C &C)
r (scalar) = H*C*H^t (H: row vector, C: symmetric matrix)
Definition: ops_matrices.h:63
void dumpToTextStream(std::ostream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
int32_t beaconID
The ID of the sensed beacon (or INVALID_BEACON_ID if unknown)
STL namespace.
static Ptr Create(Args &&... args)
Definition: CSetOfObjects.h:28
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
TMapGenericParams genericMapParams
Common params to all maps.
Definition: CMetricMap.h:275
float epipolar_TH
Epipolar constraint (rows of pixels)
A especial case: this is not an image feature, but a 2D/3D beacon (used for range-only SLAM from mrpt...
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
bool eig_symmetric(Derived &eVecs, std::vector< Scalar > &eVals, bool sorted=true) const
Read: eig()
void simulateBeaconReadings(const mrpt::poses::CPose3D &in_robotPose, const mrpt::poses::CPoint3D &in_sensorLocationOnRobot, mrpt::obs::CObservationBeaconRanges &out_Observations) const
Simulates a noisy reading toward each of the beacons in the landmarks map, if any.
size_t getScanSize() const
Get number of scan rays.
const CLandmark * getByBeaconID(unsigned int ID) const
Returns the landmark with a given beacon ID, or nullptr if not found.
void saveMetricMapRepresentationToFile(const std::string &filNamePrefix) const override
This virtual method saves the map to a file "filNamePrefix"+< some_file_extension >...
std::vector< CLandmark > TSequenceLandmarks
Definition: CLandmarksMap.h:30
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
double distanceTo(const CPoseOrPoint< OTHERCLASS, DIM2 > &b) const
Returns the Euclidean distance to another pose/point:
Definition: CPoseOrPoint.h:214
static mrpt::maps::CLandmark::TLandmarkID _mapMaxID
float stdPixel
Standard deviation of the error in feature detection.
int64_t TLandmarkID
The type for the IDs of landmarks.
Definition: CLandmark.h:41
float yaw
The sensed landmark direction, in radians, measured as the yaw (azimuth) and pitch (negative elevatio...
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:97
mrpt::poses::CPose3DQuat cameraPose
The pose of the LEFT camera, relative to the robot.
mrpt::math::CMatrixDouble33 intrinsicParams
Matrix of intrinsic parameters (containing the focal length and principal point coordinates): ...
Definition: TCamera.h:50
int32_t landmarkID
The ID of the sensed beacon, or INVALID_LANDMARK_ID (-1) if the sensor does not identify the landmark...
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
mrpt::Clock::time_point TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
Definition: datetime.h:40
void bayesianFusion(const CPointPDFGaussian &p1, const CPointPDFGaussian &p2)
Bayesian fusion of two points gauss.
mrpt::maps::CLandmark::TLandmarkID getMapMaxID()
float d2f(const double d)
shortcut for static_cast<float>(double)
double altitude_meters
The measured altitude, in meters (A).
Matching by Euclidean distance between SIFT descriptors.
return_t drawUniform(const double Min, const double Max)
Generate a uniformly distributed pseudo-random number using the MT19937 algorithm, scaled to the selected range.
This class allows loading and storing values and vectors of different types from a configuration text...
This base provides a set of functions for maths stuff.
void setPose(const mrpt::poses::CPointPDFGaussian &p)
Sets the pose from an object:
Definition: CLandmark.cpp:51
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
Definition: CObject.h:102
int SIFTs_decimation
Considers 1 out of "SIFTs_decimation" visual landmarks in the observation during the likelihood compu...
A class for storing a map of 3D probabilistic landmarks.
Definition: CLandmarksMap.h:74
float getLargestDistanceFromOrigin() const
This method returns the largest distance from the origin to any of the points, such as a sphere cente...
mrpt::img::CImage image
The image captured by the camera, that is, the main piece of information of this observation.
#define MRPT_CHECK_NORMAL_NUMBER(v)
Throws an exception if the number is NaN, IND, or +/-INF, or return the same number otherwise...
Definition: exceptions.h:125
Parameters associated to a stereo system.
constexpr double DEG2RAD(const double x)
Degrees to radians.
mrpt::math::CMatrixDouble33 cov
The 3x3 covariance matrix.
void push_back(const CLandmark &lm)
The object is copied, thus the original copy passed as a parameter can be released.
std::pair< mrpt::math::TPoint3D, unsigned int > TPairIdBeacon
std::deque< TMeasurement > sensedData
The list of observed ranges.
A list of TMatchingPair.
Definition: TMatchingPair.h:70
void sphericalCoordinates(const mrpt::math::TPoint3D &point, double &out_range, double &out_yaw, double &out_pitch) const
Computes the spherical coordinates of a 3D point as seen from the 6D pose specified by this object...
Definition: CPose3D.cpp:312
double longitude_degrees
The measured longitude, in degrees (East:+ , West:-)
Observation class for either a pair of left+right or left+disparity images from a stereo camera...
float fieldOfView_pitch
Information about the sensor: The "field-of-view" of the sensor, in radians (for pitch )...
This namespace contains representation of robot actions and observations.
string iniFile(myDataDir+string("benchmark-options.ini"))
double computeLikelihood_SIFT_LandmarkMap(CLandmarksMap *map, mrpt::tfest::TMatchingPairList *correspondences=nullptr, std::vector< bool > *otherCorrespondences=nullptr)
Returns the (logarithmic) likelihood of a set of landmarks "map" given "this" map.
Classes for computer vision, detectors, features, etc.
Definition: CDifodo.h:17
void getPose(mrpt::poses::CPointPDFGaussian &p) const
Returns the pose as an object:
Definition: CLandmark.cpp:32
mrpt::img::TCamera cameraParams
Intrinsic and distortion parameters of the camera.
double x() const
Common members of all points & poses classes.
Definition: CPoseOrPoint.h:143
T * cellByIndex(unsigned int cx, unsigned int cy)
Returns a pointer to the contents of a cell given by its cell indexes, or nullptr if it is out of the...
Definition: CDynamicGrid.h:222
size_t getSizeX() const
Returns the horizontal size of grid map in cells count.
Definition: CDynamicGrid.h:242
return_t drawGaussian1D(const double mean, const double std)
Generate a normally distributed pseudo-random number.
Derived inverse_LLt() const
Returns the inverse of a symmetric matrix using LLt.
CMatrixDouble cov(const MATRIX &v)
Computes the covariance matrix from a list of samples in an NxM matrix, where each row is a sample...
Definition: ops_matrices.h:149
double norm() const
Returns the euclidean norm of vector: .
Definition: CPoseOrPoint.h:256
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:50
A class used to store a 3D point.
Definition: CPoint3D.h:31
A list of visual features, to be used as output by detectors, as input/output by trackers, etc.
Definition: CFeature.h:275
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
double roll() const
Get the ROLL angle (in radians)
Definition: CPose3D.h:558
float stdError
The "sigma" of the sensor, assuming a zero-mean Gaussian noise model.
mrpt::system::TTimeStamp timestampLastSeen
The last time that this landmark was observed.
Definition: CLandmark.h:78
A structure for holding correspondences between two sets of points or points-like entities in 2D or 3...
Definition: TMatchingPair.h:31
bool saveToFile(const std::string &fil) const
Saves the scene to a 3Dscene file, loadable by the application SceneViewer3D.
mrpt::poses::CPose3D sensorLocationOnRobot
The position of the sensor on the robot.
void changeCoordinatesReference(const mrpt::poses::CPose3D &newOrg)
Changes the reference system of the map to a given 3D pose.
size_t getSizeY() const
Returns the vertical size of grid map in cells count.
Definition: CDynamicGrid.h:244
mrpt::maps::CLandmarksMap::TInsertionOptions insertionOptions
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:410
static std::map< std::pair< mrpt::maps::CLandmark::TLandmarkID, mrpt::maps::CLandmark::TLandmarkID >, double > _mEDD
Map of the Euclidean Distance between the descriptors of two SIFT-based landmarks.
mrpt::math::TPoint3D asTPoint() const
Definition: CPoint3D.cpp:164
float sensedDistance
The sensed range itself (in meters).
mrpt::maps::CLandmarksMap::TLikelihoodOptions likelihoodOpts
return_t square(const num_t x)
Inline function for the square of a number.
T x
X,Y,Z coordinates.
Definition: TPoint3D.h:29
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
The class for storing "landmarks" (visual or laser-scan-extracted features,...)
Definition: CLandmark.h:35
#define MAP_DEFINITION_REGISTER(_CLASSNAME_STRINGS, _CLASSNAME_WITH_NS)
Registers one map class into TMetricMapInitializer factory.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:60
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
virtual const mrpt::rtti::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
double productIntegralNormalizedWith2D(const CPointPDFGaussian &p) const
Computes the "correspondence likelihood" of this PDF with another one: This is implemented as the int...
virtual const mrpt::rtti::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:54
Declares a virtual base class for all metric maps storage classes.
Definition: CMetricMap.h:52
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
Definition: CPose2D.h:39
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:85
mrpt::vision::TStereoCalibResults out
Declares a class that represents any robot&#39;s observation.
Definition: CObservation.h:43
mrpt::math::TPoint3D normal
The "normal" to the landmark, i.e.
Definition: CLandmark.h:50
std::deque< TPairIdBeacon > initialBeacons
Initial contents of the map, especified by a set of 3D Beacons with associated IDs.
void loadSiftFeaturesFromStereoImageObservation(const mrpt::obs::CObservationStereoImages &obs, mrpt::maps::CLandmark::TLandmarkID fID, const mrpt::vision::CFeatureExtraction::TOptions &feat_options=mrpt::vision::CFeatureExtraction::TOptions(mrpt::vision::featSIFT))
Loads into this landmarks map the SIFT features extracted from an observation consisting of a pair of...
mrpt::poses::CPose3DQuat rightCameraPose
The pose of the right camera, relative to the left one: Note that using the conventional reference co...
const float & getScanRange(const size_t i) const
The range values of the scan, in meters.
#define ASSERT_ABOVE_(__A, __B)
Definition: exceptions.h:155
size_t matchFeatures(const CFeatureList &list1, const CFeatureList &list2, CMatchedFeatureList &matches, const TMatchingOptions &options=TMatchingOptions(), const TStereoSystemParams &params=TStereoSystemParams())
Find the matches between two lists of features which must be of the same type.
CMatrixDouble33 generateAxisBaseFromDirection(double dx, double dy, double dz)
Computes an axis base (a set of three 3D normal vectors) with the given vector being the first of the...
Definition: geometry.cpp:2569
#define MRPT_END
Definition: exceptions.h:245
This observation represents a number of range-bearing value pairs, each one for a detected landmark...
A structure containing options for the matching.
TInsertionOptions()
Initilization of default parameters.
std::vector< mrpt::vision::CFeature > features
The set of features from which the landmark comes.
Definition: CLandmark.h:44
void loadSiftFeaturesFromImageObservation(const mrpt::obs::CObservationImage &obs, const mrpt::vision::CFeatureExtraction::TOptions &feat_options=mrpt::vision::CFeatureExtraction::TOptions(mrpt::vision::featSIFT))
Loads into this landmarks map the SIFT features extracted from an image observation (Previous content...
content_t fields
Message content, accesible by individual fields.
This class allows the user to create, load, save, and render 3D scenes using OpenGL primitives...
Definition: COpenGLScene.h:56
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
EIGEN_MAP asEigen()
Get as an Eigen-compatible Eigen::Map object.
Definition: CMatrixFixed.h:251
mrpt::poses::CPoint3D sensorLocationOnRobot
Position of the sensor on the robot.
int x2idx(double x) const
Transform a coordinate values into cell indexes.
Definition: CDynamicGrid.h:256
#define INVALID_LANDMARK_ID
Used for CObservationBearingRange::TMeasurement::beaconID and others.
Definition: CObservation.h:27
void auxParticleFilterCleanUp() override
This method is called at the end of each "prediction-update-map insertion" cycle within "mrpt::slam::...
void dumpToTextStream(std::ostream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:257
void composePoint(double lx, double ly, double lz, double &gx, double &gy, double &gz, mrpt::optional_ref< mrpt::math::CMatrixDouble33 > out_jacobian_df_dpoint=std::nullopt, mrpt::optional_ref< mrpt::math::CMatrixDouble36 > out_jacobian_df_dpose=std::nullopt, mrpt::optional_ref< mrpt::math::CMatrixDouble36 > out_jacobian_df_dse3=std::nullopt, bool use_small_rot_approx=false) const
An alternative, slightly more efficient way of doing with G and L being 3D points and P this 6D pose...
float maxEDD_TH
Maximum Euclidean Distance Between SIFT Descriptors.
internal::TSequenceLandmarks::const_iterator const_iterator
T norm() const
Point norm: |v| = sqrt(x^2+y^2+z^2)
Definition: TPoint3D.h:150
void simulateRangeBearingReadings(const mrpt::poses::CPose3D &robotPose, const mrpt::poses::CPose3D &sensorLocationOnRobot, mrpt::obs::CObservationBearingRange &observations, bool sensorDetectsIDs=true, const float stdRange=0.01f, const float stdYaw=mrpt::DEG2RAD(0.1f), const float stdPitch=mrpt::DEG2RAD(0.1f), std::vector< size_t > *real_associations=nullptr, const double spurious_count_mean=0, const double spurious_count_std=0) const
Simulates a noisy bearing-range observation of all the beacons (landamrks with type glBeacon) in the ...
bool validCovariances
True: The individual 3x3 covariance matrices must be taken into account, false (default): All the mea...
bool saveToMATLABScript3D(std::string file, const char *style="b", float confInterval=0.95f) const
Save to a MATLAB script which displays 3D error ellipses for the map.
mrpt::math::TPoint3D pose_mean
The mean of the landmark 3D position.
Definition: CLandmark.h:47
void projectMatchedFeatures(const CMatchedFeatureList &matches, const mrpt::img::TStereoCamera &stereo_camera, std::vector< mrpt::math::TPoint3D > &out_points)
TMatchingMethod matching_method
Matching method.
This class stores messages from GNSS or GNSS+IMU devices, from consumer-grade inexpensive GPS receive...
float sensor_std_range
Taken into account only if validCovariances=false: the standard deviation of the sensor noise model f...
CRandomGenerator & getRandomGenerator()
A static instance of a CRandomGenerator class, for use in single-thread applications.
void insert(const CRenderizable::Ptr &newObject, const std::string &viewportName=std::string("main"))
Insert a new object into the scene, in the given viewport (by default, into the "main" viewport)...
mrpt::img::TCamera leftCamera
Parameters for the left/right cameras: individual intrinsic and distortion parameters of the cameras...
Functions for estimating the optimal transformation between two frames of references given measuremen...
void clear()
Clear the contents of this container.
Definition: ts_hash_map.h:183
void getHomogeneousMatrix(mrpt::math::CMatrixDouble44 &out_HM) const
Returns the corresponding 4x4 homogeneous transformation matrix for the point(translation) or pose (t...
Definition: CPose3D.cpp:797
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
bool isEmpty() const override
Returns true if the map is empty/no observation has been inserted.
uint32_t seenTimesCount
The number of times that this landmark has been seen.
Definition: CLandmark.h:81
mrpt::math::TPoint3D pixelTo3D(const mrpt::img::TPixelCoordf &xy, const mrpt::math::CMatrixDouble33 &A)
Extract a UNITARY 3D vector in the direction of a 3D point, given from its (x,y) pixels coordinates...
struct mrpt::maps::CLandmarksMap::TCustomSequenceLandmarks landmarks
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
Definition: datetime.h:43
void loadOccupancyFeaturesFrom2DRangeScan(const mrpt::obs::CObservation2DRangeScan &obs, const mrpt::poses::CPose3D *robotPose=nullptr, unsigned int downSampleFactor=1)
Loads into this landmarks-map a set of occupancy features according to a 2D range scan (Previous cont...
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
Definition: geometry.cpp:1871
mrpt::img::CImage imageRight
Image from the right camera, only contains a valid image if hasImageRight == true.
void setDiagonal(const std::size_t N, const Scalar value)
Resize to NxN, set all entries to zero, except the main diagonal which is set to value ...
Definition: MatrixBase.h:34
A gaussian distribution for 3D points.
float compute3DMatchingRatio(const mrpt::maps::CMetricMap *otherMap, const mrpt::poses::CPose3D &otherMapPose, const TMatchingRatioParams &params) const override
Computes the ratio in [0,1] of correspondences between "this" and the "otherMap" map, whose 6D pose relative to "this" is "otherMapPose" In the case of a multi-metric map, this returns the average between the maps.
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:148
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
float stdDisp
Standard deviation of the error in disparity computation.
The central class from which images can be analyzed in search of different kinds of interest points a...
TLandmarkID ID
An ID for the landmark (see details next...) This ID was introduced in the version 3 of this class (2...
Definition: CLandmark.h:75
TMeasurementList sensedData
The list of observed ranges:
double drawGaussian1D_normalized()
Generate a normalized (mean=0, std=1) normally distributed sample.
mrpt::math::CMatrixDouble33 K
Intrinsic parameters.
CMatrixDynamic< double > CMatrixDouble
Declares a matrix of double numbers (non serializable).
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186
void multiply_HCHt(const MAT_H &H, const MAT_C &C, MAT_R &R, bool accumResultInOutput=false)
R = H * C * H^t.
Definition: ops_matrices.h:28
mrpt::maps::CLandmarksMap::TLikelihoodOptions likelihoodOptions
bool getScanRangeValidity(const size_t i) const
It&#39;s false (=0) on no reflected rays, referenced to elements in scan.
A list of features.
Definition: CFeature.h:495



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 3a26b90fd Wed Mar 25 20:17:03 2020 +0100 at miƩ mar 25 23:05:41 CET 2020