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