Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
catchMbtJsonSettings.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Test vpMbGenericTracker JSON parse / save.
32 */
33
39
40#include <visp3/core/vpIoTools.h>
41#include <visp3/mbt/vpMbGenericTracker.h>
42
43#if defined(VISP_HAVE_NLOHMANN_JSON) && defined(VISP_HAVE_CATCH2)
44#include VISP_NLOHMANN_JSON(json.hpp)
45using json = nlohmann::json;
46
47#include <catch_amalgamated.hpp>
48
49#ifdef ENABLE_VISP_NAMESPACE
50using namespace VISP_NAMESPACE_NAME;
51#endif
52
53vpMbGenericTracker baseTrackerConstructor()
54{
55 const std::vector<std::string> names = { "C1", "C2" };
56 std::vector<int> featureTypes;
57#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
59#else
60 featureTypes.push_back(vpMbGenericTracker::EDGE_TRACKER);
61#endif
64 cam1.initPersProjWithoutDistortion(300, 300, 200, 200);
66 cam2.initPersProjWithoutDistortion(500, 400, 250, 250);
67
68 vpMbGenericTracker t = vpMbGenericTracker(names, featureTypes);
69
70 std::map<std::string, vpCameraParameters> cams;
71 cams[names[0]] = cam1;
72 cams[names[1]] = cam2;
73 t.setCameraParameters(cams);
74
75 t.setLod(false);
76
77 t.setAngleAppear(vpMath::rad(60));
78 t.setAngleDisappear(vpMath::rad(90));
79 vpMe me;
80 me.setSampleStep(2.0);
81 me.setMaskSize(7);
82 me.setMaskNumber(160);
83 me.setRange(8);
85 me.setThreshold(20);
86 me.setMu1(0.2);
87 me.setMu2(0.3);
88 me.setSampleStep(4);
89 t.setMovingEdge(me);
90 return t;
91}
92
93template<typename T, typename C>
94void checkProperties(const T &t1, const T &t2, C fn, const std::string &message)
95{
96 THEN(message)
97 {
98 REQUIRE((t1.*fn)() == (t2.*fn)());
99 }
100}
101
102template<typename T, typename C, typename... Fns>
103void checkProperties(const T &t1, const T &t2, C fn, const std::string &message, Fns... fns)
104{
105 checkProperties(t1, t2, fn, message);
106 checkProperties(t1, t2, fns...);
107}
108
109void compareNamesAndTypes(const vpMbGenericTracker &t1, const vpMbGenericTracker &t2)
110{
111 REQUIRE(t1.getCameraNames() == t2.getCameraNames());
112 REQUIRE(t1.getCameraTrackerTypes() == t2.getCameraTrackerTypes());
113}
114
115void compareCameraParameters(const vpMbGenericTracker &t1, const vpMbGenericTracker &t2)
116{
117 std::map<std::string, vpCameraParameters> c1, c2;
118 t1.getCameraParameters(c1);
119 t2.getCameraParameters(c2);
120 REQUIRE(c1 == c2);
121}
122
123json loadJson(const std::string &path)
124{
125 std::ifstream json_file(path);
126 if (!json_file.good()) {
127 throw vpException(vpException::ioError, "Could not open JSON settings file");
128 }
129 json j = json::parse(json_file);
130 json_file.close();
131 return j;
132}
133
134void saveJson(const json &j, const std::string &path)
135{
136 std::ofstream json_file(path);
137 if (!json_file.good()) {
138 throw vpException(vpException::ioError, "Could not open JSON settings file to write modifications");
139 }
140 json_file << j.dump();
141 json_file.close();
142}
143
144SCENARIO("MBT JSON Serialization", "[json]")
145{
146 // setup test dir
147 // Get the user login name
148
149 std::string tmp_dir = vpIoTools::makeTempDirectory(vpIoTools::getTempPath() + vpIoTools::path("/") + "visp_test_json_parsing_mbt");
150
151 GIVEN("A generic tracker with two cameras, one with edge and KLT features, the other with depth features")
152 {
153 vpMbGenericTracker t1 = baseTrackerConstructor();
154 WHEN("Saving to a JSON settings file")
155 {
156 const std::string jsonPath = tmp_dir + "/" + "tracker_save.json";
157
158 const auto modifyJson = [&jsonPath](std::function<void(json &)> modify) -> void {
159 json j = loadJson(jsonPath);
160 modify(j);
161 saveJson(j, jsonPath);
162 };
163
164 REQUIRE_NOTHROW(t1.saveConfigFile(jsonPath));
165 THEN("Reloading this tracker has the same basic properties")
166 {
168 REQUIRE_NOTHROW(t2.loadConfigFile(jsonPath));
169 compareNamesAndTypes(t1, t2);
170 compareCameraParameters(t1, t2);
171 }
172
173 THEN("Reloading this tracker has the same basic properties")
174 {
176 REQUIRE_NOTHROW(t2.loadConfigFile(jsonPath));
177 checkProperties(t1, t2,
178 &vpMbGenericTracker::getAngleAppear, "Angle appear should be the same",
179 &vpMbGenericTracker::getAngleDisappear, "Angle appear should be the same"
180 );
181 }
182
183 THEN("Reloaded edge tracker parameters should be the same")
184 {
185 std::map<std::string, vpMe> oldvpMe, newvpMe;
186 t1.getMovingEdge(oldvpMe);
188 t2.loadConfigFile(jsonPath);
189 t2.getMovingEdge(newvpMe);
190 for (const auto &it : oldvpMe) {
191 vpMe o = it.second;
192 vpMe n;
193 REQUIRE_NOTHROW(n = newvpMe[it.first]);
194 checkProperties(o, n,
195 &vpMe::getAngleStep, "Angle step should be equal",
196 &vpMe::getMaskNumber, "Mask number should be equal",
197 &vpMe::getMaskSign, "Mask sign should be equal",
198 &vpMe::getMinSampleStep, "Min sample step should be equal",
199 &vpMe::getSampleStep, "Min sample step should be equal",
200
201 &vpMe::getMu1, "Mu 1 should be equal",
202 &vpMe::getMu2, "Mu 2 should be equal",
203 &vpMe::getNbTotalSample, "Nb total sample should be equal",
204 &vpMe::getPointsToTrack, "Number of points to track should be equal",
205 &vpMe::getRange, "Range should be equal",
206 &vpMe::getStrip, "Strip should be equal"
207 );
208 }
209 }
210
211#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV)
212 THEN("Reloaded KLT tracker parameters should be the same")
213 {
214 std::map<std::string, vpKltOpencv> oldvpKlt, newvpKlt;
215 t1.getKltOpencv(oldvpKlt);
217 t2.loadConfigFile(jsonPath);
218 t2.getKltOpencv(newvpKlt);
219 for (const auto &it : oldvpKlt) {
220 vpKltOpencv o = it.second;
221 vpKltOpencv n;
222 REQUIRE_NOTHROW(n = newvpKlt[it.first]);
223 checkProperties(o, n,
224 &vpKltOpencv::getBlockSize, "Block size should be equal",
225 &vpKltOpencv::getHarrisFreeParameter, "Harris parameter should be equal",
226 &vpKltOpencv::getMaxFeatures, "Max number of features should be equal",
227 &vpKltOpencv::getMinDistance, "Minimum distance should be equal",
228 &vpKltOpencv::getPyramidLevels, "Pyramid levels should be equal",
229 &vpKltOpencv::getQuality, "Quality should be equal",
230 &vpKltOpencv::getWindowSize, "Window size should be equal"
231 );
232 }
233 }
234#endif
235
236 THEN("Clipping properties should be the same")
237 {
238 vpMbGenericTracker t2 = baseTrackerConstructor();
242 t2.loadConfigFile(jsonPath);
243 std::map<std::string, unsigned int> oldFlags, newFlags;
244 t1.getClipping(oldFlags);
245 t2.getClipping(newFlags);
246 for (const auto &it : oldFlags) {
247 unsigned int o = it.second;
248 unsigned int n = 0;
249 REQUIRE_NOTHROW(n = newFlags[it.first]);
250 THEN("Clipping flags for camera " + it.first + " should be the same")
251 {
252 REQUIRE(o == n);
253 }
254 }
255 checkProperties(t1, t2,
256 &vpMbGenericTracker::getNearClippingDistance, "Near clipping distance should be the same",
257 &vpMbGenericTracker::getFarClippingDistance, "Far clipping distance should be the same"
258 );
259 }
260
261 THEN("VVS properties should be the same")
262 {
263 vpMbGenericTracker t2 = baseTrackerConstructor();
264 t2.setMaxIter(4096);
265 t2.setLambda(5.0);
266 t2.setInitialMu(5.0);
267
268 t2.loadConfigFile(jsonPath);
269
270 checkProperties(t1, t2,
271 &vpMbGenericTracker::getMaxIter, "VVS m iterations be the same",
272 &vpMbGenericTracker::getLambda, "VVS lambda should be the same",
273 &vpMbGenericTracker::getInitialMu, "VVS initial mu be the same"
274 );
275 }
276
277 WHEN("Modifying JSON file/Using a custom JSON file")
278 {
279 THEN("Removing version from file generates an error on load")
280 {
281 modifyJson([](json &j) -> void {
282 j.erase("version");
283 });
284 REQUIRE_THROWS(t1.loadConfigFile(jsonPath));
285 }
286
287 THEN("Using an unsupported version generates an error on load")
288 {
289 modifyJson([](json &j) -> void {
290 j["version"] = "0.0.0";
291 });
292 REQUIRE_THROWS(t1.loadConfigFile(jsonPath));
293 }
294
295 THEN("Using an undefined reference camera generates an error")
296 {
297 modifyJson([](json &j) -> void {
298 j["referenceCameraName"] = "C3";
299 });
300 REQUIRE_THROWS(t1.loadConfigFile(jsonPath));
301 }
302
303 THEN("Not defining a transformation matrix for the reference camera is valid")
304 {
305 modifyJson([&t1](json &j) -> void {
306 j["trackers"][t1.getReferenceCameraName()].erase("camTref");
307 });
308 REQUIRE_NOTHROW(t1.loadConfigFile(jsonPath));
309 }
310
311 THEN("Not defining a transformation from a non-reference camera to the reference camera generates an error")
312 {
313 modifyJson([&t1](json &j) -> void {
314 std::string otherCamName = t1.getReferenceCameraName() == "C1" ? "C2" : "C1";
315 j["trackers"][otherCamName].erase("camTref");
316 });
317 REQUIRE_THROWS(t1.loadConfigFile(jsonPath));
318 }
319
320 THEN("The full clipping config is optional")
321 {
322 vpMbGenericTracker t2 = baseTrackerConstructor();
323 const double clipping_near = 0.21;
324 const double clipping_far = 5.2;
325 const int clipping = vpPolygon3D::LEFT_CLIPPING;
326 t2.setNearClippingDistance(clipping_near);
327 t2.setFarClippingDistance(clipping_far);
328 t2.setClipping(clipping);
329 modifyJson([&t1](json &j) -> void {
330 for (const auto &c : t1.getCameraNames()) {
331 j["trackers"][c].erase("clipping");
332 }
333 });
334 REQUIRE_NOTHROW(t2.loadConfigFile(jsonPath, false));
335 REQUIRE(t2.getClipping() == clipping);
336 REQUIRE(t2.getNearClippingDistance() == clipping_near);
337 REQUIRE(t2.getFarClippingDistance() == clipping_far);
338 }
339
340 THEN("Each clipping param is optional on its own")
341 {
342 vpMbGenericTracker t2 = baseTrackerConstructor();
343 const double clipping_near = 0.21;
344 const double clipping_far = 5.2;
345 const int clipping = vpPolygon3D::LEFT_CLIPPING;
346 t2.setNearClippingDistance(clipping_near);
347 t2.setFarClippingDistance(clipping_far);
348 t2.setClipping(clipping);
349 THEN("Near clipping is optional")
350 {
351 modifyJson([&t1](json &j) -> void {
352 for (const auto &c : t1.getCameraNames()) {
353 j["trackers"][c]["clipping"].erase("near");
354 }
355 });
356 t2.loadConfigFile(jsonPath);
357 REQUIRE(t2.getNearClippingDistance() == clipping_near);
358 REQUIRE(t2.getFarClippingDistance() == t1.getFarClippingDistance());
359 REQUIRE(t2.getClipping() == t1.getClipping());
360 }
361 THEN("Far clipping is optional")
362 {
363 modifyJson([&t1](json &j) -> void {
364 for (const auto &c : t1.getCameraNames()) {
365 j["trackers"][c]["clipping"].erase("far");
366 }
367 });
368 t2.loadConfigFile(jsonPath);
369 REQUIRE(t2.getNearClippingDistance() == t1.getNearClippingDistance());
370 REQUIRE(t2.getFarClippingDistance() == clipping_far);
371 REQUIRE(t2.getClipping() == t1.getClipping());
372 }
373 THEN("Clipping flags are optional")
374 {
375 modifyJson([&t1](json &j) -> void {
376 for (const auto &c : t1.getCameraNames()) {
377 j["trackers"][c]["clipping"].erase("flags");
378 }
379 });
380 t2.loadConfigFile(jsonPath);
381 REQUIRE(t2.getNearClippingDistance() == t1.getNearClippingDistance());
382 REQUIRE(t2.getFarClippingDistance() == t1.getFarClippingDistance());
383 REQUIRE(t2.getClipping() & clipping);
384 }
385 }
386 }
387 }
388 }
389}
390
391int main(int argc, char *argv[])
392{
393 Catch::Session session;
394 session.applyCommandLine(argc, argv);
395 int numFailed = session.run();
396 return numFailed;
397}
398
399#else
400
401int main()
402{
403 return EXIT_SUCCESS;
404}
405
406#endif
Generic class defining intrinsic camera parameters.
void initPersProjWithoutDistortion(double px, double py, double u0, double v0)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ ioError
I/O error.
Definition vpException.h:67
static std::string path(const std::string &pathname)
static std::string getTempPath()
static std::string makeTempDirectory(const std::string &dirname)
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV. Thus to enable this ...
Definition vpKltOpencv.h:83
double getQuality() const
int getMaxFeatures() const
Get the list of lost feature.
int getWindowSize() const
Get the window size used to refine the corner locations.
double getHarrisFreeParameter() const
Get the free parameter of the Harris detector.
double getMinDistance() const
int getBlockSize() const
Get the size of the averaging block used to track the features.
int getPyramidLevels() const
Get the list of features id.
static double rad(double deg)
Definition vpMath.h:129
Real-time 6D object pose tracking using its CAD model.
virtual void getCameraParameters(vpCameraParameters &camera) const VP_OVERRIDE
virtual std::map< std::string, int > getCameraTrackerTypes() const
virtual std::vector< std::string > getCameraNames() const
virtual void getClipping(unsigned int &clippingFlag1, unsigned int &clippingFlag2) const
virtual void setClipping(const unsigned int &flags) VP_OVERRIDE
virtual vpKltOpencv getKltOpencv() const
virtual vpMe getMovingEdge() const
virtual void setNearClippingDistance(const double &dist) VP_OVERRIDE
virtual void loadConfigFile(const std::string &configFile, bool verbose=true) VP_OVERRIDE
virtual void setFarClippingDistance(const double &dist) VP_OVERRIDE
virtual double getNearClippingDistance() const
virtual void setMaxIter(unsigned int max)
virtual double getInitialMu() const
virtual double getAngleAppear() const
virtual double getAngleDisappear() const
virtual void setInitialMu(double mu)
virtual void setLambda(double gain)
virtual unsigned int getMaxIter() const
virtual double getLambda() const
virtual double getFarClippingDistance() const
Definition vpMe.h:143
int getMaskSign() const
Definition vpMe.h:231
void setMu1(const double &mu_1)
Definition vpMe.h:408
double getMinSampleStep() const
Definition vpMe.h:248
void setRange(const unsigned int &range)
Definition vpMe.h:438
void setLikelihoodThresholdType(const vpLikelihoodThresholdType likelihood_threshold_type)
Definition vpMe.h:531
void setMaskNumber(const unsigned int &mask_number)
Definition vpMe.cpp:555
int getNbTotalSample() const
Definition vpMe.h:269
void setThreshold(const double &threshold)
Definition vpMe.h:489
unsigned int getAngleStep() const
Definition vpMe.h:202
double getMu1() const
Definition vpMe.h:255
unsigned int getMaskNumber() const
Definition vpMe.h:224
int getPointsToTrack() const
Definition vpMe.h:276
int getStrip() const
Definition vpMe.h:297
void setSampleStep(const double &sample_step)
Definition vpMe.h:445
double getMu2() const
Definition vpMe.h:262
void setMaskSize(const unsigned int &mask_size)
Definition vpMe.cpp:563
void setMu2(const double &mu_2)
Definition vpMe.h:415
double getSampleStep() const
Definition vpMe.h:290
unsigned int getRange() const
Definition vpMe.h:283
@ NORMALIZED_THRESHOLD
Definition vpMe.h:154