Visual Servoing Platform  version 3.0.0
vpMe.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
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 http://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  * Moving edges.
32  *
33  * Authors:
34  * Eric Marchand
35  * Andrew Comport
36  *
37  *****************************************************************************/
38 
46 #include <visp3/me/vpMe.h>
47 #include <visp3/core/vpColVector.h>
48 #include <visp3/core/vpMath.h>
49 #include <stdlib.h>
50 #ifndef DOXYGEN_SHOULD_SKIP_THIS
51 
52 
53 struct point
54 {
55  double x ;
56  double y ;
57 } ;
58 
59 struct droite
60 {
61  double a ;
62  double b ;
63  double c ;
64 } ;
65 
66 
67 
68 
69 
70 
71 
72 template <class Type>
73 inline void
74 permute(Type & a, Type & b)
75 {
76  Type t = a;
77  a = b;
78  b = t;
79 }
80 
81 static droite
82 droite_cartesienne(point P, point Q)
83 {
84  droite PQ;
85 
86  PQ.a = P.y-Q.y;
87  PQ.b = Q.x-P.x;
88  PQ.c = Q.y*P.x - Q.x*P.y;
89 
90  return(PQ);
91 }
92 
93 
94 
95 static point
96 point_intersection(droite D1, droite D2)
97 {
98  point I;
99  double det; // determinant des 2 vect.normaux
100 
101  det = (D1.a*D2.b - D2.a*D1.b); // interdit D1,D2 paralleles
102  I.x = (D2.c*D1.b - D1.c*D2.b)/det;
103  I.y = (D1.c*D2.a - D2.c*D1.a)/det;
104 
105  return(I);
106 }
107 
108 static void
109 recale(point & P,
110  double Xmin, double Ymin, double Xmax, double Ymax)
111 {
112  if(vpMath::equal(P.x,Xmin))
113  P.x=Xmin; // a peu pres => exactement !
114  if(vpMath::equal(P.x,Xmax))
115  P.x=Xmax;
116 
117  if(vpMath::equal(P.y,Ymin))
118  P.y=Ymin;
119  if(vpMath::equal(P.y,Ymax))
120  P.y=Ymax;
121 }
122 
123 
124 static void
125 permute(point &A, point &B)
126 {
127  point C ;
128 
129  if (A.x>B.x) // fonction sans doute a tester...
130  {
131  C = A ;
132  A = B ;
133  B = C ;
134  }
135 }
136 
137 
138 // vrai si partie visible
139 static bool
140 clipping (point A, point B,
141  double Xmin, double Ymin, double Xmax, double Ymax,
142  point & Ac , point & Bc )// resultat: A,B clippes
143 {
144  droite AB, D[4];
145  D[0].a = 1; D[0].b = 0; D[0].c = -Xmin;
146  D[1].a = 1; D[1].b = 0; D[1].c = -Xmax;
147  D[2].a = 0; D[2].b = 1; D[2].c = -Ymin;
148  D[3].a = 0; D[3].b = 1; D[3].c = -Ymax;
149 
150  point P[2];
151  P[0]=A; P[1]=B;
152  int code_P[2], // codes de P[n]
153  i, bit_i, // i -> (0000100...)
154  n;
155 
156  AB = droite_cartesienne(A,B);
157 
158  for ( ; ; ) // 2 sorties directes internes
159  {
160  // CALCULE CODE DE VISIBILITE (Sutherland & Sproul)
161  // ================================================
162  for(n=0; n<2; n++)
163  {
164  code_P[n] = 0000;
165 
166  if( P[n].x < Xmin )
167  code_P[n] |= 1; // positionne bit0
168  if( P[n].x > Xmax )
169  code_P[n] |= 2; // .. bit1
170  if( P[n].y < Ymin )
171  code_P[n] |= 4; // .. bit2
172  if( P[n].y > Ymax )
173  code_P[n] |= 8; // .. bit3
174  }
175 
176 
177  // 2 CAS OU L'ON PEUT CONCLURE => sortie
178  // =====================================
179  if((code_P[0] | code_P[1])==0000) // Aucun bit a 1
180  /* NE TRIE PLUS LE RESULTAT ! S_relative() en tient compte
181  { if(P[0].x < P[1].x) // Rend le couple de points
182  { Ac=P[0]; Bc=P[1]; } // clippes (ordonnes selon
183  else { Ac=P[1]; Bc=P[0]; } // leur abscisse x)
184  */
185  {
186  Ac=P[0]; Bc=P[1];
187  if(vpMath::equal(Ac.x,Bc.x) && vpMath::equal(Ac.y,Bc.y))
188  return(false); // AB = 1 point = invisible
189  else
190  return(true); // Partie de AB clippee visible!
191  }
192 
193  if((code_P[0] & code_P[1])!=0000) // au moins 1 bit commun
194  {
195  return(false); // AB completement invisible!
196  }
197 
198 
199  // CAS GENERAL (on sait que code_P[0 ou 1] a au moins un bit a 1
200  // - clippe le point P[n] qui sort de la fenetre (coupe Droite i)
201  // - reboucle avec le nouveau couple de points
202  // ================================================================
203  if(code_P[0] != 0000)
204  {
205  n=0; // c'est P[0] qu'on clippera
206  for(i=0,bit_i=1; !(code_P[0] & bit_i); i++,bit_i<<=1){;}
207  }
208  else
209  {
210  n=1; // c'est P[1] qu'on clippera
211  for(i=0,bit_i=1; !(code_P[1] & bit_i); i++,bit_i<<=1){;}
212  }
213 
214  P[n] = point_intersection(AB,D[i]); // clippe le point concerne
215 
216 
217  // RECALE EXACTEMENT LE POINT (calcul flottant => arrondi)
218  // AFIN QUE LE CALCUL DES CODES NE BOUCLE PAS INDEFINIMENT
219  // =======================================================
220  recale(P[n], Xmin,Ymin,Xmax,Ymax);
221 
222  }
223 
224 }
225 
226 
227 // calcule la surface relative des 2 portions definies
228 // par le segment PQ sur le carre Xmin,Ymin,Xmax,Ymax
229 // Rem : P,Q tries sur x, et donc seulement 6 cas
230 static double
231 S_relative(point P, point Q,
232  double Xmin, double Ymin, double Xmax, double Ymax)
233 {
234 
235  if(Q.x < P.x) // tri le couple de points
236  permute(P,Q); // selon leur abscisse x
237 
238 
239 
240  recale(P, Xmin,Ymin,Xmax,Ymax); // permet des calculs de S_relative
241  recale(Q, Xmin,Ymin,Xmax,Ymax); // moins approximatifs.
242 
243  //if(P.x==Xmin && Q.x==Xmax)
244  if((std::fabs(P.x-Xmin) <= vpMath::maximum(std::fabs(P.x),std::fabs(Xmin))*std::numeric_limits<double>::epsilon())
245  &&
246  (std::fabs(Q.x-Xmax) <= vpMath::maximum(std::fabs(Q.x),std::fabs(Xmax))*std::numeric_limits<double>::epsilon()))
247  return( fabs(Ymax+Ymin-P.y-Q.y) );
248 
249  //if( (P.y==Ymin && Q.y==Ymax) ||
250  // (Q.y==Ymin && P.y==Ymax))
251  if( ( (std::fabs(P.y-Ymin) <= vpMath::maximum(std::fabs(P.y),std::fabs(Ymin))*std::numeric_limits<double>::epsilon())
252  &&
253  (std::fabs(Q.y-Ymax) <= vpMath::maximum(std::fabs(Q.y),std::fabs(Ymax))*std::numeric_limits<double>::epsilon()) )
254  ||
255  ( (std::fabs(Q.y-Ymin) <= vpMath::maximum(std::fabs(Q.y),std::fabs(Ymin))*std::numeric_limits<double>::epsilon())
256  &&
257  (std::fabs(P.y-Ymax) <= vpMath::maximum(std::fabs(P.y),std::fabs(Ymax))*std::numeric_limits<double>::epsilon()) ) )
258  return( fabs(Xmax+Xmin-P.x-Q.x) );
259 
260  //if( P.x==Xmin && Q.y==Ymax )
261  if( std::fabs(P.x-Xmin) <= vpMath::maximum(std::fabs(P.x),std::fabs(Xmin))*std::numeric_limits<double>::epsilon()
262  &&
263  std::fabs(Q.y-Ymax) <= vpMath::maximum(std::fabs(Q.y),std::fabs(Ymax))*std::numeric_limits<double>::epsilon() )
264  return( 1-(Ymax-P.y)*(Q.x-Xmin) );
265  //if( P.x==Xmin && Q.y==Ymin )
266  if( std::fabs(P.x-Xmin) <= vpMath::maximum(std::fabs(P.x),std::fabs(Xmin))*std::numeric_limits<double>::epsilon()
267  &&
268  std::fabs(Q.y-Ymin) <= vpMath::maximum(std::fabs(Q.y),std::fabs(Ymin))*std::numeric_limits<double>::epsilon() )
269  return( 1-(P.y-Ymin)*(Q.x-Xmin) );
270  //if( P.y==Ymin && Q.x==Xmax )
271  if( std::fabs(P.y-Ymin) <= vpMath::maximum(std::fabs(P.y),std::fabs(Ymin))*std::numeric_limits<double>::epsilon()
272  && std::fabs(Q.x-Xmax) <= vpMath::maximum(std::fabs(Q.x),std::fabs(Xmax))*std::numeric_limits<double>::epsilon() )
273  return( 1-(Xmax-P.x)*(Q.y-Ymin) );
274  //if( P.y==Ymax && Q.x==Xmax )
275  if( std::fabs(P.y-Ymax) <= vpMath::maximum(std::fabs(P.y),std::fabs(Ymax))*std::numeric_limits<double>::epsilon()
276  && std::fabs(Q.x-Xmax) <= vpMath::maximum(std::fabs(Q.x),std::fabs(Xmax))*std::numeric_limits<double>::epsilon())
277  return( 1-(Xmax-P.x)*(Ymax-Q.y) );
278 
279 
280  printf("utils_ecm: ERREUR dans S_relative (%f,%f) (%f,%f) %f %f %f %f\n",
281  P.x,P.y,Q.x,Q.y,Xmin,Ymin,Xmax,Ymax);
282  exit(-1); // DEBUG Stoppe net l'execution
283 }
284 
285 
286 static void
287 calcul_masques(vpColVector &angle, // definitions des angles theta
288  unsigned int n, // taille masques (PAIRE ou IMPAIRE Ok)
289  vpMatrix *M) // resultat M[theta](n,n)
290 {
291  // Le coef |a| = |1/2n| n'est pas incorpore dans M(i,j) (=> que des int)
292 
293  unsigned int i_theta, // indice (boucle sur les masques)
294  i,j; // indices de boucle sur M(i,j)
295  double X,Y, // point correspondant/centre du masque
296  theta, cos_theta, sin_theta, tan_theta,
297  moitie = ((double)n)/2.0; // moitie REELLE du masque
298  point P1,Q1,P,Q; // clippe Droite(theta) P1,Q1 -> P,Q
299  int sgn; // signe de M(i,j)
300  double v; // ponderation de M(i,j)
301 
302  unsigned int nb_theta = angle.getRows() ;
303 
304  for(i_theta=0; i_theta<nb_theta; i_theta++)
305  {
306  theta = M_PI/180*angle[i_theta]; // indice i -> theta(i) en radians
307  // angle[] dans [0,180[
308  cos_theta = cos(theta); // vecteur directeur de l'ECM
309  sin_theta = sin(theta); // associe au masque
310 
311  // PRE-CALCULE 2 POINTS DE D(theta) BIEN EN DEHORS DU MASQUE
312  // =========================================================
313  //if( angle[i_theta]==90 ) // => tan(theta) infinie !
314  if( std::fabs(angle[i_theta]-90) <= vpMath::maximum(std::fabs(angle[i_theta]), 90.)*std::numeric_limits<double>::epsilon() ) // => tan(theta) infinie !
315  {
316  P1.x=0; P1.y=-(int)n;
317  Q1.x=0; Q1.y= n;
318  }
319  else
320  {
321  tan_theta = sin_theta/cos_theta; // pente de la droite D(theta)
322  P1.x=-(int)n; P1.y=tan_theta*(-(int)n);
323  Q1.x=n; Q1.y=tan_theta*n;
324  }
325 
326  // CALCULE MASQUE M(theta)
327  // ======================
328  M[i_theta].resize(n,n); // allocation (si necessaire)
329 
330  for(i=0,Y=-moitie+0.5 ; i<n ; i++,Y++)
331  {
332  for(j=0,X=-moitie+0.5 ; j<n ; j++,X++)
333  {
334  // produit vectoriel dir_droite*(X,Y)
335  sgn = vpMath::sign(cos_theta*Y - sin_theta*X);
336 
337  // Resultat = P,Q
338  if( clipping(P1,Q1, X-0.5,Y-0.5,X+0.5,Y+0.5, P,Q) )
339  {
340  // v dans [0,1]
341  v=S_relative(P,Q, X-0.5,Y-0.5,X+0.5,Y+0.5);
342  }
343  else
344  v=1; // PQ ne coupe pas le pixel(i,j)
345 
346  M[i_theta][i][j] = vpMath::round(100*sgn*v);
347 
348  // 2 chiffres significatifs
349  // M(i,j) sans incorporer le coef a
350  }
351  }
352  }
353 
354 }
355 
356 #endif
357 
363 void
365 {
366 
367  if (mask != NULL)
368  delete [] mask;
369 
370  mask = new vpMatrix[n_mask] ;
371 
372  vpColVector angle(n_mask) ;
373 
374  unsigned int angle_pas ;
375  angle_pas = 180 / n_mask ;
376 
377  unsigned int k =0 ;
378  for (unsigned int i = 0 ; /* i < 180, */ k < n_mask ; i += angle_pas)
379  angle[k++] = i ;
380 
381  calcul_masques(angle, mask_size, mask ) ;
382 
383 }
384 
385 
386 
387 void
389 {
390 
391  std::cout<< std::endl ;
392  std::cout<<"Moving edges settings " <<std::endl ;
393  std::cout<< std::endl ;
394  std::cout<<" Size of the convolution masks...."<<mask_size<<"x"<<mask_size<<" pixels"<<std::endl ;
395  std::cout<<" Number of masks.................."<<n_mask<<" "<<std::endl ;
396  std::cout<<" Query range +/- J................"<<range<<" pixels "<<std::endl ;
397  std::cout<<" Likelihood test ratio............"<<threshold<<std::endl ;
398  std::cout<<" Contrast tolerance +/-..........."<< mu1 * 100<<"% and "<<mu2 * 100<<"% "<<std::endl ;
399  std::cout<<" Sample step......................"<<sample_step<<" pixels"<<std::endl ;
400  std::cout<<" Strip............................"<<strip<<" pixels "<<std::endl ;
401  std::cout<<" Min_Samplestep..................."<<min_samplestep<<" pixels "<<std::endl ;
402 }
403 
405  : threshold(1500), mu1(0.5), mu2(0.5), min_samplestep(4), anglestep(1), mask_sign(0),
406  range(4), sample_step(10), ntotal_sample(0), points_to_track(500), mask_size(5),
407  n_mask(180), strip(2), mask(NULL)
408 {
409  //ntotal_sample = 0; // not sure that it is used
410  //points_to_track = 500; // not sure that it is used
411  anglestep = (180 / n_mask) ;
412 
413  initMask() ;
414 }
415 
416 vpMe::vpMe(const vpMe &me)
417  : threshold(1500), mu1(0.5), mu2(0.5), min_samplestep(4), anglestep(1), mask_sign(0),
418  range(4), sample_step(10), ntotal_sample(0), points_to_track(500), mask_size(5),
419  n_mask(180), strip(2), mask(NULL)
420 {
421  *this = me;
422 }
423 
424 const
426 {
427  if (mask != NULL) {
428  delete [] mask;
429  mask = NULL ;
430  }
431  threshold = me.threshold ;
432  mu1 = me.mu1 ;
433  mu2 = me.mu2 ;
435  anglestep = me.anglestep ;
436  mask_size = me.mask_size ;
437  n_mask = me.n_mask ;
438  mask_sign = me.mask_sign ;
439  range = me.range ;
440  sample_step = me.sample_step ;
443  strip = me.strip ;
444 
445  initMask() ;
446  return *this;
447 }
448 
450 {
451  if (mask != NULL)
452  {
453  delete [] mask ;
454  mask = NULL;
455  }
456 }
457 
458 
459 void
460 vpMe::setMaskNumber(const unsigned int &n)
461 {
462  n_mask = n ;
463  anglestep = 180 / n_mask ;
464  initMask() ;
465 }
466 
467 void
468 vpMe::setMaskSize(const unsigned int &s)
469 {
470  mask_size = s ;
471  initMask() ;
472 }
473 
474 
475 
476 
double threshold
Definition: vpMe.h:66
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:92
const vpMe & operator=(const vpMe &me)
Definition: vpMe.cpp:425
void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify=true)
Definition: vpArray2D.h:167
vpMatrix * mask
Definition: vpMe.h:86
unsigned int range
Definition: vpMe.h:72
void setMaskNumber(const unsigned int &a)
Definition: vpMe.cpp:460
static bool equal(double x, double y, double s=0.001)
Definition: vpMath.h:297
int ntotal_sample
Distance between sampled points (in pixels)
Definition: vpMe.h:74
Definition: vpMe.h:59
int mask_sign
Definition: vpMe.h:71
static int round(const double x)
Definition: vpMath.h:248
void initMask()
Definition: vpMe.cpp:364
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:141
unsigned int mask_size
convolution masks' size in pixels (masks are square),
Definition: vpMe.h:77
void setMaskSize(const unsigned int &a)
Definition: vpMe.cpp:468
int points_to_track
Definition: vpMe.h:75
virtual ~vpMe()
Definition: vpMe.cpp:449
vpMe()
Array of matrices defining the different masks (one for every angle step).
Definition: vpMe.cpp:404
unsigned int getRows() const
Return the number of rows of the 2D array.
Definition: vpArray2D.h:152
double min_samplestep
Contrast continuity parameter (right boundary)
Definition: vpMe.h:69
unsigned int n_mask
the number of convolution masks available for tracking ; defines resolution.
Definition: vpMe.h:79
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
int strip
Definition: vpMe.h:84
double mu1
Likelihood ratio threshold.
Definition: vpMe.h:67
double mu2
Contrast continuity parameter (left boundary)
Definition: vpMe.h:68
void print()
Definition: vpMe.cpp:388
unsigned int anglestep
Definition: vpMe.h:70
static int sign(double x)
Definition: vpMath.h:266
double sample_step
Seek range - on both sides of the reference pixel.
Definition: vpMe.h:73