Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
testPose.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Compute the pose of a 3D object using the Dementhon, Lagrange and
33  * Non-Linear approach.
34  *
35  * Authors:
36  * Eric Marchand
37  * Fabien Spindler
38  *
39  *****************************************************************************/
40 
41 #include <visp3/core/vpDebug.h>
42 #include <visp3/core/vpHomogeneousMatrix.h>
43 #include <visp3/core/vpMath.h>
44 #include <visp3/core/vpPoint.h>
45 #include <visp3/core/vpRotationMatrix.h>
46 #include <visp3/core/vpRxyzVector.h>
47 #include <visp3/core/vpTranslationVector.h>
48 #include <visp3/vision/vpPose.h>
49 
50 #include <stdio.h>
51 #include <stdlib.h>
52 
53 #define L 0.035
54 #define L2 0.1
55 
64 void print_pose(const vpHomogeneousMatrix &cMo, const std::string &legend);
65 int compare_pose(const vpPose &pose, const vpHomogeneousMatrix &cMo_ref, const vpHomogeneousMatrix &cMo_est,
66  const std::string &legend);
67 
68 // print the resulting estimated pose
69 void print_pose(const vpHomogeneousMatrix &cMo, const std::string &legend)
70 {
71  vpPoseVector cpo = vpPoseVector(cMo);
72 
73  std::cout << std::endl
74  << legend << "\n "
75  << "tx = " << cpo[0] << "\n "
76  << "ty = " << cpo[1] << "\n "
77  << "tz = " << cpo[2] << "\n "
78  << "tux = vpMath::rad(" << vpMath::deg(cpo[3]) << ")\n "
79  << "tuy = vpMath::rad(" << vpMath::deg(cpo[4]) << ")\n "
80  << "tuz = vpMath::rad(" << vpMath::deg(cpo[5]) << ")\n"
81  << std::endl;
82 }
83 
84 // test if pose is well estimated
85 int compare_pose(const vpPose &pose, const vpHomogeneousMatrix &cMo_ref, const vpHomogeneousMatrix &cMo_est,
86  const std::string &legend)
87 {
88  vpPoseVector pose_ref = vpPoseVector(cMo_ref);
89  vpPoseVector pose_est = vpPoseVector(cMo_est);
90 
91  int fail = 0;
92 
93  // Test done on the 3D pose
94  for (unsigned int i = 0; i < 6; i++) {
95  if (std::fabs(pose_ref[i] - pose_est[i]) > 0.001)
96  fail = 1;
97  }
98 
99  std::cout << "Based on 3D parameters " << legend << " is " << (fail ? "badly" : "well") << " estimated" << std::endl;
100 
101  // Test done on the residual
102  double r = pose.computeResidual(cMo_est);
103  if (pose.listP.size() < 4) {
104  fail = 1;
105  std::cout << "Not enough point" << std::endl;
106  return fail;
107  }
108  r = sqrt(r / pose.listP.size());
109  // std::cout << "Residual on each point (meter): " << r << std::endl;
110  fail = (r > 0.001) ? 1 : 0;
111  std::cout << "Based on 2D residual (" << r << ") " << legend << " is " << (fail ? "badly" : "well") << " estimated"
112  << std::endl;
113  return fail;
114 }
115 
116 int main()
117 {
118  try {
119  int test_planar_fail = 0, test_non_planar_fail = 0, fail = 0;
120 
121  vpHomogeneousMatrix cMo; // will contain the estimated pose
122 
123  {
124  //
125  // Test planar case with 4 points
126  //
127 
128  std::cout << "Start test considering planar case with 4 points..." << std::endl;
129  std::cout << "===================================================" << std::endl;
130 
131  //vpPoseVector cpo_ref = vpPoseVector(0.01, 0.02, 0.25, vpMath::rad(5), 0, vpMath::rad(10));
132  vpPoseVector cpo_ref = vpPoseVector(-0.01, -0.02, 0.3, vpMath::rad(20), vpMath::rad(-20), vpMath::rad(10));
133  vpHomogeneousMatrix cMo_ref(cpo_ref);
134 
135  int npt = 4;
136  std::vector<vpPoint> P(npt); // Point to be tracked
137  double Z = 0.05; // FS: Dementhon estimation is not good when Z=0.3
138 
139  P[0].setWorldCoordinates(-L, -L, Z);
140  P[1].setWorldCoordinates( L, -L, Z);
141  P[2].setWorldCoordinates( L, L, Z);
142  P[3].setWorldCoordinates(-L, L, Z);
143 
144  vpPose pose;
145 
146  for (int i = 0; i < npt; i++) {
147  P[i].project(cMo_ref);
148  // P[i].print();
149  pose.addPoint(P[i]); // and added to the pose computation class
150  }
151 
152  // Let's go ...
153 
154  print_pose(cMo_ref, std::string("Reference pose"));
155 
156  std::cout << "-------------------------------------------------" << std::endl;
157  pose.computePose(vpPose::LAGRANGE, cMo);
158 
159  print_pose(cMo, std::string("Pose estimated by Lagrange"));
160  fail = compare_pose(pose, cMo_ref, cMo, "pose by Lagrange");
161  test_planar_fail |= fail;
162 
163  std::cout << "--------------------------------------------------" << std::endl;
164  pose.computePose(vpPose::DEMENTHON, cMo);
165 
166  print_pose(cMo, std::string("Pose estimated by Dementhon"));
167  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon");
168  test_planar_fail |= fail;
169 
170  std::cout << "--------------------------------------------------" << std::endl;
171 
173  pose.setRansacThreshold(0.01);
174  pose.computePose(vpPose::RANSAC, cMo);
175 
176  print_pose(cMo, std::string("Pose estimated by Ransac"));
177  fail = compare_pose(pose, cMo_ref, cMo, "pose by Ransac");
178  test_planar_fail |= fail;
179 
180  std::cout << "--------------------------------------------------" << std::endl;
182 
183  print_pose(cMo, std::string("Pose estimated by Lagrange then Lowe"));
184  fail = compare_pose(pose, cMo_ref, cMo, "pose by Lagrange then Lowe");
185  test_planar_fail |= fail;
186 
187  std::cout << "--------------------------------------------------" << std::endl;
189 
190  print_pose(cMo, std::string("Pose estimated by Dementhon then Lowe"));
191  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon then Lowe");
192  test_planar_fail |= fail;
193 
194  // Now Virtual Visual servoing
195  std::cout << "--------------------------------------------------" << std::endl;
196  pose.computePose(vpPose::VIRTUAL_VS, cMo);
197 
198  print_pose(cMo, std::string("Pose estimated by VVS"));
199  fail = compare_pose(pose, cMo_ref, cMo, "pose by VVS");
200  test_planar_fail |= fail;
201 
202  std::cout << "-------------------------------------------------" << std::endl;
204 
205  print_pose(cMo, std::string("Pose estimated by Dementhon then by VVS"));
206  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon then by VVS");
207  test_planar_fail |= fail;
208 
209  std::cout << "-------------------------------------------------" << std::endl;
211 
212  print_pose(cMo, std::string("Pose estimated by Lagrange then by VVS"));
213  fail = compare_pose(pose, cMo_ref, cMo, "pose by Lagrange then by VVS");
214  test_planar_fail |= fail;
215 
216  }
217 
218  {
219  //
220  // Test non-planar case with 6 points (at least 6 points for Lagrange non planar)
221  //
222 
223  std::cout << "\nStart test considering non-planar case with 6 points..." << std::endl;
224  std::cout << "=======================================================" << std::endl;
225 
226  vpPoseVector cpo_ref = vpPoseVector(0.01, 0.02, 0.25, vpMath::rad(5), 0, vpMath::rad(10));
227  vpHomogeneousMatrix cMo_ref(cpo_ref);
228 
229  int npt = 6;
230  std::vector<vpPoint> P(npt); // Point to be tracked
231  P[0].setWorldCoordinates(-L, -L, 0); // Lagrange not accurate...
232  P[0].setWorldCoordinates(-L, -L, -0.02);
233  P[1].setWorldCoordinates( L, -L, 0);
234  P[2].setWorldCoordinates( L, L, 0);
235  P[3].setWorldCoordinates(-2 * L, 3 * L, 0);
236  P[4].setWorldCoordinates(-L, L, 0.01);
237  P[5].setWorldCoordinates( L, L/2., 0.03);
238 
239  vpPose pose;
240 
241  for (int i = 0; i < npt; i++) {
242  P[i].project(cMo_ref);
243  // P[i].print();
244  pose.addPoint(P[i]); // and added to the pose computation class
245  }
246 
247  // Let's go ...
248  print_pose(cMo_ref, std::string("Reference pose"));
249 
250  std::cout << "-------------------------------------------------" << std::endl;
251  pose.computePose(vpPose::LAGRANGE, cMo);
252 
253  print_pose(cMo, std::string("Pose estimated by Lagrange"));
254  fail = compare_pose(pose, cMo_ref, cMo, "pose by Lagrange");
255  test_non_planar_fail |= fail;
256 
257  std::cout << "--------------------------------------------------" << std::endl;
258  pose.computePose(vpPose::DEMENTHON, cMo);
259 
260  print_pose(cMo, std::string("Pose estimated by Dementhon"));
261  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon");
262  test_non_planar_fail |= fail;
263 
264  std::cout << "--------------------------------------------------" << std::endl;
266  pose.setRansacThreshold(0.01);
267  pose.computePose(vpPose::RANSAC, cMo);
268 
269  print_pose(cMo, std::string("Pose estimated by Ransac"));
270  fail = compare_pose(pose, cMo_ref, cMo, "pose by Ransac");
271  test_non_planar_fail |= fail;
272 
273  std::cout << "--------------------------------------------------" << std::endl;
275 
276  print_pose(cMo, std::string("Pose estimated by Lagrange then Lowe"));
277  fail = compare_pose(pose, cMo_ref, cMo, "pose by Lagrange then Lowe");
278  test_non_planar_fail |= fail;
279 
280  std::cout << "--------------------------------------------------" << std::endl;
282 
283  print_pose(cMo, std::string("Pose estimated by Dementhon then Lowe"));
284  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon then Lowe");
285  test_non_planar_fail |= fail;
286 
287  // Now Virtual Visual servoing
288 
289  std::cout << "--------------------------------------------------" << std::endl;
290  pose.computePose(vpPose::VIRTUAL_VS, cMo);
291 
292  print_pose(cMo, std::string("Pose estimated by VVS"));
293  fail = compare_pose(pose, cMo_ref, cMo, "pose by VVS");
294  test_non_planar_fail |= fail;
295 
296  std::cout << "-------------------------------------------------" << std::endl;
298 
299  print_pose(cMo, std::string("Pose estimated by Dementhon then by VVS"));
300  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon then by VVS");
301  test_non_planar_fail |= fail;
302 
303  std::cout << "-------------------------------------------------" << std::endl;
305 
306  print_pose(cMo, std::string("Pose estimated by Lagrange then by VVS"));
307  fail = compare_pose(pose, cMo_ref, cMo, "pose by Lagrange then by VVS");
308  test_non_planar_fail |= fail;
309  }
310 
311  //
312  // Test non-planar case with 4 points (Lagrange can not be used)
313  //
314 
315  std::cout << "\nStart test considering non-planar case with 4 points..." << std::endl;
316  std::cout << "=======================================================" << std::endl;
317 
318  {
319  int npt = 4;
320  std::vector<vpPoint> P(npt); // Point to be tracked
321  P[0].setWorldCoordinates(-L2, -L2, 0);
322  P[1].setWorldCoordinates( L2, -L2, 0.2);
323  P[2].setWorldCoordinates( L2, L2, -0.1);
324  P[3].setWorldCoordinates(-L2, L2, 0);
325 
326  vpPose pose;
327 
328  vpPoseVector cpo_ref = vpPoseVector(-0.1, -0.2, 0.8, vpMath::rad(10), vpMath::rad(-10), vpMath::rad(25));
329  vpHomogeneousMatrix cMo_ref(cpo_ref);
330 
331  for (int i = 0; i < npt; i++) {
332  P[i].project(cMo_ref);
333  // P[i].print(); printf("\n");
334  pose.addPoint(P[i]); // and added to the pose computation class
335  }
336 
337  // Let's go ...
338  print_pose(cMo_ref, std::string("Reference pose"));
339 
340  std::cout << "--------------------------------------------------" << std::endl;
341  pose.computePose(vpPose::DEMENTHON, cMo);
342 
343  print_pose(cMo, std::string("Pose estimated by Dementhon"));
344  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon");
345  test_non_planar_fail |= fail;
346 
347  std::cout << "--------------------------------------------------" << std::endl;
349  pose.setRansacThreshold(0.01);
350  pose.computePose(vpPose::RANSAC, cMo);
351 
352  print_pose(cMo, std::string("Pose estimated by Ransac"));
353  fail = compare_pose(pose, cMo_ref, cMo, "pose by Ransac");
354  test_non_planar_fail |= fail;
355 
356  std::cout << "--------------------------------------------------" << std::endl;
358 
359  print_pose(cMo, std::string("Pose estimated by Dementhon then Lowe"));
360  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon then Lowe");
361  test_non_planar_fail |= fail;
362 
363  // Now Virtual Visual servoing
364  std::cout << "--------------------------------------------------" << std::endl;
365  pose.computePose(vpPose::VIRTUAL_VS, cMo);
366 
367  print_pose(cMo, std::string("Pose estimated by VVS"));
368  fail = compare_pose(pose, cMo_ref, cMo, "pose by VVS");
369  test_non_planar_fail |= fail;
370 
371  std::cout << "-------------------------------------------------" << std::endl;
373 
374  print_pose(cMo, std::string("Pose estimated by Dementhon then by VVS"));
375  fail = compare_pose(pose, cMo_ref, cMo, "pose by Dementhon then by VVS");
376  test_non_planar_fail |= fail;
377 
378  std::cout << "-------------------------------------------------" << std::endl;
379  }
380 
381  std::cout << "=======================================================" << std::endl;
382  std::cout << "Pose estimation test from planar points: " << (test_planar_fail ? "fail" : "is ok") << std::endl;
383  std::cout << "Pose estimation test from non-planar points: " << (test_non_planar_fail ? "fail" : "is ok") << std::endl;
384  std::cout << "Global pose estimation test: " << ((test_planar_fail | test_non_planar_fail) ? "fail" : "is ok") << std::endl;
385 
386  return ((test_planar_fail | test_non_planar_fail) ? EXIT_FAILURE : EXIT_SUCCESS);
387  } catch (const vpException &e) {
388  std::cout << "Catch an exception: " << e << std::endl;
389  return EXIT_FAILURE;
390  }
391 }
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, bool(*func)(const vpHomogeneousMatrix &)=NULL)
Definition: vpPose.cpp:374
Implementation of an homogeneous matrix and operations on such kind of matrices.
error that can be emited by ViSP classes.
Definition: vpException.h:71
void setRansacThreshold(const double &t)
Definition: vpPose.h:248
std::list< vpPoint > listP
Array of point (use here class vpPoint)
Definition: vpPose.h:110
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
Definition: vpPose.h:80
static double rad(double deg)
Definition: vpMath.h:108
void setRansacNbInliersToReachConsensus(const unsigned int &nbC)
Definition: vpPose.h:247
static double deg(double rad)
Definition: vpMath.h:101
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:151
double computeResidual(const vpHomogeneousMatrix &cMo) const
Compute and return the sum of squared residuals expressed in meter^2 for the pose matrix cMo...
Definition: vpPose.cpp:336
void addPoint(const vpPoint &P)
Definition: vpPose.cpp:149