Main MRPT website > C++ reference for MRPT 1.9.9
COccupancyGridMap2D_likelihood.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "maps-precomp.h" // Precomp header
11 
16 #include <mrpt/utils/CStream.h>
17 
18 using namespace mrpt;
19 using namespace mrpt::math;
20 using namespace mrpt::maps;
21 using namespace mrpt::obs;
22 using namespace mrpt::utils;
23 using namespace mrpt::poses;
24 using namespace std;
25 
26 /*---------------------------------------------------------------
27  Computes the likelihood that a given observation was taken from a given pose in
28  the world being modeled with this map.
29  takenFrom The robot's pose the observation is supposed to be taken from.
30  obs The observation.
31  This method returns a likelihood in the range [0,1].
32  ---------------------------------------------------------------*/
33 double COccupancyGridMap2D::internal_computeObservationLikelihood(
34  const CObservation* obs, const CPose3D& takenFrom3D)
35 {
36  // Ignore laser scans if they are not planar or they are not
37  // at the altitude of this grid map:
39  {
40  const CObservation2DRangeScan* scan =
41  static_cast<const CObservation2DRangeScan*>(obs);
42  if (!scan->isPlanarScan(insertionOptions.horizontalTolerance))
43  return -10;
44  if (insertionOptions.useMapAltitude &&
45  fabs(insertionOptions.mapAltitude - scan->sensorPose.z()) > 0.01)
46  return -10;
47 
48  // OK, go on...
49  }
50 
51  // Execute according to the selected method:
52  // --------------------------------------------
53  CPose2D takenFrom =
54  CPose2D(takenFrom3D); // 3D -> 2D, we are in a gridmap...
55 
56  switch (likelihoodOptions.likelihoodMethod)
57  {
58  default:
59  case lmRayTracing:
60  return computeObservationLikelihood_rayTracing(obs, takenFrom);
61 
62  case lmMeanInformation:
63  return computeObservationLikelihood_MI(obs, takenFrom);
64 
65  case lmConsensus:
66  return computeObservationLikelihood_Consensus(obs, takenFrom);
67 
68  case lmCellsDifference:
69  return computeObservationLikelihood_CellsDifference(obs, takenFrom);
70 
71  case lmLikelihoodField_Thrun:
72  return computeObservationLikelihood_likelihoodField_Thrun(
73  obs, takenFrom);
74 
75  case lmLikelihoodField_II:
76  return computeObservationLikelihood_likelihoodField_II(
77  obs, takenFrom);
78 
79  case lmConsensusOWA:
80  return computeObservationLikelihood_ConsensusOWA(obs, takenFrom);
81  };
82 }
83 
84 /*---------------------------------------------------------------
85  computeObservationLikelihood_Consensus
86 ---------------------------------------------------------------*/
87 double COccupancyGridMap2D::computeObservationLikelihood_Consensus(
88  const CObservation* obs, const CPose2D& takenFrom)
89 {
90  double likResult = 0;
91 
92  // This function depends on the observation type:
93  // -----------------------------------------------------
95  {
96  // THROW_EXCEPTION("This method is defined for 'CObservation2DRangeScan'
97  // classes only.");
98  return 1e-3;
99  }
100  // Observation is a laser range scan:
101  // -------------------------------------------
102  const CObservation2DRangeScan* o =
103  static_cast<const CObservation2DRangeScan*>(obs);
104 
105  // Insert only HORIZONTAL scans, since the grid is supposed to
106  // be a horizontal representation of space.
107  if (!o->isPlanarScan(insertionOptions.horizontalTolerance))
108  return 0.5f; // NO WAY TO ESTIMATE NON HORIZONTAL SCANS!!
109 
110  // Assure we have a 2D points-map representation of the points from the
111  // scan:
112  const CPointsMap* compareMap =
114 
115  // Observation is a points map:
116  // -------------------------------------------
117  size_t Denom = 0;
118  // int Acells = 1;
119  TPoint2D pointGlobal, pointLocal;
120 
121  // Get the points buffers:
122 
123  // compareMap.getPointsBuffer( n, xs, ys, zs );
124  const size_t n = compareMap->size();
125 
126  for (size_t i = 0; i < n; i += likelihoodOptions.consensus_takeEachRange)
127  {
128  // Get the point and pass it to global coordinates:
129  compareMap->getPoint(i, pointLocal);
130  takenFrom.composePoint(pointLocal, pointGlobal);
131 
132  int cx0 = x2idx(pointGlobal.x);
133  int cy0 = y2idx(pointGlobal.y);
134 
135  likResult += 1 - getCell_nocheck(cx0, cy0);
136  Denom++;
137  }
138  if (Denom) likResult /= Denom;
139  likResult =
140  pow(likResult, static_cast<double>(likelihoodOptions.consensus_pow));
141 
142  return log(likResult);
143 }
144 
145 /*---------------------------------------------------------------
146  computeObservationLikelihood_ConsensusOWA
147 ---------------------------------------------------------------*/
148 double COccupancyGridMap2D::computeObservationLikelihood_ConsensusOWA(
149  const CObservation* obs, const CPose2D& takenFrom)
150 {
151  double likResult = 0;
152 
153  // This function depends on the observation type:
154  // -----------------------------------------------------
156  {
157  // THROW_EXCEPTION("This method is defined for 'CObservation2DRangeScan'
158  // classes only.");
159  return 1e-3;
160  }
161  // Observation is a laser range scan:
162  // -------------------------------------------
163  const CObservation2DRangeScan* o =
164  static_cast<const CObservation2DRangeScan*>(obs);
165 
166  // Insert only HORIZONTAL scans, since the grid is supposed to
167  // be a horizontal representation of space.
168  if (!o->isPlanarScan(insertionOptions.horizontalTolerance))
169  return 0.5; // NO WAY TO ESTIMATE NON HORIZONTAL SCANS!!
170 
171  // Assure we have a 2D points-map representation of the points from the
172  // scan:
174  insOpt.minDistBetweenLaserPoints = -1; // ALL the laser points
175 
176  const CPointsMap* compareMap =
178 
179  // Observation is a points map:
180  // -------------------------------------------
181  int Acells = 1;
182  TPoint2D pointGlobal, pointLocal;
183 
184  // Get the points buffers:
185  const size_t n = compareMap->size();
186 
187  // Store the likelihood values in this vector:
188  likelihoodOutputs.OWA_pairList.clear();
189  for (size_t i = 0; i < n; i++)
190  {
191  // Get the point and pass it to global coordinates:
192  compareMap->getPoint(i, pointLocal);
193  takenFrom.composePoint(pointLocal, pointGlobal);
194 
195  int cx0 = x2idx(pointGlobal.x);
196  int cy0 = y2idx(pointGlobal.y);
197 
198  int cxMin = max(0, cx0 - Acells);
199  int cxMax = min(static_cast<int>(size_x) - 1, cx0 + Acells);
200  int cyMin = max(0, cy0 - Acells);
201  int cyMax = min(static_cast<int>(size_y) - 1, cy0 + Acells);
202 
203  double lik = 0;
204 
205  for (int cx = cxMin; cx <= cxMax; cx++)
206  for (int cy = cyMin; cy <= cyMax; cy++)
207  lik += 1 - getCell_nocheck(cx, cy);
208 
209  int nCells = (cxMax - cxMin + 1) * (cyMax - cyMin + 1);
210  ASSERT_(nCells > 0);
211  lik /= nCells;
212 
213  TPairLikelihoodIndex element;
214  element.first = lik;
215  element.second = pointGlobal;
216  likelihoodOutputs.OWA_pairList.push_back(element);
217  } // for each range point
218 
219  // Sort the list of likelihood values, in descending order:
220  // ------------------------------------------------------------
221  std::sort(
222  likelihoodOutputs.OWA_pairList.begin(),
223  likelihoodOutputs.OWA_pairList.end());
224 
225  // Cut the vector to the highest "likelihoodOutputs.OWA_length" elements:
226  size_t M = likelihoodOptions.OWA_weights.size();
227  ASSERT_(likelihoodOutputs.OWA_pairList.size() >= M);
228 
229  likelihoodOutputs.OWA_pairList.resize(M);
230  likelihoodOutputs.OWA_individualLikValues.resize(M);
231  likResult = 0;
232  for (size_t k = 0; k < M; k++)
233  {
234  likelihoodOutputs.OWA_individualLikValues[k] =
235  likelihoodOutputs.OWA_pairList[k].first;
236  likResult += likelihoodOptions.OWA_weights[k] *
237  likelihoodOutputs.OWA_individualLikValues[k];
238  }
239 
240  return log(likResult);
241 }
242 
243 /*---------------------------------------------------------------
244  computeObservationLikelihood_CellsDifference
245 ---------------------------------------------------------------*/
246 double COccupancyGridMap2D::computeObservationLikelihood_CellsDifference(
247  const CObservation* obs, const CPose2D& takenFrom)
248 {
249  double ret = 0.5;
250 
251  // This function depends on the observation type:
252  // -----------------------------------------------------
254  {
255  // Observation is a laser range scan:
256  // -------------------------------------------
257  const CObservation2DRangeScan* o =
258  static_cast<const CObservation2DRangeScan*>(obs);
259 
260  // Insert only HORIZONTAL scans, since the grid is supposed to
261  // be a horizontal representation of space.
262  if (!o->isPlanarScan(insertionOptions.horizontalTolerance))
263  return 0.5; // NO WAY TO ESTIMATE NON HORIZONTAL SCANS!!
264 
265  // Build a copy of this occupancy grid:
266  COccupancyGridMap2D compareGrid(
267  takenFrom.x() - 10, takenFrom.x() + 10, takenFrom.y() - 10,
268  takenFrom.y() + 10, resolution);
269  CPose3D robotPose(takenFrom);
270  int Ax, Ay;
271 
272  // Insert in this temporary grid:
273  compareGrid.insertionOptions.maxDistanceInsertion =
274  insertionOptions.maxDistanceInsertion;
275  compareGrid.insertionOptions.maxOccupancyUpdateCertainty = 0.95f;
276  o->insertObservationInto(&compareGrid, &robotPose);
277 
278  // Save Cells offset between the two grids:
279  Ax = round((x_min - compareGrid.x_min) / resolution);
280  Ay = round((y_min - compareGrid.y_min) / resolution);
281 
282  int nCellsCompared = 0;
283  float cellsDifference = 0;
284  int x0 = max(0, Ax);
285  int y0 = max(0, Ay);
286  int x1 = min(compareGrid.size_x, size_x + Ax);
287  int y1 = min(compareGrid.size_y, size_y + Ay);
288 
289  for (int x = x0; x < x1; x += 1)
290  {
291  for (int y = y0; y < y1; y += 1)
292  {
293  float xx = compareGrid.idx2x(x);
294  float yy = compareGrid.idx2y(y);
295 
296  float c1 = getPos(xx, yy);
297  float c2 = compareGrid.getCell(x, y);
298  if (c2 < 0.45f || c2 > 0.55f)
299  {
300  nCellsCompared++;
301  if ((c1 > 0.5 && c2 < 0.5) || (c1 < 0.5 && c2 > 0.5))
302  cellsDifference++;
303  }
304  }
305  }
306  ret = 1 - cellsDifference / (nCellsCompared);
307  }
308  return log(ret);
309 }
310 
311 /*---------------------------------------------------------------
312  computeObservationLikelihood_MI
313 ---------------------------------------------------------------*/
314 double COccupancyGridMap2D::computeObservationLikelihood_MI(
315  const CObservation* obs, const CPose2D& takenFrom)
316 {
317  MRPT_START
318 
319  CPose3D poseRobot(takenFrom);
320  double res;
321 
322  // Dont modify the grid, only count the changes in Information
323  updateInfoChangeOnly.enabled = true;
324  insertionOptions.maxDistanceInsertion *=
325  likelihoodOptions.MI_ratio_max_distance;
326 
327  // Reset the new information counters:
328  updateInfoChangeOnly.cellsUpdated = 0;
329  updateInfoChangeOnly.I_change = 0;
330  updateInfoChangeOnly.laserRaysSkip = likelihoodOptions.MI_skip_rays;
331 
332  // Insert the observation (It will not be really inserted, only the
333  // information counted)
334  insertObservation(obs, &poseRobot);
335 
336  // Compute the change in I aported by the observation:
337  double newObservation_mean_I;
338  if (updateInfoChangeOnly.cellsUpdated)
339  newObservation_mean_I =
340  updateInfoChangeOnly.I_change / updateInfoChangeOnly.cellsUpdated;
341  else
342  newObservation_mean_I = 0;
343 
344  // Let the normal mode enabled, i.e. the grid can be updated
345  updateInfoChangeOnly.enabled = false;
346  insertionOptions.maxDistanceInsertion /=
347  likelihoodOptions.MI_ratio_max_distance;
348 
349  res =
350  pow(newObservation_mean_I,
351  static_cast<double>(likelihoodOptions.MI_exponent));
352 
353  return log(res);
354 
355  MRPT_END
356 }
357 
358 double COccupancyGridMap2D::computeObservationLikelihood_rayTracing(
359  const CObservation* obs, const CPose2D& takenFrom)
360 {
361  double ret = 0;
362 
363  // This function depends on the observation type:
364  // -----------------------------------------------------
366  {
367  // Observation is a laser range scan:
368  // -------------------------------------------
369  const CObservation2DRangeScan* o =
370  static_cast<const CObservation2DRangeScan*>(obs);
371  CObservation2DRangeScan simulatedObs;
372 
373  // Insert only HORIZONTAL scans, since the grid is supposed to
374  // be a horizontal representation of space.
375  if (!o->isPlanarScan(insertionOptions.horizontalTolerance))
376  return 0.5; // NO WAY TO ESTIMATE NON HORIZONTAL SCANS!!
377 
378  // The number of simulated rays will be original range scan rays /
379  // DOWNRATIO
380  int decimation = likelihoodOptions.rayTracing_decimation;
381  int nRays = o->scan.size();
382 
383  // Perform simulation using same parameters than real observation:
384  simulatedObs.aperture = o->aperture;
385  simulatedObs.maxRange = o->maxRange;
386  simulatedObs.rightToLeft = o->rightToLeft;
387  simulatedObs.sensorPose = o->sensorPose;
388 
389  // Performs the scan simulation:
390  laserScanSimulator(
391  simulatedObs, // The in/out observation
392  takenFrom, // robot pose
393  0.45f, // Cells threshold
394  nRays, // Scan length
395  0, decimation);
396 
397  double stdLaser = likelihoodOptions.rayTracing_stdHit;
398  double stdSqrt2 = sqrt(2.0f) * stdLaser;
399 
400  // Compute likelihoods:
401  ret = 1;
402  // bool useDF = likelihoodOptions.rayTracing_useDistanceFilter;
403  float r_sim, r_obs;
404  double likelihood;
405 
406  for (int j = 0; j < nRays; j += decimation)
407  {
408  // Simulated and measured ranges:
409  r_sim = simulatedObs.scan[j];
410  r_obs = o->scan[j];
411 
412  // Is a valid range?
413  if (o->validRange[j])
414  {
415  likelihood =
416  0.1 / o->maxRange +
417  0.9 *
418  exp(-square(
419  min((float)fabs(r_sim - r_obs), 2.0f) / stdSqrt2));
420  ret += log(likelihood);
421  // printf("Sim=%f\tReal=%f\tlik=%f\n",r_sim,r_obs,likelihood);
422  }
423  }
424  }
425 
426  return ret;
427 }
428 /**/
429 
430 /*---------------------------------------------------------------
431  computeObservationLikelihood_likelihoodField_Thrun
432 ---------------------------------------------------------------*/
433 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_Thrun(
434  const CObservation* obs, const CPose2D& takenFrom)
435 {
436  MRPT_START
437 
438  double ret = 0;
439 
440  // This function depends on the observation type:
441  // -----------------------------------------------------
443  {
444  // Observation is a laser range scan:
445  // -------------------------------------------
446  const CObservation2DRangeScan* o =
447  static_cast<const CObservation2DRangeScan*>(obs);
448 
449  // Insert only HORIZONTAL scans, since the grid is supposed to
450  // be a horizontal representation of space.
451  if (!o->isPlanarScan(insertionOptions.horizontalTolerance)) return -10;
452 
453  // Assure we have a 2D points-map representation of the points from the
454  // scan:
456  opts.minDistBetweenLaserPoints = resolution * 0.5f;
457  opts.isPlanarMap = true; // Already filtered above!
458  opts.horizontalTolerance = insertionOptions.horizontalTolerance;
459 
460  // Compute the likelihood of the points in this grid map:
461  ret = computeLikelihoodField_Thrun(
462  o->buildAuxPointsMap<mrpt::maps::CPointsMap>(&opts), &takenFrom);
463 
464  } // end of observation is a scan range 2D
465  else if (IS_CLASS(obs, CObservationRange))
466  {
467  // Sonar-like observations:
468  // ---------------------------------------
469  const CObservationRange* o = static_cast<const CObservationRange*>(obs);
470 
471  // Create a point map representation of the observation:
472  CSimplePointsMap pts;
473  pts.insertionOptions.minDistBetweenLaserPoints = resolution * 0.5f;
474  pts.insertObservation(o);
475 
476  // Compute the likelihood of the points in this grid map:
477  ret = computeLikelihoodField_Thrun(&pts, &takenFrom);
478  }
479 
480  return ret;
481 
482  MRPT_END
483 }
484 
485 /*---------------------------------------------------------------
486  computeObservationLikelihood_likelihoodField_II
487 ---------------------------------------------------------------*/
488 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_II(
489  const CObservation* obs, const CPose2D& takenFrom)
490 {
491  MRPT_START
492 
493  double ret = 0;
494 
495  // This function depends on the observation type:
496  // -----------------------------------------------------
498  {
499  // Observation is a laser range scan:
500  // -------------------------------------------
501  const CObservation2DRangeScan* o =
502  static_cast<const CObservation2DRangeScan*>(obs);
503 
504  // Insert only HORIZONTAL scans, since the grid is supposed to
505  // be a horizontal representation of space.
506  if (!o->isPlanarScan(insertionOptions.horizontalTolerance))
507  return 0.5f; // NO WAY TO ESTIMATE NON HORIZONTAL SCANS!!
508 
509  // Assure we have a 2D points-map representation of the points from the
510  // scan:
511 
512  // Compute the likelihood of the points in this grid map:
513  ret = computeLikelihoodField_II(
514  o->buildAuxPointsMap<mrpt::maps::CPointsMap>(), &takenFrom);
515 
516  } // end of observation is a scan range 2D
517 
518  return ret;
519 
520  MRPT_END
521 }
522 
523 /*---------------------------------------------------------------
524  computeLikelihoodField_Thrun
525  ---------------------------------------------------------------*/
526 double COccupancyGridMap2D::computeLikelihoodField_Thrun(
527  const CPointsMap* pm, const CPose2D* relativePose)
528 {
529  MRPT_START
530 
531  double ret;
532  size_t N = pm->size();
533  int K = (int)ceil(
534  likelihoodOptions.LF_maxCorrsDistance /*m*/ /
535  resolution); // The size of the checking area for matchings:
536 
537  bool Product_T_OrSum_F = !likelihoodOptions.LF_alternateAverageMethod;
538 
539  if (!N)
540  {
541  return -100; // No way to estimate this likelihood!!
542  }
543 
544  // Compute the likelihoods for each point:
545  ret = 0;
546 
547  float stdHit = likelihoodOptions.LF_stdHit;
548  float zHit = likelihoodOptions.LF_zHit;
549  float zRandom = likelihoodOptions.LF_zRandom;
550  float zRandomMaxRange = likelihoodOptions.LF_maxRange;
551  float zRandomTerm = zRandom / zRandomMaxRange;
552  float Q = -0.5f / square(stdHit);
553  int M = 0;
554 
555  unsigned int size_x_1 = size_x - 1;
556  unsigned int size_y_1 = size_y - 1;
557 
558 #define LIK_LF_CACHE_INVALID (66)
559 
560  // Aux. variables for the "for j" loop:
561  double thisLik = LIK_LF_CACHE_INVALID;
562  double maxCorrDist_sq = square(likelihoodOptions.LF_maxCorrsDistance);
563  double minimumLik = zRandomTerm + zHit * exp(Q * maxCorrDist_sq);
564  double ccos, ssin;
565  float occupiedMinDist;
566 
567  if (likelihoodOptions.enableLikelihoodCache)
568  {
569  // Reset the precomputed likelihood values map
570  if (precomputedLikelihoodToBeRecomputed)
571  {
572  if (!map.empty())
573  precomputedLikelihood.assign(map.size(), LIK_LF_CACHE_INVALID);
574  else
575  precomputedLikelihood.clear();
576 
577  precomputedLikelihoodToBeRecomputed = false;
578  }
579  }
580 
581  cellType thresholdCellValue = p2l(0.5f);
582  int decimation = likelihoodOptions.LF_decimation;
583 
584  const double _resolution = this->resolution;
585  const double constDist2DiscrUnits = 100 / (_resolution * _resolution);
586  const double constDist2DiscrUnits_INV = 1.0 / constDist2DiscrUnits;
587 
588  if (N < 10) decimation = 1;
589 
590  TPoint2D pointLocal;
591  TPoint2D pointGlobal;
592 
593  for (size_t j = 0; j < N; j += decimation)
594  {
595  occupiedMinDist = maxCorrDist_sq; // The max.distance
596 
597  // Get the point and pass it to global coordinates:
598  if (relativePose)
599  {
600  pm->getPoint(j, pointLocal);
601 // pointGlobal = *relativePose + pointLocal;
602 #ifdef HAVE_SINCOS
603  ::sincos(relativePose->phi(), &ssin, &ccos);
604 #else
605  ccos = cos(relativePose->phi());
606  ssin = sin(relativePose->phi());
607 #endif
608  pointGlobal.x =
609  relativePose->x() + pointLocal.x * ccos - pointLocal.y * ssin;
610  pointGlobal.y =
611  relativePose->y() + pointLocal.x * ssin + pointLocal.y * ccos;
612  }
613  else
614  {
615  pm->getPoint(j, pointGlobal);
616  }
617 
618  // Point to cell indixes
619  int cx = x2idx(pointGlobal.x);
620  int cy = y2idx(pointGlobal.y);
621 
622  // Precomputed table:
623  // Tip: Comparison cx<0 is implicit in (unsigned)(x)>size...
624  if (static_cast<unsigned>(cx) >= size_x_1 ||
625  static_cast<unsigned>(cy) >= size_y_1)
626  {
627  // We are outside of the map: Assign the likelihood for the max.
628  // correspondence distance:
629  thisLik = minimumLik;
630  }
631  else
632  {
633  // We are into the map limits:
634  if (likelihoodOptions.enableLikelihoodCache)
635  {
636  thisLik = precomputedLikelihood[cx + cy * size_x];
637  }
638 
639  if (!likelihoodOptions.enableLikelihoodCache ||
640  thisLik == LIK_LF_CACHE_INVALID)
641  {
642  // Compute now:
643  // -------------
644  // Find the closest occupied cell in a certain range, given by
645  // K:
646  int xx1 = max(0, cx - K);
647  int xx2 = min(size_x_1, (unsigned)(cx + K));
648  int yy1 = max(0, cy - K);
649  int yy2 = min(size_y_1, (unsigned)(cy + K));
650 
651  // Optimized code: this part will be invoked a *lot* of times:
652  {
653  cellType* mapPtr =
654  &map[xx1 + yy1 * size_x]; // Initial pointer position
655  unsigned incrAfterRow = size_x - ((xx2 - xx1) + 1);
656 
657  signed int Ax0 = 10 * (xx1 - cx);
658  signed int Ay = 10 * (yy1 - cy);
659 
660  unsigned int occupiedMinDistInt = mrpt::utils::round(
661  maxCorrDist_sq * constDist2DiscrUnits);
662 
663  for (int yy = yy1; yy <= yy2; yy++)
664  {
665  unsigned int Ay2 =
666  square((unsigned int)(Ay)); // Square is faster
667  // with unsigned.
668  signed short Ax = Ax0;
669  cellType cell;
670 
671  for (int xx = xx1; xx <= xx2; xx++)
672  {
673  if ((cell = *mapPtr++) < thresholdCellValue)
674  {
675  unsigned int d =
676  square((unsigned int)(Ax)) + Ay2;
677  keep_min(occupiedMinDistInt, d);
678  }
679  Ax += 10;
680  }
681  // Go to (xx1,yy++)
682  mapPtr += incrAfterRow;
683  Ay += 10;
684  }
685 
686  occupiedMinDist =
687  occupiedMinDistInt * constDist2DiscrUnits_INV;
688  }
689 
690  if (likelihoodOptions.LF_useSquareDist)
691  occupiedMinDist *= occupiedMinDist;
692 
693  thisLik = zRandomTerm + zHit * exp(Q * occupiedMinDist);
694 
695  if (likelihoodOptions.enableLikelihoodCache)
696  // And save it into the table and into "thisLik":
697  precomputedLikelihood[cx + cy * size_x] = thisLik;
698  }
699  }
700 
701  // Update the likelihood:
702  if (Product_T_OrSum_F)
703  {
704  ret += log(thisLik);
705  }
706  else
707  {
708  ret += thisLik;
709  M++;
710  }
711  } // end of for each point in the scan
712 
713  if (!Product_T_OrSum_F) ret = log(ret / M);
714 
715  return ret;
716 
717  MRPT_END
718 }
719 
720 /*---------------------------------------------------------------
721  computeLikelihoodField_II
722  ---------------------------------------------------------------*/
723 double COccupancyGridMap2D::computeLikelihoodField_II(
724  const CPointsMap* pm, const CPose2D* relativePose)
725 {
726  MRPT_START
727 
728  double ret;
729  size_t N = pm->size();
730 
731  if (!N) return 1e-100; // No way to estimate this likelihood!!
732 
733  // Compute the likelihoods for each point:
734  ret = 0;
735  // if (likelihoodOptions.LF_alternateAverageMethod)
736  // ret = 0;
737  // else ret = 1;
738 
739  TPoint2D pointLocal, pointGlobal;
740 
741  float zRandomTerm = 1.0f / likelihoodOptions.LF_maxRange;
742  float Q = -0.5f / square(likelihoodOptions.LF_stdHit);
743 
744  // Aux. cell indixes variables:
745  int cx, cy;
746  size_t j;
747  int cx0, cy0;
748  int cx_min, cx_max;
749  int cy_min, cy_max;
750  int maxRangeInCells =
751  (int)ceil(likelihoodOptions.LF_maxCorrsDistance / resolution);
752  int nCells = 0;
753 
754  // -----------------------------------------------------
755  // Compute around a window of neigbors around each point
756  // -----------------------------------------------------
757  for (j = 0; j < N; j += likelihoodOptions.LF_decimation)
758  {
759  // Get the point and pass it to global coordinates:
760  // ---------------------------------------------
761  if (relativePose)
762  {
763  pm->getPoint(j, pointLocal);
764  pointGlobal = *relativePose + pointLocal;
765  }
766  else
767  {
768  pm->getPoint(j, pointGlobal);
769  }
770 
771  // Point to cell indixes:
772  // ---------------------------------------------
773  cx0 = x2idx(pointGlobal.x);
774  cy0 = y2idx(pointGlobal.y);
775 
776  // Compute the range of cells to compute:
777  // ---------------------------------------------
778  cx_min = max(cx0 - maxRangeInCells, 0);
779  cx_max = min(cx0 + maxRangeInCells, static_cast<int>(size_x));
780  cy_min = max(cy0 - maxRangeInCells, 0);
781  cy_max = min(cy0 + maxRangeInCells, static_cast<int>(size_y));
782 
783  // debugImg.rectangle(cx_min,cy_min,cx_max,cy_max,0xFF0000 );
784 
785  // Compute over the window of cells:
786  // ---------------------------------------------
787  double lik = 0;
788  for (cx = cx_min; cx <= cx_max; cx++)
789  {
790  for (cy = cy_min; cy <= cy_max; cy++)
791  {
792  float P_free = getCell(cx, cy);
793  float termDist =
794  exp(Q * (square(idx2x(cx) - pointGlobal.x) +
795  square(idx2y(cy) - pointGlobal.y)));
796 
797  lik += P_free * zRandomTerm + (1 - P_free) * termDist;
798  } // end for cy
799  } // end for cx
800 
801  // Update the likelihood:
802  if (likelihoodOptions.LF_alternateAverageMethod)
803  ret += lik;
804  else
805  ret += log(lik / ((cy_max - cy_min + 1) * (cx_max - cx_min + 1)));
806  nCells++;
807 
808  } // end of for each point in the scan
809 
810  if (likelihoodOptions.LF_alternateAverageMethod && nCells > 0)
811  ret = log(ret / nCells);
812  else
813  ret = ret / nCells;
814 
815  return ret;
816 
817  MRPT_END
818 }
819 
820 /*---------------------------------------------------------------
821  Initilization of values, don't needed to be called directly.
822  ---------------------------------------------------------------*/
823 COccupancyGridMap2D::TLikelihoodOptions::TLikelihoodOptions()
824  : likelihoodMethod(lmLikelihoodField_Thrun),
825 
826  LF_stdHit(0.35f),
827  LF_zHit(0.95f),
828  LF_zRandom(0.05f),
829  LF_maxRange(81.0f),
830  LF_decimation(5),
831  LF_maxCorrsDistance(0.3f),
832  LF_useSquareDist(false),
833  LF_alternateAverageMethod(false),
834 
835  MI_exponent(2.5f),
836  MI_skip_rays(10),
837  MI_ratio_max_distance(1.5f),
838 
839  rayTracing_useDistanceFilter(true),
840  rayTracing_decimation(10),
841  rayTracing_stdHit(1.0f),
842 
843  consensus_takeEachRange(1),
844  consensus_pow(5),
845  OWA_weights(100, 1 / 100.0f),
846 
847  enableLikelihoodCache(true)
848 {
849 }
850 
851 /*---------------------------------------------------------------
852  loadFromConfigFile
853  ---------------------------------------------------------------*/
855  const mrpt::utils::CConfigFileBase& iniFile, const std::string& section)
856 {
857  likelihoodMethod =
858  iniFile.read_enum(section, "likelihoodMethod", likelihoodMethod);
859 
860  enableLikelihoodCache = iniFile.read_bool(
861  section, "enableLikelihoodCache", enableLikelihoodCache);
862 
863  LF_stdHit = iniFile.read_float(section, "LF_stdHit", LF_stdHit);
864  LF_zHit = iniFile.read_float(section, "LF_zHit", LF_zHit);
865  LF_zRandom = iniFile.read_float(section, "LF_zRandom", LF_zRandom);
866  LF_maxRange = iniFile.read_float(section, "LF_maxRange", LF_maxRange);
867  LF_decimation = iniFile.read_int(section, "LF_decimation", LF_decimation);
868  LF_maxCorrsDistance =
869  iniFile.read_float(section, "LF_maxCorrsDistance", LF_maxCorrsDistance);
870  LF_useSquareDist =
871  iniFile.read_bool(section, "LF_useSquareDist", LF_useSquareDist);
872  LF_alternateAverageMethod = iniFile.read_bool(
873  section, "LF_alternateAverageMethod", LF_alternateAverageMethod);
874 
875  MI_exponent = iniFile.read_float(section, "MI_exponent", MI_exponent);
876  MI_skip_rays = iniFile.read_int(section, "MI_skip_rays", MI_skip_rays);
877  MI_ratio_max_distance = iniFile.read_float(
878  section, "MI_ratio_max_distance", MI_ratio_max_distance);
879 
880  rayTracing_useDistanceFilter = iniFile.read_bool(
881  section, "rayTracing_useDistanceFilter", rayTracing_useDistanceFilter);
882  rayTracing_stdHit =
883  iniFile.read_float(section, "rayTracing_stdHit", rayTracing_stdHit);
884 
885  consensus_takeEachRange = iniFile.read_int(
886  section, "consensus_takeEachRange", consensus_takeEachRange);
887  consensus_pow = iniFile.read_float(section, "consensus_pow", consensus_pow);
888 
889  iniFile.read_vector(section, "OWA_weights", OWA_weights, OWA_weights);
890 }
891 
892 /*---------------------------------------------------------------
893  dumpToTextStream
894  ---------------------------------------------------------------*/
896  mrpt::utils::CStream& out) const
897 {
898  out.printf(
899  "\n----------- [COccupancyGridMap2D::TLikelihoodOptions] ------------ "
900  "\n\n");
901 
902  out.printf("likelihoodMethod = ");
903  switch (likelihoodMethod)
904  {
905  case lmMeanInformation:
906  out.printf("lmMeanInformation");
907  break;
908  case lmRayTracing:
909  out.printf("lmRayTracing");
910  break;
911  case lmConsensus:
912  out.printf("lmConsensus");
913  break;
914  case lmCellsDifference:
915  out.printf("lmCellsDifference");
916  break;
918  out.printf("lmLikelihoodField_Thrun");
919  break;
921  out.printf("lmLikelihoodField_II");
922  break;
923  case lmConsensusOWA:
924  out.printf("lmConsensusOWA");
925  break;
926  default:
927  out.printf("UNKNOWN!!!");
928  break;
929  }
930  out.printf("\n");
931 
932  out.printf(
933  "enableLikelihoodCache = %c\n",
934  enableLikelihoodCache ? 'Y' : 'N');
935 
936  out.printf("LF_stdHit = %f\n", LF_stdHit);
937  out.printf("LF_zHit = %f\n", LF_zHit);
938  out.printf("LF_zRandom = %f\n", LF_zRandom);
939  out.printf("LF_maxRange = %f\n", LF_maxRange);
940  out.printf("LF_decimation = %u\n", LF_decimation);
941  out.printf(
942  "LF_maxCorrsDistance = %f\n", LF_maxCorrsDistance);
943  out.printf(
944  "LF_useSquareDist = %c\n",
945  LF_useSquareDist ? 'Y' : 'N');
946  out.printf(
947  "LF_alternateAverageMethod = %c\n",
948  LF_alternateAverageMethod ? 'Y' : 'N');
949  out.printf("MI_exponent = %f\n", MI_exponent);
950  out.printf("MI_skip_rays = %u\n", MI_skip_rays);
951  out.printf(
952  "MI_ratio_max_distance = %f\n",
953  MI_ratio_max_distance);
954  out.printf(
955  "rayTracing_useDistanceFilter = %c\n",
956  rayTracing_useDistanceFilter ? 'Y' : 'N');
957  out.printf(
958  "rayTracing_decimation = %u\n",
959  rayTracing_decimation);
960  out.printf(
961  "rayTracing_stdHit = %f\n", rayTracing_stdHit);
962  out.printf(
963  "consensus_takeEachRange = %u\n",
964  consensus_takeEachRange);
965  out.printf(
966  "consensus_pow = %.02f\n", consensus_pow);
967  out.printf("OWA_weights = [");
968  for (size_t i = 0; i < OWA_weights.size(); i++)
969  {
970  if (i < 3 || i > (OWA_weights.size() - 3))
971  out.printf("%.03f ", OWA_weights[i]);
972  else if (i == 3 && OWA_weights.size() > 6)
973  out.printf(" ... ");
974  }
975  out.printf("] (size=%u)\n", (unsigned)OWA_weights.size());
976  out.printf("\n");
977 }
978 
979 /** Returns true if this map is able to compute a sensible likelihood function
980  * for this observation (i.e. an occupancy grid map cannot with an image).
981  * \param obs The observation.
982  * \sa computeObservationLikelihood
983  */
985  const mrpt::obs::CObservation* obs) const
986 {
987  // Ignore laser scans if they are not planar or they are not
988  // at the altitude of this grid map:
990  {
991  const CObservation2DRangeScan* scan =
992  static_cast<const CObservation2DRangeScan*>(obs);
993 
995  return false;
997  fabs(insertionOptions.mapAltitude - scan->sensorPose.z()) > 0.01)
998  return false;
999 
1000  // OK, go on...
1001  return true;
1002  }
1003  else // Is not a laser scanner...
1004  {
1005  return false;
1006  }
1007 }
double x() const
Common members of all points & poses classes.
Definition: CPoseOrPoint.h:135
bool isPlanarMap
If set to true, only HORIZONTAL (in the XY plane) measurements will be inserted in the map (Default v...
Definition: CPointsMap.h:236
bool read_bool(const std::string &section, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
Declares a class derived from "CObservation" that encapsules a single range measurement, and associated parameters.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
#define min(a, b)
double x
X,Y coordinates.
bool internal_canComputeObservationLikelihood(const mrpt::obs::CObservation *obs) const override
Returns true if this map is able to compute a sensible likelihood function for this observation (i...
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
const POINTSMAP * buildAuxPointsMap(const void *options=nullptr) const
Returns a cached points map representing this laser scan, building it upon the first call...
GLenum GLsizei n
Definition: glext.h:5074
virtual const mrpt::utils::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans. ...
STL namespace.
TInsertionOptions insertionOptions
With this struct options are provided to the observation insertion process.
std::pair< double, mrpt::math::TPoint2D > TPairLikelihoodIndex
Auxiliary private class.
void composePoint(double lx, double ly, double &gx, double &gy) const
An alternative, slightly more efficient way of doing with G and L being 2D points and P this 2D pose...
Definition: CPose2D.cpp:188
This class allows loading and storing values and vectors of different types from a configuration text...
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
float maxRange
The maximum range allowed by the device, in meters (e.g.
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
With this struct options are provided to the observation insertion process.
Definition: CPointsMap.h:204
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors...
Definition: CPointsMap.h:63
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
bool insertObservationInto(METRICMAP *theMap, const mrpt::poses::CPose3D *robotPose=nullptr) const
This method is equivalent to:
Definition: CObservation.h:96
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
Definition: CObject.h:85
#define MRPT_END
bool isPlanarScan(const double tolerance=0) const
Return true if the laser scanner is "horizontal", so it has an absolute value of "pitch" and "roll" l...
void read_vector(const std::string &section, const std::string &name, const VECTOR_TYPE &defaultValue, VECTOR_TYPE &outValues, bool failIfNotFound=false) const
Reads a configuration parameter of type vector, stored in the file as a string: "[v1 v2 v3 ...
#define LIK_LF_CACHE_INVALID
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini" file.
This namespace contains representation of robot actions and observations.
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< char > > validRange
It&#39;s false (=0) on no reflected rays, referenced to elements in scan.
GLsizei const GLchar ** string
Definition: glext.h:4101
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
ENUMTYPE read_enum(const std::string &section, const std::string &name, const ENUMTYPE &defaultValue, bool failIfNotFound=false) const
Reads an "enum" value, where the value in the config file can be either a numerical value or the symb...
A class for storing an occupancy grid map.
#define MRPT_START
unsigned long getPoint(size_t index, float &x, float &y, float &z) const
Access to a given point from map, as a 2D point.
Definition: CPointsMap.cpp:222
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
Definition: bits.h:220
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
Definition: CPose2D.h:40
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
Declares a class that represents any robot&#39;s observation.
Definition: CObservation.h:41
float horizontalTolerance
The tolerance in rads in pitch & roll for a laser scan to be considered horizontal, then processed by calls to this class (default=0).
const double & phi() const
Get the phi angle of the 2D pose (in radians)
Definition: CPose2D.h:91
#define IS_CLASS(ptrObj, class_name)
Evaluates to true if the given pointer to an object (derived from mrpt::utils::CSerializable) is of t...
Definition: CObject.h:103
bool useMapAltitude
The parameter "mapAltitude" has effect while inserting observations in the grid only if this is true...
float horizontalTolerance
The tolerance in rads in pitch & roll for a laser scan to be considered horizontal, considered only when isPlanarMap=true (default=0).
Definition: CPointsMap.h:240
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
#define ASSERT_(f)
float mapAltitude
The altitude (z-axis) of 2D scans (within a 0.01m tolerance) for they to be inserted in this map! ...
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
GLenum GLint GLint y
Definition: glext.h:3538
TInsertionOptions insertionOptions
The options used when inserting observations in the map.
Definition: CPointsMap.h:256
GLuint res
Definition: glext.h:7268
GLenum GLint x
Definition: glext.h:3538
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< float > > scan
The range values of the scan, in meters.
Lightweight 2D point.
size_t size() const
Returns the number of stored points in the map.
Definition: CPointsMap.h:385
bool insertObservation(const mrpt::obs::CObservation *obs, const mrpt::poses::CPose3D *robotPose=NULL)
Insert the observation information into this map.
Definition: CMetricMap.cpp:95
int16_t cellType
The type of the map cells:
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
void dumpToTextStream(mrpt::utils::CStream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a CStream.
virtual int printf(const char *fmt,...) MRPT_printf_format_check(2
Writes a string to the stream in a textual form.
Definition: CStream.cpp:597
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
float minDistBetweenLaserPoints
The minimum distance between points (in 3D): If two points are too close, one of them is not inserted...
Definition: CPointsMap.h:217



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019