QualityEvaluator_RangeImageSimilarity.cpp
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  * A repertory of multi primitive-to-primitive (MP2P) ICP algorithms in C++
3  * Copyright (C) 2018-2024 Jose Luis Blanco, University of Almeria
4  * See LICENSE for license information.
5  * ------------------------------------------------------------------------- */
14 #include <mrpt/gui/CDisplayWindow.h>
15 #include <mrpt/img/TPixelCoord.h>
16 #include <mrpt/io/vector_loadsave.h>
17 
19 
20 using namespace mp2p_icp;
21 
22 void QualityEvaluator_RangeImageSimilarity::initialize(const mrpt::containers::yaml& params)
23 {
24  rangeCamera.ncols = params["ncols"].as<uint32_t>();
25  rangeCamera.nrows = params["nrows"].as<uint32_t>();
26 
27  rangeCamera.cx(params["cx"].as<double>());
28  rangeCamera.cy(params["cy"].as<double>());
29  rangeCamera.fx(params["fx"].as<double>());
30  rangeCamera.fy(params["fy"].as<double>());
31 
32  MCP_LOAD_OPT(params, sigma);
33  MCP_LOAD_OPT(params, penalty_not_visible);
34 
35  MCP_LOAD_OPT(params, debug_show_all_in_window);
36  MCP_LOAD_OPT(params, debug_save_all_matrices);
37 }
38 
40  const metric_map_t& pcGlobal, const metric_map_t& pcLocal,
41  const mrpt::poses::CPose3D& localPose, [[maybe_unused]] const Pairings& pairingsFromICP) const
42 {
43  // See Figure 3 of IROS2017 paper:
44  // "Analyzing the Quality of Matched 3D Point Clouds of Objects"
45  // Igor Bogoslavskyi, Cyrill Stachniss
46 
47  const auto& p1 = *pcGlobal.point_layer(metric_map_t::PT_LAYER_RAW);
48  const auto& p2 = *pcLocal.point_layer(metric_map_t::PT_LAYER_RAW);
49 
50  const auto I11 = projectPoints(p1);
51  const auto I12 = projectPoints(p1, localPose);
52  const auto I22 = projectPoints(p2);
53  const auto I21 = projectPoints(p2, -localPose);
54 
55  auto s1 = scores(I11, I21);
56  auto s2 = scores(I12, I22);
57 
58  const size_t nScores = s1.size() + s2.size();
59 
60  double sum = .0;
61  for (double v : s1) sum += v;
62  for (double v : s2) sum += v;
63 
64  const double finalScore = nScores > 0 ? sum / nScores : .0;
65 
66  // ----- Debug ----------
68  {
69  mrpt::gui::CDisplayWindow win_11("I11", 400, 300);
70  mrpt::gui::CDisplayWindow win_12("I12", 400, 300);
71  mrpt::gui::CDisplayWindow win_21("I21", 400, 300);
72  mrpt::gui::CDisplayWindow win_22("I22", 400, 300);
73  win_11.setPos(5, 5);
74  win_12.setPos(410 + 5, 5);
75  win_21.setPos(5, 310 + 5);
76  win_22.setPos(410 + 5, 310 + 5);
77  mrpt::img::CImage im11, im12, im21, im22;
78  im11.setFromMatrix(I11, false);
79  win_11.showImage(im11);
80  im12.setFromMatrix(I12, false);
81  win_12.showImage(im12);
82  im21.setFromMatrix(I21, false);
83  win_21.showImage(im21);
84  im22.setFromMatrix(I22, false);
85  win_22.showImage(im22);
86  win_11.waitForKey();
87  }
89  {
90  static std::atomic_int iv = 0;
91  const int i = iv++;
92  I11.saveToTextFile(mrpt::format("I11_%05i.txt", i));
93  I22.saveToTextFile(mrpt::format("I22_%05i.txt", i));
94  I12.saveToTextFile(mrpt::format("I12_%05i.txt", i));
95  I21.saveToTextFile(mrpt::format("I21_%05i.txt", i));
96 
97  mrpt::io::vectorToTextFile(s1, mrpt::format("I1_scores_%05i.txt", i));
98  mrpt::io::vectorToTextFile(s2, mrpt::format("I2_scores_%05i.txt", i));
99  }
100 
101  Result r;
102  r.quality = finalScore;
103  return r;
104 }
105 
106 // Adapted from mrpt::vision::pinhole::projectPoint_with_distortion()
107 // 3-claused BSD
108 static void projectPoint(
109  const mrpt::math::TPoint3D& P, const mrpt::img::TCamera& params, double& pixel_x,
110  double& pixel_y)
111 {
112  /* Pinhole model.
113  *
114  * Point reference Pixel/camera reference
115  *
116  * +Z ^ / +Z
117  * | / /
118  * | / +X /
119  * +Y |/ /
120  * <-----+ +-----------> +X
121  * |
122  * |
123  * V +Y
124  *
125  */
126  const double x = -P.y / P.x;
127  const double y = -P.z / P.x;
128 
129  pixel_x = params.cx() + params.fx() * x;
130  pixel_y = params.cy() + params.fy() * y;
131 }
132 
134  const mrpt::maps::CPointsMap& pts,
135  const std::optional<mrpt::poses::CPose3D>& relativePose) const
136 {
137  const auto& rc = rangeCamera;
138 
139  mrpt::math::CMatrixDouble I(rc.nrows, rc.ncols);
140  I.setZero(); // range=0 means "invalid"
141 
142  const auto& xs = pts.getPointsBufferRef_x();
143  const auto& ys = pts.getPointsBufferRef_y();
144  const auto& zs = pts.getPointsBufferRef_z();
145 
146  const auto nPoints = xs.size();
147  // size_t nValidPoints = 0;
148  for (size_t i = 0; i < nPoints; i++)
149  {
150  mrpt::math::TPoint3D p(xs[i], ys[i], zs[i]);
151  if (relativePose) p = relativePose->composePoint(p);
152 
153  double px, py;
154  projectPoint(p, rc, px, py);
155  int pixx = static_cast<int>(px);
156  int pixy = static_cast<int>(py);
157 
158  // Out of range
159  if (pixx < 0 || pixy < 0 || pixx >= int(rc.ncols) || pixy >= int(rc.nrows)) continue;
160 
161  const double newRange = p.norm();
162  double& storedRange = I(pixy, pixx);
163 
164  if (storedRange == 0 || newRange < storedRange) storedRange = newRange;
165 
166  // nValidPoints++;
167  }
168 
169  // std::cout << "Points: " << nValidPoints << "/" << nPoints << "\n";
170 
171  return I;
172 }
173 
174 static double phi(double x) { return std::erf(x / std::sqrt(2)); }
175 static double errorForMismatch(const double x) { return 1.0 - phi(x); }
176 static double errorForMismatch(const double DeltaRange, const double sigma)
177 {
178  const double x = std::abs(DeltaRange / sigma);
179  return errorForMismatch(x);
180 }
181 
183  const mrpt::math::CMatrixDouble& m1, const mrpt::math::CMatrixDouble& m2) const
184 {
185  ASSERT_EQUAL_(m1.rows(), m2.rows());
186  ASSERT_EQUAL_(m1.cols(), m2.cols());
187 
188  std::vector<double> scores;
189  scores.reserve(m1.rows() * m1.cols() / 4);
190 
191  const size_t N = m1.rows() * m1.cols();
192  for (size_t i = 0; i < N; i++)
193  {
194  const double r1 = m1.data()[i];
195  const double r2 = m2.data()[i];
196 
197  if (r1 == 0 && r2 == 0) continue;
198 
199  double val;
200  if (r1 == 0 || r2 == 0)
201  {
202  // Maximum error:
204  }
205  else
206  {
207  // Maximum error:
208  val = errorForMismatch(r1 - r2, sigma);
209  }
210  // printf("r1=%f r2=%f -> val=%f\n", r1, r2, val);
211  scores.push_back(val);
212  }
213 
214  return scores;
215 }
mp2p_icp::QualityEvaluator_RangeImageSimilarity::evaluate
Result evaluate(const metric_map_t &pcGlobal, const metric_map_t &pcLocal, const mrpt::poses::CPose3D &localPose, const Pairings &pairingsFromICP) const override
Definition: QualityEvaluator_RangeImageSimilarity.cpp:39
mp2p_icp
Definition: covariance.h:17
mp2p_icp::QualityEvaluator_RangeImageSimilarity::initialize
void initialize(const mrpt::containers::yaml &params) override
Definition: QualityEvaluator_RangeImageSimilarity.cpp:22
mp2p_icp::QualityEvaluator::Result
Definition: QualityEvaluator.h:39
mp2p_icp::Pairings
Definition: Pairings.h:76
test.x
x
Definition: test.py:4
mp2p_icp::QualityEvaluator_RangeImageSimilarity::sigma
double sigma
Definition: QualityEvaluator_RangeImageSimilarity.h:66
mp2p_icp::metric_map_t::PT_LAYER_RAW
constexpr static const char * PT_LAYER_RAW
Definition: metricmap.h:64
mp2p_icp::QualityEvaluator_RangeImageSimilarity::projectPoints
mrpt::math::CMatrixDouble projectPoints(const mrpt::maps::CPointsMap &pts, const std::optional< mrpt::poses::CPose3D > &relativePose=std::nullopt) const
Definition: QualityEvaluator_RangeImageSimilarity.cpp:133
mp2p_icp::QualityEvaluator_RangeImageSimilarity::debug_show_all_in_window
bool debug_show_all_in_window
Definition: QualityEvaluator_RangeImageSimilarity.h:71
IMPLEMENTS_MRPT_OBJECT
IMPLEMENTS_MRPT_OBJECT(FilterDecimateVoxelsQuadratic, mp2p_icp_filters::FilterBase, mp2p_icp_filters) using namespace mp2p_icp_filters
mp2p_icp::QualityEvaluator_RangeImageSimilarity::rangeCamera
mrpt::img::TCamera rangeCamera
Definition: QualityEvaluator_RangeImageSimilarity.h:64
phi
static double phi(double x)
Definition: QualityEvaluator_RangeImageSimilarity.cpp:174
mp2p_icp::QualityEvaluator_RangeImageSimilarity::debug_save_all_matrices
bool debug_save_all_matrices
Definition: QualityEvaluator_RangeImageSimilarity.h:72
mp2p_icp::QualityEvaluator::Result::quality
double quality
The resulting quality measure, in the range [0,1].
Definition: QualityEvaluator.h:42
projectPoint
static void projectPoint(const mrpt::math::TPoint3D &P, const mrpt::img::TCamera &params, double &pixel_x, double &pixel_y)
Definition: QualityEvaluator_RangeImageSimilarity.cpp:108
mp2p_icp::metric_map_t::point_layer
mrpt::maps::CPointsMap::Ptr point_layer(const layer_name_t &name) const
Definition: metricmap.cpp:607
errorForMismatch
static double errorForMismatch(const double x)
Definition: QualityEvaluator_RangeImageSimilarity.cpp:175
mp2p_icp::QualityEvaluator_RangeImageSimilarity
Definition: QualityEvaluator_RangeImageSimilarity.h:35
PointMatcherSupport::Parametrizable
The superclass of classes that are constructed using generic parameters. This class provides the para...
Definition: Parametrizable.h:98
mp2p_icp::QualityEvaluator_RangeImageSimilarity::penalty_not_visible
double penalty_not_visible
!< Uncertainty of depth ranges [meters]
Definition: QualityEvaluator_RangeImageSimilarity.h:69
mp2p_icp::metric_map_t
Generic container of pointcloud(s), extracted features and other maps.
Definition: metricmap.h:55
mp2p_icp::QualityEvaluator_RangeImageSimilarity::scores
std::vector< double > scores(const mrpt::math::CMatrixDouble &m1, const mrpt::math::CMatrixDouble &m2) const
Definition: QualityEvaluator_RangeImageSimilarity.cpp:182
mp2p_icp::QualityEvaluator
Definition: QualityEvaluator.h:28
QualityEvaluator_RangeImageSimilarity.h
Matching quality evaluator from paper [Bogoslavskyi,IROS2017].


mp2p_icp
Author(s):
autogenerated on Mon May 26 2025 02:45:50