32 double COccupancyGridMap2D::internal_computeObservationLikelihood(
40 if (!scan.isPlanarScan(insertionOptions.horizontalTolerance))
42 if (insertionOptions.useMapAltitude &&
43 fabs(insertionOptions.mapAltitude - scan.sensorPose.z()) > 0.01)
54 switch (likelihoodOptions.likelihoodMethod)
58 return computeObservationLikelihood_rayTracing(obs, takenFrom);
60 case lmMeanInformation:
61 return computeObservationLikelihood_MI(obs, takenFrom);
64 return computeObservationLikelihood_Consensus(obs, takenFrom);
66 case lmCellsDifference:
67 return computeObservationLikelihood_CellsDifference(obs, takenFrom);
69 case lmLikelihoodField_Thrun:
70 return computeObservationLikelihood_likelihoodField_Thrun(
73 case lmLikelihoodField_II:
74 return computeObservationLikelihood_likelihoodField_II(
78 return computeObservationLikelihood_ConsensusOWA(obs, takenFrom);
85 double COccupancyGridMap2D::computeObservationLikelihood_Consensus(
104 if (!o.isPlanarScan(insertionOptions.horizontalTolerance))
120 const size_t n = compareMap->
size();
122 for (
size_t i = 0; i < n; i += likelihoodOptions.consensus_takeEachRange)
125 compareMap->getPoint(i, pointLocal);
128 int cx0 = x2idx(pointGlobal.
x);
129 int cy0 = y2idx(pointGlobal.
y);
131 likResult += 1 - getCell_nocheck(cx0, cy0);
134 if (Denom) likResult /= Denom;
136 pow(likResult, static_cast<double>(likelihoodOptions.consensus_pow));
138 return log(likResult);
144 double COccupancyGridMap2D::computeObservationLikelihood_ConsensusOWA(
147 double likResult = 0;
163 if (!o.isPlanarScan(insertionOptions.horizontalTolerance))
171 const auto* compareMap =
180 const size_t n = compareMap->
size();
183 likelihoodOutputs.OWA_pairList.clear();
184 for (
size_t i = 0; i < n; i++)
187 compareMap->getPoint(i, pointLocal);
190 int cx0 = x2idx(pointGlobal.
x);
191 int cy0 = y2idx(pointGlobal.
y);
193 int cxMin = max(0, cx0 - Acells);
194 int cxMax = min(static_cast<int>(size_x) - 1, cx0 + Acells);
195 int cyMin = max(0, cy0 - Acells);
196 int cyMax = min(static_cast<int>(size_y) - 1, cy0 + Acells);
200 for (
int cx = cxMin; cx <= cxMax; cx++)
201 for (
int cy = cyMin; cy <= cyMax; cy++)
202 lik += 1 - getCell_nocheck(cx, cy);
204 int nCells = (cxMax - cxMin + 1) * (cyMax - cyMin + 1);
210 element.second = pointGlobal;
211 likelihoodOutputs.OWA_pairList.push_back(element);
217 likelihoodOutputs.OWA_pairList.begin(),
218 likelihoodOutputs.OWA_pairList.end());
221 size_t M = likelihoodOptions.OWA_weights.
size();
222 ASSERT_(likelihoodOutputs.OWA_pairList.size() >= M);
224 likelihoodOutputs.OWA_pairList.resize(M);
225 likelihoodOutputs.OWA_individualLikValues.resize(M);
227 for (
size_t k = 0; k < M; k++)
229 likelihoodOutputs.OWA_individualLikValues[k] =
230 likelihoodOutputs.OWA_pairList[k].first;
231 likResult += likelihoodOptions.OWA_weights[k] *
232 likelihoodOutputs.OWA_individualLikValues[k];
235 return log(likResult);
241 double COccupancyGridMap2D::computeObservationLikelihood_CellsDifference(
256 if (!o.isPlanarScan(insertionOptions.horizontalTolerance))
261 takenFrom.
x() - 10, takenFrom.
x() + 10, takenFrom.
y() - 10,
262 takenFrom.
y() + 10, resolution);
267 compareGrid.insertionOptions.maxDistanceInsertion =
268 insertionOptions.maxDistanceInsertion;
269 compareGrid.insertionOptions.maxOccupancyUpdateCertainty = 0.95f;
270 o.insertObservationInto(&compareGrid, &robotPose);
273 Ax =
round((x_min - compareGrid.x_min) / resolution);
274 Ay =
round((y_min - compareGrid.y_min) / resolution);
276 int nCellsCompared = 0;
277 float cellsDifference = 0;
280 int x1 = min(compareGrid.size_x, size_x + Ax);
281 int y1 = min(compareGrid.size_y, size_y + Ay);
283 for (
int x = x0; x < x1; x += 1)
285 for (
int y = y0; y < y1; y += 1)
287 float xx = compareGrid.idx2x(x);
288 float yy = compareGrid.idx2y(y);
290 float c1 = getPos(xx, yy);
291 float c2 = compareGrid.getCell(x, y);
292 if (c2 < 0.45f || c2 > 0.55f)
295 if ((c1 > 0.5 && c2 < 0.5) || (c1 < 0.5 && c2 > 0.5))
300 ret = 1 - cellsDifference / (nCellsCompared);
308 double COccupancyGridMap2D::computeObservationLikelihood_MI(
317 updateInfoChangeOnly.enabled =
true;
318 insertionOptions.maxDistanceInsertion *=
319 likelihoodOptions.MI_ratio_max_distance;
322 updateInfoChangeOnly.cellsUpdated = 0;
323 updateInfoChangeOnly.I_change = 0;
324 updateInfoChangeOnly.laserRaysSkip = likelihoodOptions.MI_skip_rays;
328 insertObservation(obs, &poseRobot);
331 double newObservation_mean_I;
332 if (updateInfoChangeOnly.cellsUpdated)
333 newObservation_mean_I =
334 updateInfoChangeOnly.I_change / updateInfoChangeOnly.cellsUpdated;
336 newObservation_mean_I = 0;
339 updateInfoChangeOnly.enabled =
false;
340 insertionOptions.maxDistanceInsertion /=
341 likelihoodOptions.MI_ratio_max_distance;
344 pow(newObservation_mean_I,
345 static_cast<double>(likelihoodOptions.MI_exponent));
352 double COccupancyGridMap2D::computeObservationLikelihood_rayTracing(
368 if (!o.isPlanarScan(insertionOptions.horizontalTolerance))
373 int decimation = likelihoodOptions.rayTracing_decimation;
390 double stdLaser = likelihoodOptions.rayTracing_stdHit;
391 double stdSqrt2 = sqrt(2.0f) * stdLaser;
399 for (
int j = 0; j < nRays; j += decimation)
403 r_obs = o.getScanRange(j);
406 if (o.getScanRangeValidity(j))
412 min((
float)fabs(r_sim - r_obs), 2.0f) / stdSqrt2));
413 ret += log(likelihood);
426 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_Thrun(
443 if (!o.isPlanarScan(insertionOptions.horizontalTolerance))
return -10;
453 ret = computeLikelihoodField_Thrun(
469 ret = computeLikelihoodField_Thrun(&pts, &takenFrom);
480 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_II(
497 if (!o.isPlanarScan(insertionOptions.horizontalTolerance))
504 ret = computeLikelihoodField_II(
517 double COccupancyGridMap2D::computeLikelihoodField_Thrun(
523 size_t N = pm->
size();
525 likelihoodOptions.LF_maxCorrsDistance /
528 bool Product_T_OrSum_F = !likelihoodOptions.LF_alternateAverageMethod;
538 float stdHit = likelihoodOptions.LF_stdHit;
539 float zHit = likelihoodOptions.LF_zHit;
540 float zRandom = likelihoodOptions.LF_zRandom;
541 float zRandomMaxRange = likelihoodOptions.LF_maxRange;
542 float zRandomTerm = zRandom / zRandomMaxRange;
543 float Q = -0.5f /
square(stdHit);
546 unsigned int size_x_1 = size_x - 1;
547 unsigned int size_y_1 = size_y - 1;
549 #define LIK_LF_CACHE_INVALID (66) 553 double maxCorrDist_sq =
square(likelihoodOptions.LF_maxCorrsDistance);
554 double minimumLik = zRandomTerm + zHit * exp(Q * maxCorrDist_sq);
557 if (likelihoodOptions.enableLikelihoodCache)
560 if (m_likelihoodCacheOutDated)
565 precomputedLikelihood.clear();
567 m_likelihoodCacheOutDated =
false;
571 cellType thresholdCellValue = p2l(0.5f);
572 int decimation = likelihoodOptions.LF_decimation;
574 const double _resolution = this->resolution;
575 const double constDist2DiscrUnits = 100 / (_resolution * _resolution);
576 const double constDist2DiscrUnits_INV = 1.0 / constDist2DiscrUnits;
578 if (N < 10) decimation = 1;
583 for (
size_t j = 0; j < N; j += decimation)
591 ::sincos(relativePose->
phi(), &ssin, &ccos);
593 ccos = cos(relativePose->
phi());
594 ssin = sin(relativePose->
phi());
597 relativePose->
x() + pointLocal.
x * ccos - pointLocal.
y * ssin;
599 relativePose->
y() + pointLocal.
x * ssin + pointLocal.
y * ccos;
607 int cx = x2idx(pointGlobal.
x);
608 int cy = y2idx(pointGlobal.
y);
612 if (static_cast<unsigned>(cx) >= size_x_1 ||
613 static_cast<unsigned>(cy) >= size_y_1)
617 thisLik = minimumLik;
622 if (likelihoodOptions.enableLikelihoodCache)
624 thisLik = precomputedLikelihood[cx + cy * size_x];
627 if (!likelihoodOptions.enableLikelihoodCache ||
634 int xx1 = max(0, cx - K);
635 int xx2 = min(size_x_1, (
unsigned)(cx + K));
636 int yy1 = max(0, cy - K);
637 int yy2 = min(size_y_1, (
unsigned)(cy + K));
640 float occupiedMinDist;
643 &map[xx1 + yy1 * size_x];
644 unsigned incrAfterRow = size_x - ((xx2 - xx1) + 1);
646 signed int Ax0 = 10 * (xx1 - cx);
647 signed int Ay = 10 * (yy1 - cy);
649 unsigned int occupiedMinDistInt =
650 mrpt::round(maxCorrDist_sq * constDist2DiscrUnits);
652 for (
int yy = yy1; yy <= yy2; yy++)
655 square((
unsigned int)(Ay));
657 signed short Ax = Ax0;
660 for (
int xx = xx1; xx <= xx2; xx++)
662 if ((cell = *mapPtr++) < thresholdCellValue)
665 square((
unsigned int)(Ax)) + Ay2;
671 mapPtr += incrAfterRow;
676 occupiedMinDistInt * constDist2DiscrUnits_INV;
679 if (likelihoodOptions.LF_useSquareDist)
680 occupiedMinDist *= occupiedMinDist;
682 thisLik = zRandomTerm + zHit * exp(Q * occupiedMinDist);
684 if (likelihoodOptions.enableLikelihoodCache)
686 precomputedLikelihood[cx + cy * size_x] = thisLik;
691 if (Product_T_OrSum_F)
702 if (!Product_T_OrSum_F) ret = log(ret / M);
712 double COccupancyGridMap2D::computeLikelihoodField_II(
718 size_t N = pm->
size();
720 if (!N)
return 1e-100;
730 float zRandomTerm = 1.0f / likelihoodOptions.LF_maxRange;
731 float Q = -0.5f /
square(likelihoodOptions.LF_stdHit);
739 int maxRangeInCells =
740 (int)ceil(likelihoodOptions.LF_maxCorrsDistance / resolution);
746 for (j = 0; j < N; j += likelihoodOptions.LF_decimation)
753 pointGlobal = *relativePose + pointLocal;
762 cx0 = x2idx(pointGlobal.
x);
763 cy0 = y2idx(pointGlobal.
y);
767 cx_min = max(cx0 - maxRangeInCells, 0);
768 cx_max = min(cx0 + maxRangeInCells, static_cast<int>(size_x));
769 cy_min = max(cy0 - maxRangeInCells, 0);
770 cy_max = min(cy0 + maxRangeInCells, static_cast<int>(size_y));
777 for (cx = cx_min; cx <= cx_max; cx++)
779 for (cy = cy_min; cy <= cy_max; cy++)
781 float P_free = getCell(cx, cy);
783 exp(Q * (
square(idx2x(cx) - pointGlobal.
x) +
784 square(idx2y(cy) - pointGlobal.
y)));
786 lik += P_free * zRandomTerm + (1 - P_free) * termDist;
791 if (likelihoodOptions.LF_alternateAverageMethod)
794 ret += log(lik / ((cy_max - cy_min + 1) * (cx_max - cx_min + 1)));
799 if (likelihoodOptions.LF_alternateAverageMethod && nCells > 0)
800 ret = log(ret / nCells);
812 COccupancyGridMap2D::TLikelihoodOptions::TLikelihoodOptions()
813 : OWA_weights(100, 1 / 100.0f)
825 iniFile.read_enum(section,
"likelihoodMethod", likelihoodMethod);
827 enableLikelihoodCache =
iniFile.read_bool(
828 section,
"enableLikelihoodCache", enableLikelihoodCache);
830 LF_stdHit =
iniFile.read_float(section,
"LF_stdHit", LF_stdHit);
831 LF_zHit =
iniFile.read_float(section,
"LF_zHit", LF_zHit);
832 LF_zRandom =
iniFile.read_float(section,
"LF_zRandom", LF_zRandom);
833 LF_maxRange =
iniFile.read_float(section,
"LF_maxRange", LF_maxRange);
834 LF_decimation =
iniFile.read_int(section,
"LF_decimation", LF_decimation);
835 LF_maxCorrsDistance =
836 iniFile.read_float(section,
"LF_maxCorrsDistance", LF_maxCorrsDistance);
838 iniFile.read_bool(section,
"LF_useSquareDist", LF_useSquareDist);
839 LF_alternateAverageMethod =
iniFile.read_bool(
840 section,
"LF_alternateAverageMethod", LF_alternateAverageMethod);
842 MI_exponent =
iniFile.read_float(section,
"MI_exponent", MI_exponent);
843 MI_skip_rays =
iniFile.read_int(section,
"MI_skip_rays", MI_skip_rays);
844 MI_ratio_max_distance =
iniFile.read_float(
845 section,
"MI_ratio_max_distance", MI_ratio_max_distance);
847 rayTracing_useDistanceFilter =
iniFile.read_bool(
848 section,
"rayTracing_useDistanceFilter", rayTracing_useDistanceFilter);
850 iniFile.read_float(section,
"rayTracing_stdHit", rayTracing_stdHit);
852 consensus_takeEachRange =
iniFile.read_int(
853 section,
"consensus_takeEachRange", consensus_takeEachRange);
854 consensus_pow =
iniFile.read_float(section,
"consensus_pow", consensus_pow);
856 iniFile.read_vector(section,
"OWA_weights", OWA_weights, OWA_weights);
863 std::ostream&
out)
const 865 out <<
"\n----------- [COccupancyGridMap2D::TLikelihoodOptions] " 869 out <<
"likelihoodMethod = ";
870 switch (likelihoodMethod)
873 out <<
"lmMeanInformation";
876 out <<
"lmRayTracing";
879 out <<
"lmConsensus";
882 out <<
"lmCellsDifference";
885 out <<
"lmLikelihoodField_Thrun";
888 out <<
"lmLikelihoodField_II";
891 out <<
"lmConsensusOWA";
900 "enableLikelihoodCache = %c\n",
901 enableLikelihoodCache ?
'Y' :
'N');
904 "LF_stdHit = %f\n", LF_stdHit);
906 "LF_zHit = %f\n", LF_zHit);
908 "LF_zRandom = %f\n", LF_zRandom);
910 "LF_maxRange = %f\n", LF_maxRange);
912 "LF_decimation = %u\n", LF_decimation);
914 "LF_maxCorrsDistance = %f\n", LF_maxCorrsDistance);
916 "LF_useSquareDist = %c\n",
917 LF_useSquareDist ?
'Y' :
'N');
919 "LF_alternateAverageMethod = %c\n",
920 LF_alternateAverageMethod ?
'Y' :
'N');
922 "MI_exponent = %f\n", MI_exponent);
924 "MI_skip_rays = %u\n", MI_skip_rays);
926 "MI_ratio_max_distance = %f\n",
927 MI_ratio_max_distance);
929 "rayTracing_useDistanceFilter = %c\n",
930 rayTracing_useDistanceFilter ?
'Y' :
'N');
932 "rayTracing_decimation = %u\n",
933 rayTracing_decimation);
935 "rayTracing_stdHit = %f\n", rayTracing_stdHit);
937 "consensus_takeEachRange = %u\n",
938 consensus_takeEachRange);
940 "consensus_pow = %.02f\n", consensus_pow);
941 out <<
"OWA_weights = [";
942 for (
size_t i = 0; i < OWA_weights.size(); i++)
944 if (i < 3 || i > (OWA_weights.size() - 3))
946 else if (i == 3 && OWA_weights.size() > 6)
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...
void getPoint(size_t index, float &x, float &y, float &z) const
Access to a given point from map, as a 2D point.
bool isPlanarMap
If set to true, only HORIZONTAL (in the XY plane) measurements will be inserted in the map (Default v...
Declares a class derived from "CObservation" that encapsules a single range measurement, and associated parameters.
std::string std::string format(std::string_view fmt, ARGS &&... args)
const POINTSMAP * buildAuxPointsMap(const void *options=nullptr) const
Returns a cached points map representing this laser scan, building it upon the first call...
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans. ...
TInsertionOptions insertionOptions
With this struct options are provided to the observation insertion process.
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...
size_t getScanSize() const
Get number of scan rays.
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 maxRange
The maximum range allowed by the device, in meters (e.g.
#define ASSERT_(f)
Defines an assertion mechanism.
With this struct options are provided to the observation insertion process.
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors...
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.
double phi() const
Get the phi angle of the 2D pose (in radians)
std::pair< double, mrpt::math::TPoint2D > TPairLikelihoodIndex
Auxiliary private class.
#define LIK_LF_CACHE_INVALID
This namespace contains representation of robot actions and observations.
string iniFile(myDataDir+string("benchmark-options.ini"))
#define IS_CLASS(obj, class_name)
True if the given reference to object (derived from mrpt::rtti::CObject) is of the given class...
double x() const
Common members of all points & poses classes.
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini" file.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
return_t square(const num_t x)
Inline function for the square of a number.
A class for storing an occupancy grid map.
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...
constexpr std::size_t size() const
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
mrpt::vision::TStereoCalibResults out
Declares a class that represents any robot's observation.
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 float & getScanRange(const size_t i) const
The range values of the scan, in meters.
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).
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
float mapAltitude
The altitude (z-axis) of 2D scans (within a 0.01m tolerance) for they to be inserted in this map! ...
OccGridCellTraits::cellType cellType
The type of the map cells:
TInsertionOptions insertionOptions
The options used when inserting observations in the map.
size_t size() const
Save the point cloud as a PCL PCD file, in either ASCII or binary format.
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
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.
bool insertObservation(const mrpt::obs::CObservation &obs, const mrpt::poses::CPose3D *robotPose=nullptr)
Insert the observation information into this map.
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...
int round(const T value)
Returns the closer integer (int) to x.