Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpHomographyMalis.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  * Homography estimation.
32  */
33 
45 #include <visp3/core/vpDebug.h>
46 #include <visp3/core/vpMatrixException.h>
47 #include <visp3/vision/vpHomography.h>
48 
49 #include <cmath> // std::fabs
50 
51 BEGIN_VISP_NAMESPACE
52 
53 #ifndef DOXYGEN_SHOULD_SKIP_THIS
54 namespace
55 {
56 const double eps = 1e-6;
57 
58 /**************************************************************************
59  * NOM :
60  * changeFrame
61  *
62  * DESCRIPTION :
63  * Changement de repere Euclidien.
64  *
65  ****************************************************************************
66  * ENTREES :
67  * int pts_ref[4] : Definit quels sont les points de reference, ils ne
68  * seront pas affectes par le changement de repere
69  * int nb_pts : nombre de points a changer de repere
70  * double **pd : La matrice des coordonnees des points desires
71  * double **p : La matrice des coordonnees des points courants
72  *
73  *
74  * SORTIES :
75  *
76  * double **pt_des_nr : La matrice des coordonnees des points desires
77  * dans le nouveau repere.
78  * double **pt_cour_nr : La matrice des coordonnees des points courants
79  * dans le nouveau repere
80  * double **M : ??
81  * double **Mpd : pseudo inverse de M ..
82  *
83  *
84  ****************************************************************************
85  */
86 
87 void changeFrame(unsigned int *pts_ref, unsigned int nb_pts, vpMatrix &pd, vpMatrix &p, vpMatrix &pnd, vpMatrix &pn,
88  vpMatrix &M, vpMatrix &Mdp);
89 void hlm2D(unsigned int nb_pts, vpMatrix &points_des, vpMatrix &points_cour, vpMatrix &H);
90 void hlm3D(unsigned int nb_pts, vpMatrix &pd, vpMatrix &p, vpMatrix &H);
91 void hlm(unsigned int q_cible, const std::vector<double> &xm, const std::vector<double> &ym,
92  const std::vector<double> &xmi, const std::vector<double> &ymi, vpMatrix &H);
93 
94 void changeFrame(unsigned int *pts_ref, unsigned int nb_pts, vpMatrix &pd, vpMatrix &p, vpMatrix &pnd, vpMatrix &pn,
95  vpMatrix &M, vpMatrix &Mdp)
96 {
97  /* Construction des matrices de changement de repere */
98  vpMatrix Md(3, 3);
99  vpMatrix Mp(3, 3);
100 
101  const unsigned int val_3 = 3;
102  for (unsigned int i = 0; i < val_3; ++i) {
103  for (unsigned int j = 0; j < val_3; ++j) {
104  M[j][i] = p[pts_ref[i]][j];
105  Md[j][i] = pd[pts_ref[i]][j];
106  }
107  }
108 
109  /*calcul de la pseudo inverse */
110  Mp = M.pseudoInverse(1e-16);
111  Mdp = Md.pseudoInverse(1e-16);
112 
113  if (pts_ref[3] > 0) {
114  double lamb_des[3];
115  double lamb_cour[3];
116 
117  for (unsigned int i = 0; i < val_3; ++i) {
118  for (unsigned int j = 0; j < val_3; ++j) {
119  lamb_cour[i] = Mp[i][j] * p[pts_ref[3]][j];
120  lamb_des[i] = Mdp[i][j] * pd[pts_ref[3]][j];
121  }
122  }
123 
124  for (unsigned int i = 0; i < val_3; ++i) {
125  for (unsigned int j = 0; j < val_3; ++j) {
126  M[i][j] = M[i][j] * lamb_cour[j];
127  Md[i][j] = Md[i][j] * lamb_des[j];
128  }
129  }
130 
131  Mdp = Md.pseudoInverse(1e-16);
132  }
133 
134  /* changement de repere pour tous les points autres que
135  les trois points de reference */
136 
137  unsigned int cont_pts = 0;
138  for (unsigned int k = 0; k < nb_pts; ++k) {
139  if ((pts_ref[0] != k) && (pts_ref[1] != k) && (pts_ref[2] != k)) {
140  for (unsigned int i = 0; i < val_3; ++i) {
141  pn[cont_pts][i] = 0.0;
142  pnd[cont_pts][i] = 0.0;
143  for (unsigned int j = 0; j < val_3; ++j) {
144  pn[cont_pts][i] = pn[cont_pts][i] + (Mp[i][j] * p[k][j]);
145  pnd[cont_pts][i] = pnd[cont_pts][i] + (Mdp[i][j] * pd[k][j]);
146  }
147  }
148  cont_pts = cont_pts + 1;
149  }
150  }
151 }
152 
153 /**************************************************************************
154  * NOM :
155  * Homographie_CrvMafEstHomoPointsCible2D
156  *
157  * DESCRIPTION :
158  * Calcul de l'homographie entre une image courante et une image desiree dans
159  *le cas particulier d'une cible planaire de points (cible pi). Cette
160  *procedure est appellee par "Homographie_CrvMafCalculHomographie".
161  *
162  ****************************************************************************
163  * ENTREES :
164  * int Nb_pts : nombre de points
165  * double **pd : tableau des coordonnees des points desires
166  * couble **p : tableau des coordonnees des points courants
167  *
168  * SORTIES :
169  *
170  * double **H matrice d homographie
171  *
172  ****************************************************************************
173  * AUTEUR : BOSSARD Nicolas. INSA Rennes 5eme annee.
174  *
175  * DATE DE CREATION : 02/12/98
176  *
177  * DATES DE MISE A JOUR :
178  *
179  ****************************************************************************/
180 void hlm2D(unsigned int nb_pts, vpMatrix &points_des, vpMatrix &points_cour, vpMatrix &H)
181 {
182  double vals_inf;
183  unsigned int contZeros, vect;
184 
186  vpMatrix M(3 * nb_pts, 9);
187  vpMatrix V(9, 9);
188  vpColVector sv(9);
189 
191  for (unsigned int j = 0; j < nb_pts; ++j) {
192  M[3 * j][0] = 0;
193  M[3 * j][1] = 0;
194  M[3 * j][2] = 0;
195  M[3 * j][3] = -points_des[j][0] * points_cour[j][2];
196  M[3 * j][4] = -points_des[j][1] * points_cour[j][2];
197  M[3 * j][5] = -points_des[j][2] * points_cour[j][2];
198  M[3 * j][6] = points_des[j][0] * points_cour[j][1];
199  M[3 * j][7] = points_des[j][1] * points_cour[j][1];
200  M[3 * j][8] = points_des[j][2] * points_cour[j][1];
201 
202  M[(3 * j) + 1][0] = points_des[j][0] * points_cour[j][2];
203  M[(3 * j) + 1][1] = points_des[j][1] * points_cour[j][2];
204  M[(3 * j) + 1][2] = points_des[j][2] * points_cour[j][2];
205  M[(3 * j) + 1][3] = 0;
206  M[(3 * j) + 1][4] = 0;
207  M[(3 * j) + 1][5] = 0;
208  M[(3 * j) + 1][6] = -points_des[j][0] * points_cour[j][0];
209  M[(3 * j) + 1][7] = -points_des[j][1] * points_cour[j][0];
210  M[(3 * j) + 1][8] = -points_des[j][2] * points_cour[j][0];
211 
212  M[(3 * j) + 2][0] = -points_des[j][0] * points_cour[j][1];
213  M[(3 * j) + 2][1] = -points_des[j][1] * points_cour[j][1];
214  M[(3 * j) + 2][2] = -points_des[j][2] * points_cour[j][1];
215  M[(3 * j) + 2][3] = points_des[j][0] * points_cour[j][0];
216  M[(3 * j) + 2][4] = points_des[j][1] * points_cour[j][0];
217  M[(3 * j) + 2][5] = points_des[j][2] * points_cour[j][0];
218  M[(3 * j) + 2][6] = 0;
219  M[(3 * j) + 2][7] = 0;
220  M[(3 * j) + 2][8] = 0;
221  }
222 
224  M.svd(sv, V);
225 
226  /*****
227  La meilleure solution est le vecteur de V associe
228  a la valeur singuliere la plus petite en valeur absolu.
229  Pour cela on parcourt la matrice des valeurs singulieres
230  et on repere la plus petite valeur singuliere, on en profite
231  pour effectuer un controle sur le rang de la matrice : pas plus
232  de 2 valeurs singulieres quasi=0
233  *****/
234  vals_inf = sv[0];
235  vect = 0;
236  contZeros = 0;
237  if (sv[0] < eps) {
238  contZeros = contZeros + 1;
239  }
240  for (unsigned int j = 1; j < 9; ++j) {
241  if (sv[j] < vals_inf) {
242  vals_inf = sv[j];
243  vect = j;
244  }
245  if (sv[j] < eps) {
246  contZeros = contZeros + 1;
247  }
248  }
249 
251  if (contZeros > 2) {
252  // vpERROR_TRACE("matrix is rank deficient");
253  throw(vpMatrixException(vpMatrixException::matrixError, "matrix is rank deficient"));
254  }
255 
256  H.resize(3, 3);
258  const unsigned int val_3 = 3;
259  for (unsigned int i = 0; i < val_3; ++i) {
260  for (unsigned int j = 0; j < val_3; ++j) {
261  H[i][j] = V[(3 * i) + j][vect];
262  }
263  }
264 }
265 
266 /**************************************************************************
267  * NOM :
268  * Homographie_CrvMafEstHomoPointsC3DEzio
269  *
270  * DESCRIPTION :
271  * Calcul de l'homographie entre une image courante et une image desiree dans
272  *le cas particulier d'une cible non planaire de points (cible pi). Cette
273  *procedure est appellee par "Homographie_CrvMafCalculHomographie".
274  *
275  *
276  ****************************************************************************
277  * ENTREES :
278  * int Nb_pts : nombre de points
279  * double **pd : tableau des coordonnees des points desires
280  * couble **p : tableau des coordonnees des points courants
281  *
282  * SORTIES :
283  *
284  * double **H matrice d'homographie
285  * double epipole[3] epipole
286  *
287  ****************************************************************************
288  **/
289 void hlm3D(unsigned int nb_pts, vpMatrix &pd, vpMatrix &p, vpMatrix &H)
290 {
291  unsigned int pts_ref[4]; /*** definit lesquels des points de
292  l'image sont les points de reference***/
293 
294  vpMatrix M(3, 3);
295  vpMatrix Mdp(3, 3);
296  vpMatrix c(8, 2); // matrice des coeff C
297 
298  vpColVector d(8);
299  vpMatrix cp(2, 8); // matrice pseudo-inverse de C
300 
301  vpMatrix H_int(3, 3);
302  vpMatrix pn((nb_pts - 3), 3); // points courant nouveau repere
303 
304  vpMatrix pnd((nb_pts - 3), 3); // points derives nouveau repere
305 
306  /* preparation du changement de repere */
307  /****
308  comme plan de reference on choisit pour le moment
309  arbitrairement le plan contenant les points 1,2,3 du cinq
310  ****/
311  pts_ref[0] = 0;
312  pts_ref[1] = 1;
313  pts_ref[2] = 2;
314  pts_ref[3] = 0;
315 
316  /* changement de repere pour tous les points autres que les trois points de
317  * reference */
318 
319  changeFrame(pts_ref, nb_pts, pd, p, pnd, pn, M, Mdp);
320 
321  unsigned int cont_pts = nb_pts - 3;
322 
323  if (cont_pts < 5) {
324  // vpERROR_TRACE(" not enough point to compute the homography ... ");
325  throw(vpMatrixException(vpMatrixException::matrixError, "Not enough point to compute the homography"));
326  }
327 
328  unsigned int nc = 7; // nb cols
329 
330  /* Allocation matrice CtC */
331  vpMatrix CtC(nc, nc);
332 
333  /* Initialisation matrice CtC */
334  for (unsigned int i = 0; i < nc; ++i) {
335  for (unsigned int j = 0; j < nc; ++j) {
336  CtC[i][j] = 0.0;
337  }
338  }
339 
340  /* Allocation matrice M */
341  vpColVector C(nc); // Matrice des coefficients
342 
343  /* construction de la matrice M des coefficients dans le cas general */
344  /****
345  inconnues du nouveau algorithme
346  x1 = a ; x2 = b ; x3 = c ;
347  x4 = ex ; x5 = ey ; x6 = ez ;
348  qui deviennent apres changement :
349  v1 = x1*x6 ; v2 = x1*x5 ;
350  v3 = x2*x4 ; v4 = x2*x6 ;
351  v5 = x3*x5 ; v6 = x3*x4 ;
352  ****/
353  unsigned int cont = 0;
354  for (unsigned int i = 0; i < (nb_pts - 5); ++i) {
355  for (unsigned int j = i + 1; j < (nb_pts - 4); ++j) {
356  for (unsigned int k = j + 1; k < (nb_pts - 3); ++k) {
357  /* coeff a^2*b */
358  C[0] = (pn[i][2] * pn[j][2] * pn[k][1] * pnd[k][0] //
359  * ((pnd[j][0] * pnd[i][1]) - (pnd[j][1] * pnd[i][0]))) //
360  + (pn[i][2] * pn[k][2] * pn[j][1] * pnd[j][0] //
361  * ((pnd[i][0] * pnd[k][1]) - (pnd[i][1] * pnd[k][0]))) //
362  + (pn[j][2] * pn[k][2] * pn[i][1] * pnd[i][0] //
363  * ((pnd[k][0] * pnd[j][1]) - (pnd[k][1] * pnd[j][0]))); //
364  /* coeff a*b^2 */
365  C[1] = (pn[i][2] * pn[j][2] * pn[k][0] * pnd[k][1] //
366  * ((pnd[i][0] * pnd[j][1]) - (pnd[i][1] * pnd[j][0]))) //
367  + (pn[i][2] * pn[k][2] * pn[j][0] * pnd[j][1] //
368  * ((pnd[k][0] * pnd[i][1]) - (pnd[k][1] * pnd[i][0]))) //
369  + (pn[j][2] * pn[k][2] * pn[i][0] * pnd[i][1] //
370  * ((pnd[j][0] * pnd[k][1]) - (pnd[j][1] * pnd[k][0]))); //
371  /* coeff a^2 */
372  C[2] = (pn[i][1] * pn[k][1] * pn[j][2] * pnd[j][0] //
373  * ((pnd[k][2] * pnd[i][0]) - (pnd[k][0] * pnd[i][2]))) //
374  + (pn[i][1] * pn[j][1] * pn[k][2] * pnd[k][0] //
375  * ((pnd[i][2] * pnd[j][0]) - (pnd[i][0] * pnd[j][2]))) +
376  (pn[j][1] * pn[k][1] * pn[i][2] * pnd[i][0] //
377  * ((pnd[j][2] * pnd[k][0]) - (pnd[j][0] * pnd[k][2]))); //
378 
379  /* coeff b^2 */
380  C[3] = (pn[i][0] * pn[j][0] * pn[k][2] * pnd[k][1] //
381  * ((pnd[i][2] * pnd[j][1]) - (pnd[i][1] * pnd[j][2]))) //
382  + (pn[i][0] * pn[k][0] * pn[j][2] * pnd[j][1] //
383  * ((pnd[k][2] * pnd[i][1]) - (pnd[k][1] * pnd[i][2]))) //
384  + (pn[j][0] * pn[k][0] * pn[i][2] * pnd[i][1] //
385  * ((pnd[j][2] * pnd[k][1]) - (pnd[j][1] * pnd[k][2]))); //
386 
387  /* coeff a */
388  C[5] = (pn[i][1] * pn[j][1] * pn[k][0] * pnd[k][2] //
389  * ((pnd[i][0] * pnd[j][2]) - (pnd[i][2] * pnd[j][0]))) //
390  + (pn[i][1] * pn[k][1] * pn[j][0] * pnd[j][2] //
391  * ((pnd[k][0] * pnd[i][2]) - (pnd[k][2] * pnd[i][0]))) //
392  + (pn[j][1] * pn[k][1] * pn[i][0] * pnd[i][2] //
393  * ((pnd[j][0] * pnd[k][2]) - (pnd[j][2] * pnd[k][0]))); //
394  /* coeff b */
395  C[6] = (pn[i][0] * pn[j][0] * pn[k][1] * pnd[k][2] //
396  * ((pnd[i][1] * pnd[j][2]) - (pnd[i][2] * pnd[j][1]))) //
397  + (pn[i][0] * pn[k][0] * pn[j][1] * pnd[j][2] //
398  * ((pnd[k][1] * pnd[i][2]) - (pnd[k][2] * pnd[i][1]))) //
399  + (pn[j][0] * pn[k][0] * pn[i][1] * pnd[i][2] //
400  * ((pnd[j][1] * pnd[k][2]) - (pnd[j][2] * pnd[k][1]))); //
401  /* coeff a*b */
402  C[4] = (pn[i][0] * pn[k][1] * pn[j][2] //
403  * ((pnd[k][0] * pnd[j][1] * pnd[i][2]) - (pnd[j][0] * pnd[i][1] * pnd[k][2]))) //
404  + (pn[k][0] * pn[i][1] * pn[j][2] //
405  * ((pnd[j][0] * pnd[k][1] * pnd[i][2]) - (pnd[i][0] * pnd[j][1] * pnd[k][2]))) //
406  + (pn[i][0] * pn[j][1] * pn[k][2] //
407  * ((pnd[k][0] * pnd[i][1] * pnd[j][2]) - (pnd[j][0] * pnd[k][1] * pnd[i][2]))) //
408  + (pn[j][0] * pn[i][1] * pn[k][2] //
409  * ((pnd[i][0] * pnd[k][1] * pnd[j][2]) - (pnd[k][0] * pnd[j][1] * pnd[i][2]))) //
410  + (pn[k][0] * pn[j][1] * pn[i][2] //
411  * ((pnd[j][0] * pnd[i][1] * pnd[k][2]) - (pnd[i][0] * pnd[k][1] * pnd[j][2]))) //
412  + (pn[j][0] * pn[k][1] * pn[i][2] //
413  * ((pnd[i][0] * pnd[j][1] * pnd[k][2]) - (pnd[k][0] * pnd[i][1] * pnd[j][2]))); //
414 
415  cont = cont + 1;
416  /* construction de la matrice CtC */
417  for (unsigned int ii = 0; ii < nc; ++ii) {
418  for (unsigned int jj = ii; jj < nc; ++jj) {
419  CtC[ii][jj] = CtC[ii][jj] + (C[ii] * C[jj]);
420  }
421  }
422  }
423  }
424  }
425 
426  /* calcul de CtC */
427  for (unsigned int i = 0; i < nc; ++i) {
428  for (unsigned int j = i + 1; j < nc; ++j) {
429  CtC[j][i] = CtC[i][j];
430  }
431  }
432 
433  nc = 7; /* nombre de colonnes */
434 
435  /* Creation de matrice CtC termine */
436  /* Allocation matrice V */
437  vpMatrix V(nc, nc);
438  /*****
439  Preparation au calcul de la svd (pseudo-inverse)
440  pour obtenir une solution il faut au moins 5 equations independantes
441  donc il faut au moins la mise en correspondence de 3+5 points
442  *****/
443  vpColVector sv(nc); // Vecteur contenant les valeurs singulieres
444 
445  CtC.svd(sv, V);
446 
447  /*****
448  Il faut un controle sur le rang de la matrice !!
449  La meilleure solution est le vecteur de V associe
450  a la valeur singuliere la plus petite en valeur
451  absolu
452  *****/
453 
454  vpColVector svSorted = vpColVector::invSort(sv); // sorted singular value
455 
456  /*****
457  Parcours de la matrice ordonnee des valeurs singulieres
458  On note "cont_zeros" le nbre de valeurs quasi= a 0.
459  On note "vect" le rang de la plus petite valeur singliere
460  en valeur absolu
461  *****/
462 
463  unsigned int vect = 0;
464  int cont_zeros = 0;
465  cont = 0;
466  for (unsigned int j = 0; j < nc; ++j) {
467  if (std::fabs(sv[j] - svSorted[cont]) <= std::fabs(vpMath::maximum(sv[j], svSorted[cont]))) {
468  vect = j;
469  }
470  if (std::fabs(sv[j] / svSorted[nc - 1]) < eps) {
471  cont_zeros = cont_zeros + 1;
472  }
473  }
474 
475  if (cont_zeros > 5) {
476  hlm2D(nb_pts, pd, p, H);
477  }
478  else {
479 
480  // estimation de a = 1,b,c ; je cherche le min de somme(i=1:n)
481  // (0.5*(ei)^2)
482  // e1 = V[1][.] * b - V[3][.] = 0 ;
483  // e2 = V[2][.] * c - V[3][.] = 0 ;
484  // e3 = V[2][.] * b - V[3][.] * c = 0 ;
485  // e4 = V[4][.] * b - V[5][.] = 0 ;
486  // e5 = V[4][.] * c - V[6][.] = 0 ;
487  // e6 = V[6][.] * b - V[5][.] * c = 0 ;
488  // e7 = V[7][.] * b - V[8][.] = 0 ;
489  // e8 = V[7][.] * c - V[9][.] = 0 ;
490  d[0] = V[2][vect];
491  d[1] = V[4][vect];
492  d[2] = V[1][vect];
493  d[3] = V[0][vect];
494  d[4] = V[3][vect];
495  d[5] = V[4][vect];
496  d[6] = V[0][vect];
497  d[7] = V[1][vect];
498 
499  c[0][0] = V[5][vect];
500  c[0][1] = 0.0;
501  c[1][0] = V[6][vect];
502  c[1][1] = 0.0;
503  c[2][0] = V[3][vect];
504  c[2][1] = 0.0;
505  c[3][0] = V[4][vect];
506  c[3][1] = 0.0;
507  c[4][0] = 0.0;
508  c[4][1] = V[6][vect];
509  c[5][0] = 0.0;
510  c[5][1] = V[5][vect];
511  c[6][0] = 0.0;
512  c[6][1] = V[2][vect];
513  c[7][0] = 0.0;
514  c[7][1] = V[4][vect];
515 
517  cp = c.pseudoInverse(1e-6);
518 
519  vpColVector H_nr(3), temp; // Homographie diagonale
520  // Multiplication de la matrice H_nr par le vecteur cp
521  temp = cp * d;
522 
523  H_nr[0] = temp[0];
524  H_nr[1] = temp[1];
525  H_nr[2] = 1.0;
526 
527  vpMatrix T(9, 3);
528  T = 0;
529  T[0][0] = -V[1][vect];
530  T[0][1] = V[0][vect];
531  T[1][0] = V[4][vect];
532  T[1][2] = -V[2][vect];
533  T[2][0] = -V[6][vect];
534  T[2][1] = V[2][vect];
535  T[3][0] = V[6][vect];
536  T[3][2] = -V[0][vect];
537  T[4][0] = -V[3][vect];
538  T[4][1] = V[6][vect];
539  T[5][0] = V[3][vect];
540  T[5][2] = -V[1][vect];
541  T[6][0] = -V[5][vect];
542  T[6][1] = V[4][vect];
543  T[7][0] = V[5][vect];
544  T[7][2] = -V[6][vect];
545  T[8][1] = -V[5][vect];
546  T[8][2] = V[2][vect];
547 
548  vpMatrix Hd(3, 3); // diag(gu,gv,gw)
549  const unsigned int val_3 = 3;
550  for (unsigned int i = 0; i < val_3; ++i) {
551  Hd[i][i] = H_nr[i];
552  }
553 
554  // H is equal to M diag(gu,gv,gw) M*-1
555  H = M * Hd * Mdp;
556  }
557 }
558 
559 void hlm(unsigned int q_cible, const std::vector<double> &xm, const std::vector<double> &ym,
560  const std::vector<double> &xmi, const std::vector<double> &ymi, vpMatrix &H)
561 {
562  unsigned int nbpt = static_cast<unsigned int>(xm.size());
563 
564  /****
565  on regarde si il y a au moins un point mais pour l'homographie
566  il faut au moins quatre points
567  ****/
568  vpMatrix pd(nbpt, 3);
569  vpMatrix p(nbpt, 3);
570 
571  for (unsigned int i = 0; i < nbpt; ++i) {
572  /****
573  on assigne les points fournies par la structure robot
574  pour la commande globale
575  ****/
576  pd[i][0] = xmi[i];
577  pd[i][1] = ymi[i];
578  pd[i][2] = 1.0;
579  p[i][0] = xm[i];
580  p[i][1] = ym[i];
581  p[i][2] = 1.0;
582  }
583 
584  switch (q_cible) {
585  case 1:
586  case 2:
587  /* La cible est planaire de type points */
588 
589  hlm2D(nbpt, pd, p, H);
590 
591  break;
592  case 3: /* cible non planaire : chateau */
593  /* cible non planaire de type points */
594  hlm3D(nbpt, pd, p, H);
595  break;
596  default:
597  break;
598  } /* fin switch */
599 
600 } /* fin procedure calcul_homogaphie */
601 
602 } // end namespace
603 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
604 
605 void vpHomography::HLM(const std::vector<double> &xb, const std::vector<double> &yb, const std::vector<double> &xa,
606  const std::vector<double> &ya, bool isplanar, vpHomography &aHb)
607 {
608  unsigned int n = static_cast<unsigned int>(xb.size());
609  if ((yb.size() != n) || (xa.size() != n) || (ya.size() != n)) {
610  throw(vpException(vpException::dimensionError, "Bad dimension for HLM shomography estimation"));
611  }
612 
613  // 4 point are required
614  if (n < 4) {
615  throw(vpException(vpException::fatalError, "There must be at least 4 matched points"));
616  }
617 
618  // The reference plane is the plane build from the 3 first points.
619  unsigned int q_cible;
620  vpMatrix H; // matrice d'homographie en metre
621 
622  if (isplanar) {
623  q_cible = 1;
624  }
625  else {
626  q_cible = 3;
627  }
628 
629  hlm(q_cible, xa, ya, xb, yb, H);
630 
631  aHb = H;
632 }
633 
634 END_VISP_NAMESPACE
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
static vpColVector invSort(const vpColVector &v)
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
@ fatalError
Fatal error.
Definition: vpException.h:72
Implementation of an homography and operations on homographies.
Definition: vpHomography.h:174
static void HLM(const std::vector< double > &xb, const std::vector< double > &yb, const std::vector< double > &xa, const std::vector< double > &ya, bool isplanar, vpHomography &aHb)
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:254
error that can be emitted by the vpMatrix class and its derivatives
@ matrixError
Matrix operation error.
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
void svd(vpColVector &w, vpMatrix &V)
vpMatrix pseudoInverse(double svThreshold=1e-6) const