Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpPoseFeatures.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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 * Pose computation from any features.
32 */
33
34#include <visp3/core/vpDebug.h>
35#include <visp3/vision/vpPoseFeatures.h>
36
37#if defined(VISP_HAVE_MODULE_VISUAL_FEATURES) && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
38
40
42 : m_maxSize(0), m_totalSize(0), m_vvsIterMax(200), m_lambda(1.0), m_verbose(false), m_computeCovariance(false),
43 m_covarianceMatrix(), m_featurePoint_Point_list(), m_featurePoint3D_Point_list(), m_featureVanishingPoint_Point_list(),
44 m_featureVanishingPoint_DuoLine_list(), m_featureEllipse_Sphere_list(), m_featureEllipse_Circle_list(),
45 m_featureLine_Line_list(), m_featureLine_DuoLineInt_List(), m_featureSegment_DuoPoints_list()
46{ }
47
49
51{
52 for (int i = static_cast<int>(m_featurePoint_Point_list.size()) - 1; i >= 0; i--)
53 delete m_featurePoint_Point_list[static_cast<unsigned int>(i)].desiredFeature;
54 m_featurePoint_Point_list.clear();
55
56 for (int i = static_cast<int>(m_featurePoint3D_Point_list.size()) - 1; i >= 0; i--)
57 delete m_featurePoint3D_Point_list[static_cast<unsigned int>(i)].desiredFeature;
58 m_featurePoint3D_Point_list.clear();
59
60 for (int i = static_cast<int>(m_featureVanishingPoint_Point_list.size()) - 1; i >= 0; i--)
61 delete m_featureVanishingPoint_Point_list[static_cast<unsigned int>(i)].desiredFeature;
62 m_featureVanishingPoint_Point_list.clear();
63
64 for (int i = static_cast<int>(m_featureVanishingPoint_DuoLine_list.size()) - 1; i >= 0; i--)
65 delete m_featureVanishingPoint_DuoLine_list[static_cast<unsigned int>(i)].desiredFeature;
66 m_featureVanishingPoint_DuoLine_list.clear();
67
68 for (int i = static_cast<int>(m_featureEllipse_Sphere_list.size()) - 1; i >= 0; i--)
69 delete m_featureEllipse_Sphere_list[static_cast<unsigned int>(i)].desiredFeature;
70 m_featureEllipse_Sphere_list.clear();
71
72 for (int i = static_cast<int>(m_featureEllipse_Circle_list.size()) - 1; i >= 0; i--)
73 delete m_featureEllipse_Circle_list[static_cast<unsigned int>(i)].desiredFeature;
74 m_featureEllipse_Circle_list.clear();
75
76 for (int i = static_cast<int>(m_featureLine_Line_list.size()) - 1; i >= 0; i--)
77 delete m_featureLine_Line_list[static_cast<unsigned int>(i)].desiredFeature;
78 m_featureLine_Line_list.clear();
79
80 for (int i = static_cast<int>(m_featureLine_DuoLineInt_List.size()) - 1; i >= 0; i--)
81 delete m_featureLine_DuoLineInt_List[static_cast<unsigned int>(i)].desiredFeature;
82 m_featureLine_DuoLineInt_List.clear();
83
84 for (int i = static_cast<int>(m_featureSegment_DuoPoints_list.size()) - 1; i >= 0; i--)
85 delete m_featureSegment_DuoPoints_list[static_cast<unsigned int>(i)].desiredFeature;
86 m_featureSegment_DuoPoints_list.clear();
87
88 for (int i = static_cast<int>(m_featureSpecific_list.size()) - 1; i >= 0; i--)
89 delete m_featureSpecific_list[static_cast<unsigned int>(i)];
90 m_featureSpecific_list.clear();
91
92 m_maxSize = 0;
93 m_totalSize = 0;
94}
95
97{
98 m_featurePoint_Point_list.push_back(vpDuo<vpFeaturePoint, vpPoint>());
99 m_featurePoint_Point_list.back().firstParam = p;
100 m_featurePoint_Point_list.back().desiredFeature = new vpFeaturePoint();
101 vpFeatureBuilder::create(*m_featurePoint_Point_list.back().desiredFeature, p);
102
103 m_totalSize++;
104 if (m_featurePoint_Point_list.size() > m_maxSize)
105 m_maxSize = static_cast<unsigned int>(m_featurePoint_Point_list.size());
106}
107
109{
110 m_featurePoint3D_Point_list.push_back(vpDuo<vpFeaturePoint3D, vpPoint>());
111 m_featurePoint3D_Point_list.back().firstParam = p;
112 m_featurePoint3D_Point_list.back().desiredFeature = new vpFeaturePoint3D();
113 vpFeatureBuilder::create(*m_featurePoint3D_Point_list.back().desiredFeature, p);
114
115 m_totalSize++;
116 if (m_featurePoint3D_Point_list.size() > m_maxSize)
117 m_maxSize = static_cast<unsigned int>(m_featurePoint3D_Point_list.size());
118}
119
121{
122 m_featureVanishingPoint_Point_list.push_back(vpDuo<vpFeatureVanishingPoint, vpPoint>());
123 m_featureVanishingPoint_Point_list.back().firstParam = p;
124 m_featureVanishingPoint_Point_list.back().desiredFeature = new vpFeatureVanishingPoint();
125 vpFeatureBuilder::create(*m_featureVanishingPoint_Point_list.back().desiredFeature, p);
126
127 m_totalSize++;
128 if (m_featureVanishingPoint_Point_list.size() > m_maxSize)
129 m_maxSize = static_cast<unsigned int>(m_featureVanishingPoint_Point_list.size());
130}
131
133{
134 m_featureVanishingPoint_DuoLine_list.push_back(vpTrio<vpFeatureVanishingPoint, vpLine, vpLine>());
135 m_featureVanishingPoint_DuoLine_list.back().firstParam = l1;
136 m_featureVanishingPoint_DuoLine_list.back().secondParam = l2;
137 m_featureVanishingPoint_DuoLine_list.back().desiredFeature = new vpFeatureVanishingPoint();
138 vpFeatureBuilder::create(*m_featureVanishingPoint_DuoLine_list.back().desiredFeature, l1, l2);
139
140 m_totalSize++;
141 if (m_featureVanishingPoint_DuoLine_list.size() > m_maxSize)
142 m_maxSize = static_cast<unsigned int>(m_featureVanishingPoint_DuoLine_list.size());
143}
144
146{
147 m_featureEllipse_Sphere_list.push_back(vpDuo<vpFeatureEllipse, vpSphere>());
148 m_featureEllipse_Sphere_list.back().firstParam = s;
149 m_featureEllipse_Sphere_list.back().desiredFeature = new vpFeatureEllipse();
150 vpFeatureBuilder::create(*m_featureEllipse_Sphere_list.back().desiredFeature, s);
151
152 m_totalSize++;
153 if (m_featureEllipse_Sphere_list.size() > m_maxSize)
154 m_maxSize = static_cast<unsigned int>(m_featureEllipse_Sphere_list.size());
155}
156
158{
159 m_featureEllipse_Circle_list.push_back(vpDuo<vpFeatureEllipse, vpCircle>());
160 m_featureEllipse_Circle_list.back().firstParam = c;
161 m_featureEllipse_Circle_list.back().desiredFeature = new vpFeatureEllipse();
162 vpFeatureBuilder::create(*m_featureEllipse_Circle_list.back().desiredFeature, c);
163
164 m_totalSize++;
165 if (m_featureEllipse_Circle_list.size() > m_maxSize)
166 m_maxSize = static_cast<unsigned int>(m_featureEllipse_Circle_list.size());
167}
168
170{
171 m_featureLine_Line_list.push_back(vpDuo<vpFeatureLine, vpLine>());
172 m_featureLine_Line_list.back().firstParam = l;
173 m_featureLine_Line_list.back().desiredFeature = new vpFeatureLine();
174 vpFeatureBuilder::create(*m_featureLine_Line_list.back().desiredFeature, l);
175
176 m_totalSize++;
177 if (m_featureLine_Line_list.size() > m_maxSize)
178 m_maxSize = static_cast<unsigned int>(m_featureLine_Line_list.size());
179}
180
181void vpPoseFeatures::addFeatureLine(const vpCylinder &c, const int &line)
182{
183 m_featureLine_DuoLineInt_List.push_back(vpTrio<vpFeatureLine, vpCylinder, int>());
184 m_featureLine_DuoLineInt_List.back().firstParam = c;
185 m_featureLine_DuoLineInt_List.back().secondParam = line;
186 m_featureLine_DuoLineInt_List.back().desiredFeature = new vpFeatureLine();
187 vpFeatureBuilder::create(*m_featureLine_DuoLineInt_List.back().desiredFeature, c, line);
188
189 m_totalSize++;
190 if (m_featureLine_DuoLineInt_List.size() > m_maxSize)
191 m_maxSize = static_cast<unsigned int>(m_featureLine_DuoLineInt_List.size());
192}
193
195{
196 m_featureSegment_DuoPoints_list.push_back(vpTrio<vpFeatureSegment, vpPoint, vpPoint>());
197 m_featureSegment_DuoPoints_list.back().firstParam = P1;
198 m_featureSegment_DuoPoints_list.back().secondParam = P2;
199 m_featureSegment_DuoPoints_list.back().desiredFeature = new vpFeatureSegment();
200 vpFeatureBuilder::create(*m_featureSegment_DuoPoints_list.back().desiredFeature, P1, P2);
201
202 m_totalSize++;
203 if (m_featureSegment_DuoPoints_list.size() > m_maxSize)
204 m_maxSize = static_cast<unsigned int>(m_featureSegment_DuoPoints_list.size());
205}
206
207void vpPoseFeatures::error_and_interaction(vpHomogeneousMatrix &cMo, vpColVector &err, vpMatrix &L)
208{
209 err = vpColVector();
210 L = vpMatrix();
211
212 for (unsigned int i = 0; i < m_maxSize; i++) {
213 //--------------vpFeaturePoint--------------
214 // From vpPoint
215 if (i < m_featurePoint_Point_list.size()) {
217 vpPoint p(m_featurePoint_Point_list[i].firstParam);
218 p.track(cMo);
220 err.stack(fp.error(*(m_featurePoint_Point_list[i].desiredFeature)));
221 L.stack(fp.interaction());
222 }
223
224 //--------------vpFeaturePoint3D--------------
225 // From vpPoint
226 if (i < m_featurePoint3D_Point_list.size()) {
227 vpFeaturePoint3D fp3D;
228 vpPoint p(m_featurePoint3D_Point_list[i].firstParam);
229 p.track(cMo);
231 err.stack(fp3D.error(*(m_featurePoint3D_Point_list[i].desiredFeature)));
232 L.stack(fp3D.interaction());
233 }
234
235 //--------------vpFeatureVanishingPoint--------------
236 // From vpPoint
237 if (i < m_featureVanishingPoint_Point_list.size()) {
238 vpFeatureVanishingPoint fvp;
239 vpPoint p(m_featureVanishingPoint_Point_list[i].firstParam);
240 p.track(cMo);
242 err.stack(fvp.error(*(m_featureVanishingPoint_Point_list[i].desiredFeature)));
243 L.stack(fvp.interaction());
244 }
245 // From Duo of vpLines
246 if (i < m_featureVanishingPoint_DuoLine_list.size()) {
247 vpFeatureVanishingPoint fvp;
248 vpLine l1(m_featureVanishingPoint_DuoLine_list[i].firstParam);
249 vpLine l2(m_featureVanishingPoint_DuoLine_list[i].secondParam);
250 l1.track(cMo);
251 l2.track(cMo);
252 vpFeatureBuilder::create(fvp, l1, l2);
253 err.stack(fvp.error(*(m_featureVanishingPoint_DuoLine_list[i].desiredFeature)));
254 L.stack(fvp.interaction());
255 }
256
257 //--------------vpFeatureEllipse--------------
258 // From vpSphere
259 if (i < m_featureEllipse_Sphere_list.size()) {
260 vpFeatureEllipse fe;
261 vpSphere s(m_featureEllipse_Sphere_list[i].firstParam);
262 s.track(cMo);
264 err.stack(fe.error(*(m_featureEllipse_Sphere_list[i].desiredFeature)));
265 L.stack(fe.interaction());
266 }
267 // From vpCircle
268 if (i < m_featureEllipse_Circle_list.size()) {
269 vpFeatureEllipse fe;
270 vpCircle c(m_featureEllipse_Circle_list[i].firstParam);
271 c.track(cMo);
273 err.stack(fe.error(*(m_featureEllipse_Circle_list[i].desiredFeature)));
274 L.stack(fe.interaction());
275 }
276
277 //--------------vpFeatureLine--------------
278 // From vpLine
279 if (i < m_featureLine_Line_list.size()) {
280 vpFeatureLine fl;
281 vpLine l(m_featureLine_Line_list[i].firstParam);
282 l.track(cMo);
284 err.stack(fl.error(*(m_featureLine_Line_list[i].desiredFeature)));
285 L.stack(fl.interaction());
286 }
287 // From Duo of vpCylinder / Integer
288 if (i < m_featureLine_DuoLineInt_List.size()) {
289 vpFeatureLine fl;
290 vpCylinder c(m_featureLine_DuoLineInt_List[i].firstParam);
291 c.track(cMo);
292 vpFeatureBuilder::create(fl, c, m_featureLine_DuoLineInt_List[i].secondParam);
293 err.stack(fl.error(*(m_featureLine_DuoLineInt_List[i].desiredFeature)));
294 L.stack(fl.interaction());
295 }
296
297 //--------------vpFeatureSegment--------------
298 // From Duo of vpPoints
299 if (i < m_featureSegment_DuoPoints_list.size()) {
300 vpFeatureSegment fs;
301 vpPoint p1(m_featureSegment_DuoPoints_list[i].firstParam);
302 vpPoint p2(m_featureSegment_DuoPoints_list[i].secondParam);
303 p1.track(cMo);
304 p2.track(cMo);
305 vpFeatureBuilder::create(fs, p1, p2);
306 err.stack(fs.error(*(m_featureSegment_DuoPoints_list[i].desiredFeature)));
307 L.stack(fs.interaction());
308 }
309
310 //--------------Specific Feature--------------
311 if (i < m_featureSpecific_list.size()) {
312 m_featureSpecific_list[i]->createCurrent(cMo);
313 err.stack(m_featureSpecific_list[i]->error());
314 L.stack(m_featureSpecific_list[i]->currentInteraction());
315 }
316 }
317}
318
320{
321 switch (type) {
322 case VIRTUAL_VS:
323 computePoseVVS(cMo);
324 break;
326 computePoseRobustVVS(cMo);
327 break;
328 default:
329 break;
330 }
331}
332
333void vpPoseFeatures::computePoseVVS(vpHomogeneousMatrix &cMo)
334{
335 try {
336 double residu_1 = 1e8;
337 double r = 1e8 - 1;
338 // we stop the minimization when the error is bellow 1e-8
339
340 vpMatrix L;
341 vpColVector err;
342 vpColVector v;
343 unsigned int rank_max = 0;
344 unsigned int iter = 0;
345
346 // while(static_cast<int>((residu_1 - r)*1e12) != 0 )
347 while (std::fabs((residu_1 - r) * 1e12) > std::numeric_limits<double>::epsilon()) {
348 residu_1 = r;
349
350 // Compute the interaction matrix and the error
351 error_and_interaction(cMo, err, L);
352
353 // compute the residual
354 r = err.sumSquare();
355
356 // compute the pseudo inverse of the interaction matrix
357 vpMatrix Lp;
358 unsigned int rank = L.pseudoInverse(Lp, 1e-6); // modif FC 1e-16
359
360 if (rank_max < rank)
361 rank_max = rank;
362
363 // compute the VVS control law
364 v = -m_lambda * Lp * err;
365
366 cMo = vpExponentialMap::direct(v).inverse() * cMo;
367 if (iter++ > m_vvsIterMax) {
368 vpTRACE("Max iteration reached");
369 break;
370 }
371 }
372 if (rank_max < 6) {
373 if (m_verbose) {
374 vpTRACE("Only %d pose parameters can be estimated.", rank_max);
375 }
376 }
377
378 if (m_computeCovariance)
379 m_covarianceMatrix = vpMatrix::computeCovarianceMatrix(L, v, -m_lambda * err);
380
381 }
382 catch (...) {
383 vpERROR_TRACE("vpPoseFeatures::computePoseVVS");
384 throw;
385 }
386}
387
388void vpPoseFeatures::computePoseRobustVVS(vpHomogeneousMatrix &cMo)
389{
390 try {
391 double residu_1 = 1e8;
392 double r = 1e8 - 1;
393
394 // we stop the minimization when the error is bellow 1e-8
395 vpMatrix L, W;
396 vpColVector w, res;
397 vpColVector v;
398 vpColVector error; // error vector
399
400 vpRobust robust;
401 robust.setMinMedianAbsoluteDeviation(0.00001);
402
403 unsigned int rank_max = 0;
404 unsigned int iter = 0;
405
406 // while(static_cast<int>((residu_1 - r)*1e12) !=0)
407 while (std::fabs((residu_1 - r) * 1e12) > std::numeric_limits<double>::epsilon()) {
408 residu_1 = r;
409
410 // Compute the interaction matrix and the error
411 error_and_interaction(cMo, error, L);
412
413 // compute the residual
414 r = error.sumSquare();
415
416 if (iter == 0) {
417 res.resize(error.getRows() / 2);
418 w.resize(error.getRows() / 2);
419 W.resize(error.getRows(), error.getRows());
420 w = 1;
421 }
422
423 for (unsigned int k = 0; k < error.getRows() / 2; k++) {
424 res[k] = vpMath::sqr(error[2 * k]) + vpMath::sqr(error[2 * k + 1]);
425 }
426 robust.MEstimator(vpRobust::TUKEY, res, w);
427
428 // compute the pseudo inverse of the interaction matrix
429 for (unsigned int k = 0; k < error.getRows() / 2; k++) {
430 W[2 * k][2 * k] = w[k];
431 W[2 * k + 1][2 * k + 1] = w[k];
432 }
433 // compute the pseudo inverse of the interaction matrix
434 vpMatrix Lp;
435 vpMatrix LRank;
436 (W * L).pseudoInverse(Lp, 1e-6);
437 unsigned int rank = L.pseudoInverse(LRank, 1e-6);
438
439 if (rank_max < rank)
440 rank_max = rank;
441
442 // compute the VVS control law
443 v = -m_lambda * Lp * W * error;
444
446 if (iter++ > m_vvsIterMax) {
447 vpTRACE("Max iteration reached");
448 break;
449 }
450 }
451
452 if (rank_max < 6) {
453 if (m_verbose) {
454 vpTRACE("Only %d pose parameters can be estimated.", rank_max);
455 }
456 }
457
458 if (m_computeCovariance)
459 m_covarianceMatrix =
460 vpMatrix::computeCovarianceMatrix(L, v, -m_lambda * error, W * W); // Remark: W*W = W*W.t() since the
461 // matrix is diagonal, but using W*W
462 // is more efficient.
463 }
464 catch (...) {
465 vpERROR_TRACE("vpPoseFeatures::computePoseRobustVVS");
466 throw;
467 }
468}
469
470END_VISP_NAMESPACE
471
472#elif !defined(VISP_BUILD_SHARED_LIBS)
473// Work around to avoid warning: libvisp_vision.a(vpPoseFeatures.cpp.o) has no symbols
474void dummy_vpPoseFeatures() { }
475#endif
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:448
Class that defines a 3D circle in the object frame and allows forward projection of a 3D circle in th...
Definition vpCircle.h:87
Implementation of column vector and the associated operations.
double sumSquare() const
void stack(double d)
void resize(unsigned int i, bool flagNullify=true)
Class that defines a 3D cylinder in the object frame and allows forward projection of a 3D cylinder i...
Definition vpCylinder.h:101
static vpHomogeneousMatrix direct(const vpColVector &v)
static void create(vpFeaturePoint &s, const vpCameraParameters &cam, const vpDot &d)
Class that defines 2D ellipse visual feature.
vpMatrix interaction(unsigned int select=FEATURE_ALL) VP_OVERRIDE
compute the interaction matrix from a subset a the possible features
vpColVector error(const vpBasicFeature &s_star, unsigned int select=FEATURE_ALL) VP_OVERRIDE
Class that defines a 2D line visual feature which is composed by two parameters that are and ,...
vpMatrix interaction(unsigned int select=FEATURE_ALL) VP_OVERRIDE
vpColVector error(const vpBasicFeature &s_star, unsigned int select=FEATURE_ALL) VP_OVERRIDE
Class that defines the 3D point visual feature.
vpColVector error(const vpBasicFeature &s_star, unsigned int select=FEATURE_ALL) VP_OVERRIDE
vpMatrix interaction(unsigned int select=FEATURE_ALL) VP_OVERRIDE
Class that defines a 2D point visual feature which is composed by two parameters that are the cartes...
vpColVector error(const vpBasicFeature &s_star, unsigned int select=FEATURE_ALL) VP_OVERRIDE
vpMatrix interaction(unsigned int select=FEATURE_ALL) VP_OVERRIDE
Class that defines a 2D segment visual features. This class allow to consider two sets of visual feat...
vpColVector error(const vpBasicFeature &s_star, unsigned int select=FEATURE_ALL) VP_OVERRIDE
vpMatrix interaction(unsigned int select=FEATURE_ALL) VP_OVERRIDE
vpColVector error(const vpBasicFeature &s_star, unsigned int select=(vpFeatureVanishingPoint::selectX()|vpFeatureVanishingPoint::selectY())) VP_OVERRIDE
vpMatrix interaction(unsigned int select=(vpFeatureVanishingPoint::selectX()|vpFeatureVanishingPoint::selectY())) VP_OVERRIDE
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix inverse() const
Class that defines a 3D line in the object frame and allows forward projection of the line in the cam...
Definition vpLine.h:103
static double sqr(double x)
Definition vpMath.h:203
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
vpMatrix pseudoInverse(double svThreshold=1e-6) const
static vpMatrix computeCovarianceMatrix(const vpMatrix &A, const vpColVector &x, const vpColVector &b)
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition vpPoint.h:79
void addFeatureLine(const vpLine &l)
void addFeatureEllipse(const vpCircle &c)
void addFeaturePoint3D(const vpPoint &p)
void addFeaturePoint(const vpPoint &p)
virtual ~vpPoseFeatures()
void addFeatureVanishingPoint(const vpPoint &p)
void computePose(vpHomogeneousMatrix &cMo, const vpPoseFeaturesMethodType &type=VIRTUAL_VS)
void addFeatureSegment(vpPoint &P1, vpPoint &P2)
@ TUKEY
Tukey influence function.
Definition vpRobust.h:89
void MEstimator(const vpRobustEstimatorType method, const vpColVector &residues, vpColVector &weights)
Definition vpRobust.cpp:130
void setMinMedianAbsoluteDeviation(double mad_min)
Definition vpRobust.h:136
Class that defines a 3D sphere in the object frame and allows forward projection of a 3D sphere in th...
Definition vpSphere.h:80
#define vpTRACE
Definition vpDebug.h:450
#define vpERROR_TRACE
Definition vpDebug.h:423