Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
catchPanda.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 vpCameraParameters JSON parse / save.
32 */
33
39
40#include <visp3/core/vpConfig.h>
41
42#if defined(VISP_HAVE_PANDA3D) && defined(VISP_HAVE_CATCH2)
43#include <visp3/core/vpCameraParameters.h>
44#include <visp3/core/vpIoTools.h>
45#include <visp3/ar/vpPanda3DBaseRenderer.h>
46#include <visp3/ar/vpPanda3DRGBRenderer.h>
47#include <visp3/ar/vpPanda3DFrameworkManager.h>
48#include <visp3/ar/vpPanda3DRendererSet.h>
49#include <visp3/ar/vpPanda3DGeometryRenderer.h>
50#include <catch_amalgamated.hpp>
51
52#ifdef ENABLE_VISP_NAMESPACE
53using namespace VISP_NAMESPACE_NAME;
54#endif
55
56#include <random>
57
58const std::string objCube =
59"o Cube\n"
60"v -0.050000 -0.050000 0.050000\n"
61"v -0.050000 0.050000 0.050000\n"
62"v -0.050000 -0.050000 -0.050000\n"
63"v -0.050000 0.050000 -0.050000\n"
64"v 0.050000 -0.050000 0.050000\n"
65"v 0.050000 0.050000 0.050000\n"
66"v 0.050000 -0.050000 -0.050000\n"
67"v 0.050000 0.050000 -0.050000\n"
68"f 2/4/1 3/8/1 1/1/1\n"
69"f 4/9/2 7/13/2 3/8/2\n"
70"f 8/14/3 5/11/3 7/13/3\n"
71"f 6/12/4 1/2/4 5/11/4\n"
72"f 7/13/5 1/3/5 3/7/5\n"
73"f 4/10/6 6/12/6 8/14/6\n"
74"f 2/4/1 4/9/1 3/8/1\n"
75"f 4/9/2 8/14/2 7/13/2\n"
76"f 8/14/3 6/12/3 5/11/3\n"
77"f 6/12/4 2/5/4 1/2/4\n"
78"f 7/13/5 5/11/5 1/3/5\n"
79"f 4/10/6 2/6/6 6/12/6\n";
80
81
82std::string createObjFile()
83{
84 const std::string tempDir = vpIoTools::makeTempDirectory("visp_test_rbt_obj");
85 const std::string objFile = vpIoTools::createFilePath(tempDir, "cube.obj");
86 std::ofstream f(objFile);
87 std::cout << objFile << std::endl;
88 f << objCube;
89 f.close();
90
91 return objFile;
92}
93
94vpPanda3DRenderParameters defaultRenderParams()
95{
96 vpCameraParameters cam(600, 600, 160, 120);
97 return vpPanda3DRenderParameters(cam, 240, 320, 0.001, 1.0);
98}
99
100bool opt_no_display = false; // If true, disable display or tests requiring display
101
102SCENARIO("Instanciating multiple Panda3D renderers", "[Panda3D]")
103{
104 if (opt_no_display) {
105 std::cout << "Display is disabled for tests, skipping..." << std::endl;
106 }
107 else {
108 GIVEN("A single renderer")
109 {
111 r1.setRenderParameters(defaultRenderParams());
112 r1.initFramework();
113 r1.renderFrame();
115 r1.getRender(depth);
116
117 THEN("Creating another, uncoupled renderer is ok and its destruction does not raise an error")
118 {
120 r2.setRenderParameters(defaultRenderParams());
121 r2.initFramework();
122 r2.renderFrame();
123 }
124 r1.renderFrame();
125
126 r1.getRender(depth);
127 }
128 }
129}
130
131
132SCENARIO("Sequentially instanciating and destroying Panda3D renderers", "[Panda3D]")
133{
134 if (opt_no_display) {
135 std::cout << "Display is disabled for tests, skipping..." << std::endl;
136 }
137 else {
139 r3.setRenderParameters(defaultRenderParams());
140 r3.initFramework();
141 r3.renderFrame();
143 r3.getRender(depth);
144
145 {
147 r1.setRenderParameters(defaultRenderParams());
148 r1.initFramework();
149 r1.renderFrame();
150 r1.getRender(depth);
151 }
152
153 {
155 r2.setRenderParameters(defaultRenderParams());
156 r2.initFramework();
158 r2.renderFrame();
159 r2.getRender(depth);
160
161 }
162 }
163}
164
165SCENARIO("Sequentially instanciating and destroying Panda3D renderer sets", "[Panda3D]")
166{
167 if (opt_no_display) {
168 std::cout << "Display is disabled for tests, skipping..." << std::endl;
169 }
170 else {
171 {
172 vpPanda3DRendererSet r1(defaultRenderParams());
173 r1.addSubRenderer(std::make_shared<vpPanda3DGeometryRenderer>(vpPanda3DGeometryRenderer::CAMERA_NORMALS));
174 r1.addSubRenderer(std::make_shared<vpPanda3DRGBRenderer>(true));
175 r1.initFramework();
176 r1.renderFrame();
177 }
178
179 {
180 vpPanda3DRendererSet r1(defaultRenderParams());
181 r1.addSubRenderer(std::make_shared<vpPanda3DGeometryRenderer>(vpPanda3DGeometryRenderer::CAMERA_NORMALS));
182 r1.addSubRenderer(std::make_shared<vpPanda3DRGBRenderer>(true));
183 r1.initFramework();
184 r1.renderFrame();
185 }
186 }
187}
188
189SCENARIO("Using multiple panda3d renderers in parallel", "[Panda3D]")
190{
191 if (opt_no_display) {
192 std::cout << "Display is disabled for tests, skipping..." << std::endl;
193 }
194 else {
195 vpPanda3DRGBRenderer r3(true);
196 r3.setRenderParameters(defaultRenderParams());
197 r3.initFramework();
198 r3.renderFrame();
199
201 r1.setRenderParameters(defaultRenderParams());
202 r1.initFramework();
203 r1.renderFrame();
205 r1.getRender(depth);
206
208 r2.setRenderParameters(defaultRenderParams());
209 r2.initFramework();
210 r2.renderFrame();
211 r2.getRender(depth);
212
213
214 r1.renderFrame();
215 r1.getRender(depth);
216 }
217}
218
219TEST_CASE("Testing Geometry renderer", "[panda3D]")
220{
221 if (opt_no_display) {
222 std::cout << "Display is disabled for tests, skipping..." << std::endl;
223 return;
224 }
227
228
229 std::vector<vpPanda3DGeometryRenderer *> renderers = { &r1, &r2, &r3, &r4 };
230
231 std::vector<vpHomogeneousMatrix> cameraPoses = {
232 vpHomogeneousMatrix(0.0, 0.0, 0.5, 0.0, vpMath::rad(15), 0.0),
233 vpHomogeneousMatrix(0.05, 0.0, 0.4, vpMath::rad(5), 0.0, 0.0),
234 };
235
236 for (const vpHomogeneousMatrix &p: cameraPoses) {
237 std::vector<vpImage<vpRGBf>> normalsImages;
238 std::vector<vpImage<float>> depthImages;
239
240 vpPanda3DRenderParameters params = defaultRenderParams();
241 const std::string objId = "object";
242 for (const auto r: renderers) {
243 r->setRenderParameters(params);
244 r->initFramework();
245 r->addNodeToScene(r->loadObject(objId, createObjFile()));
246 r->setNodePose(objId, vpHomogeneousMatrix(0, 0, 0, 0, 0, 0));
247 r->setCameraPose(p.inverse());
248 r->renderFrame();
249
250 vpImage<float> depth, depthBB, depthSolo;
251 vpImage<vpRGBf> normals(params.getImageHeight(), params.getImageWidth(), vpRGBf(0, 0, 0)), normalsBB, normalsSolo;
252
253 r->getRender(normals, depth);
254 r->getRender(normalsSolo);
255 r->getRender(depthSolo);
256 r->getRender(normalsBB, depthBB, vpRect(0, 0, params.getImageWidth(), params.getImageHeight()), params.getImageHeight(), params.getImageWidth());
257 // Using different getter lead to the same output
258 REQUIRE((depth.getMinValue() == 0 && depth.getMaxValue() > 0.0));
259 REQUIRE(depth == depthSolo);
260 REQUIRE(depth == depthBB);
261 REQUIRE((normals.getSum() != 0.0));
262 REQUIRE(normals == normalsSolo);
263 REQUIRE(normals == normalsBB);
264 normalsImages.push_back(normals);
265 depthImages.push_back(depth);
266 }
267 // Fast rendering difference is small enough
268 const float thresholdN = 1 / 127.5f;
269 const float thresholdDepth = params.getFarClippingDistance() / 255.f;
270 for (unsigned int i = 0; i < normalsImages.size() - 1; ++i) {
271 for (unsigned int j = i + 1; j < normalsImages.size(); ++j) {
272 if (renderers[i]->getRenderType() == renderers[j]->getRenderType()) {
273
274 std::cout << "Comparing renderers" << i << " and " << j << std::endl;
275
276 for (unsigned int b = 0; b < depthImages[i].getSize(); ++b) {
277
278 float depthDiff = fabs(depthImages[i].bitmap[b] - depthImages[j].bitmap[b]);
279 if (depthDiff > thresholdDepth) {
280 FAIL("Depth error is too great");
281 }
282 if (depthImages[i].bitmap[b] > 0.0) {
283 const vpRGBf c1 = normalsImages[i].bitmap[b];
284 const vpRGBf c2 = normalsImages[j].bitmap[b];
285
286
287 if (fabs(c1.R - c2.R) > thresholdN || fabs(c1.G - c2.G) > thresholdN || fabs(c1.B - c2.B) > thresholdN) {
288 std::cout << c1 << c2 << std::endl;
289 FAIL("Normal error is too great");
290 }
291 }
292 }
293 }
294 }
295 }
296
297 }
298
299}
300
301
302int main(int argc, char *argv[])
303{
304 Catch::Session session; // There must be exactly one instance
305 auto cli = session.cli()
306 | Catch::Clara::Opt(opt_no_display)["--no-display"]("Disable display");
307 session.cli(cli);
308
309 const int returnCode = session.applyCommandLine(argc, argv);
310 if (returnCode != 0) { // Indicates a command line error
311 return returnCode;
312 }
313
314 const int numFailed = session.run();
316
317 return numFailed;
318}
319
320#else
321
322#include <stdlib.h>
323
324int main() { return EXIT_SUCCESS; }
325
326#endif
Generic class defining intrinsic camera parameters.
Implementation of an homogeneous matrix and operations on such kind of matrices.
Definition of the vpImage class member functions.
Definition vpImage.h:131
static std::string createFilePath(const std::string &parent, const std::string &child)
static std::string makeTempDirectory(const std::string &dirname)
static double rad(double deg)
Definition vpMath.h:129
static vpPanda3DFrameworkManager & getInstance()
Renderer that outputs object geometric information.
@ CAMERA_NORMALS
Surface normals in the object frame.
Implementation of a traditional RGB renderer in Panda3D.
Rendering parameters for a panda3D simulation.
Class that renders multiple datatypes, in a single pass. A renderer set contains multiple subrenderer...
float B
Blue component.
Definition vpRGBf.h:161
float G
Green component.
Definition vpRGBf.h:160
float R
Red component.
Definition vpRGBf.h:159
Defines a rectangle in the plane.
Definition vpRect.h:79