Visual Servoing Platform  version 3.1.0
vpMeSite.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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  * Moving edges.
33  *
34  * Authors:
35  * Eric Marchand
36  * Andrew Comport
37  * Aurelien Yol
38  *
39  *****************************************************************************/
40 
46 #include <cmath> // std::fabs
47 #include <limits> // numeric_limits
48 #include <stdlib.h>
49 #include <visp3/core/vpTrackingException.h>
50 #include <visp3/me/vpMe.h>
51 #include <visp3/me/vpMeSite.h>
52 
53 #ifndef DOXYGEN_SHOULD_SKIP_THIS
54 static bool horsImage(int i, int j, int half, int rows, int cols)
55 {
56  // return((i < half + 1) || ( i > (rows - half - 3) )||(j < half + 1) || (j
57  // > (cols - half - 3) )) ;
58  int half_1 = half + 1;
59  int half_3 = half + 3;
60  // return((i < half + 1) || ( i > (rows - half - 3) )||(j < half + 1) || (j
61  // > (cols - half - 3) )) ;
62  return ((0 < (half_1 - i)) || ((i - rows + half_3) > 0) || (0 < (half_1 - j)) || ((j - cols + half_3) > 0));
63 }
64 #endif
65 
67 {
68  // Site components
69  alpha = 0.0;
70  convlt = 0.0;
71  weight = -1;
72 
73  selectDisplay = NONE;
74 
75  // Pixel components
76  i = 0;
77  j = 0;
78  v = 0;
79  ifloat = i;
80  jfloat = j;
81  i_1 = 0;
82  j_1 = 0;
83 
84  mask_sign = 1;
85 
86  normGradient = 0;
87 
88  state = NO_SUPPRESSION;
89 
90 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
91  suppress = 0;
92 #endif
93 }
94 
96  : i(0), j(0), i_1(0), j_1(0), ifloat(0), jfloat(0), v(0), mask_sign(1), alpha(0.), convlt(0.), normGradient(0),
97  weight(1), selectDisplay(NONE), state(NO_SUPPRESSION)
98 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
99  ,
100  suppress(0)
101 #endif
102 {
103 }
104 
105 vpMeSite::vpMeSite(double ip, double jp)
106  : i(0), j(0), i_1(0), j_1(0), ifloat(0), jfloat(0), v(0), mask_sign(1), alpha(0.), convlt(0.), normGradient(0),
107  weight(1), selectDisplay(NONE), state(NO_SUPPRESSION)
108 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
109  ,
110  suppress(0)
111 #endif
112 {
113  i = vpMath::round(ip);
114  j = vpMath::round(jp);
115  ifloat = ip;
116  jfloat = jp;
117 }
118 
123  : i(0), j(0), i_1(0), j_1(0), ifloat(0), jfloat(0), v(0), mask_sign(1), alpha(0.), convlt(0.), normGradient(0),
124  weight(1), selectDisplay(NONE), state(NO_SUPPRESSION)
125 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
126  ,
127  suppress(0)
128 #endif
129 {
130  *this = mesite;
131 }
132 
133 // More an Update than init
134 // For points in meter form (to avoid approximations)
135 void vpMeSite::init(double ip, double jp, double alphap)
136 {
137  // Note: keep old value of convlt, suppress and contrast
138  selectDisplay = NONE;
139 
140  ifloat = ip;
141  i = vpMath::round(ip);
142  jfloat = jp;
143  j = vpMath::round(jp);
144  alpha = alphap;
145  mask_sign = 1;
146 
147  v = 0;
148  i_1 = 0;
149  j_1 = 0;
150 }
151 
152 // initialise with convolution
153 void vpMeSite::init(double ip, double jp, double alphap, double convltp)
154 {
155  selectDisplay = NONE;
156  ifloat = ip;
157  i = (int)ip;
158  jfloat = jp;
159  j = (int)jp;
160  alpha = alphap;
161  convlt = convltp;
162  mask_sign = 1;
163 
164  v = 0;
165  i_1 = 0;
166  j_1 = 0;
167 }
168 // initialise with convolution and sign
169 void vpMeSite::init(double ip, double jp, double alphap, double convltp, int sign)
170 {
171  selectDisplay = NONE;
172  ifloat = ip;
173  i = (int)ip;
174  jfloat = jp;
175  j = (int)jp;
176  alpha = alphap;
177  convlt = convltp;
178  mask_sign = sign;
179 
180  v = 0;
181  i_1 = 0;
182  j_1 = 0;
183 }
184 
186 {
187  i = m.i;
188  j = m.j;
189  i_1 = m.i_1;
190  j_1 = m.j_1;
191  ifloat = m.ifloat;
192  jfloat = m.jfloat;
193  v = m.v;
194  mask_sign = m.mask_sign;
195  alpha = m.alpha;
196  convlt = m.convlt;
198  weight = m.weight;
199  selectDisplay = m.selectDisplay;
200  state = m.state;
201 
202 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
203  suppress = m.suppress;
204 #endif
205 
206  return *this;
207 }
208 
209 // ===================================================================
217 // ===================================================================
218 
220 {
221 
222  int k;
223 
224  int n;
225  vpMeSite *list_query_pixels;
226  list_query_pixels = NULL;
227 
228  unsigned int range_ = static_cast<unsigned int>(range);
229  // Size of query list includes the point on the line
230  list_query_pixels = new vpMeSite[2 * range_ + 1];
231 
232  // range : +/- the range within which the pixel's
233  // correspondent will be sought
234 
235  double salpha = sin(alpha);
236  double calpha = cos(alpha);
237  n = 0;
238  vpImagePoint ip;
239 
240  for (k = -range; k <= range; k++) {
241  double ii = (ifloat + k * salpha);
242  double jj = (jfloat + k * calpha);
243 
244  // Display
245  if ((selectDisplay == RANGE_RESULT) || (selectDisplay == RANGE)) {
246  ip.set_i(ii);
247  ip.set_j(jj);
249  }
250 
251  // Copy parent's convolution
252  vpMeSite pel;
253  pel.init(ii, jj, alpha, convlt, mask_sign);
254  pel.setDisplay(selectDisplay); // Display
255 
256  // Add site to the query list
257  list_query_pixels[n] = pel;
258  n++;
259  }
260 
261  return (list_query_pixels);
262 }
263 
264 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
265 // ===================================================================
273 // ===================================================================
274 void vpMeSite::getSign(const vpImage<unsigned char> &I, const int range)
275 {
276 
277  int k;
278 
279  double salpha = sin(alpha);
280  double calpha = cos(alpha);
281 
282  // First extremity
283  k = -range;
284  unsigned int i1 = static_cast<unsigned int>(vpMath::round(ifloat + k * salpha));
285  unsigned int j1 = static_cast<unsigned int>(vpMath::round(jfloat + k * calpha));
286 
287  // Second extremity
288  k = range;
289  unsigned int i2 = static_cast<unsigned int>(vpMath::round(ifloat + k * salpha));
290  unsigned int j2 = static_cast<unsigned int>(vpMath::round(jfloat + k * calpha));
291 
292  // TODO: Here check if i1,j1,i2,j2 > 0 else ??
293  if (I[i1][j1] > I[i2][j2])
294  mask_sign = 1;
295  else
296  mask_sign = -1;
297 }
298 #endif
299 
300 // Specific function for ME
302 {
303  int half;
304  int height_ = static_cast<int>(I.getHeight());
305  int width_ = static_cast<int>(I.getWidth());
306 
307  double conv = 0.0;
308  unsigned int msize = me->getMaskSize();
309  half = (static_cast<int>(msize) - 1) >> 1;
310 
311  if (horsImage(i, j, half + me->getStrip(), height_, width_)) {
312  conv = 0.0;
313  i = 0;
314  j = 0;
315  } else {
316  // Calculate tangent angle from normal
317  double theta = alpha + M_PI / 2;
318  // Move tangent angle to within 0->M_PI for a positive
319  // mask index
320  while (theta < 0)
321  theta += M_PI;
322  while (theta > M_PI)
323  theta -= M_PI;
324 
325  // Convert radians to degrees
326  int thetadeg = vpMath::round(theta * 180 / M_PI);
327 
328  if (abs(thetadeg) == 180) {
329  thetadeg = 0;
330  }
331 
332  unsigned int index_mask = (unsigned int)(thetadeg / (double)me->getAngleStep());
333 
334  unsigned int i_ = static_cast<unsigned int>(i);
335  unsigned int j_ = static_cast<unsigned int>(j);
336  unsigned int half_ = static_cast<unsigned int>(half);
337 
338  unsigned int ihalf = i_ - half_;
339  unsigned int jhalf = j_ - half_;
340 
341  for (unsigned int a = 0; a < msize; a++) {
342  unsigned int ihalfa = ihalf + a;
343  for (unsigned int b = 0; b < msize; b++) {
344  conv += mask_sign * me->getMask()[index_mask][a][b] *
345  // I(i-half+a,j-half+b) ;
346  I(ihalfa, jhalf + b);
347  }
348  }
349  }
350 
351  return (conv);
352 }
353 
362 void vpMeSite::track(const vpImage<unsigned char> &I, const vpMe *me, const bool test_contraste)
363 {
364  // vpMeSite *list_query_pixels ;
365  // int max_rank =0 ;
366  // int max_rank1=0 ;
367  // int max_rank2 = 0;
368  // double convolution = 0 ;
369  // double max_convolution = 0 ;
370  // double max = 0 ;
371  // double contraste = 0;
372  // // vpDisplay::display(I) ;
373  // // vpERROR_TRACE("getclcik %d",me->getRange()) ;
374  // // vpDisplay::getClick(I) ;
375  //
376  // // range = +/- range of pixels within which the correspondent
377  // // of the current pixel will be sought
378  // int range = me->getRange() ;
379  //
380  // // std::cout << i << " " << j<<" " << range << " " << suppress <<
381  // std::endl ; list_query_pixels = getQueryList(I, range) ;
382  //
383  // double contraste_max = 1 + me->getMu2();
384  // double contraste_min = 1 - me->getMu1();
385  //
386  // // array in which likelihood ratios will be stored
387  // double *likelihood= new double[ 2 * range + 1 ] ;
388  //
389  // int ii_1 = i ;
390  // int jj_1 = j ;
391  // i_1 = i ;
392  // j_1 = j ;
393  // double threshold;
394  // threshold = me->getThreshold();
395  //
396  // // std::cout <<"---------------------"<<std::endl ;
397  // for(int n = 0 ; n < 2 * range + 1 ; n++)
398  // {
399  //
400  // // convolution results
401  // convolution = list_query_pixels[n].convolution(I, me) ;
402  //
403  // // luminance ratio of reference pixel to potential correspondent
404  // pixel
405  // // the luminance must be similar, hence the ratio value should
406  // // lay between, for instance, 0.5 and 1.5 (parameter tolerance)
407  // if( test_contraste )
408  // {
409  // // Include this to eliminate temporal calculation
410  // if (convlt==0)
411  // {
412  // std::cout << "vpMeSite::track : Division by zero convlt = 0" <<
413  // std::endl ; delete []list_query_pixels ; delete
414  // []likelihood;
415  // throw(vpTrackingException(vpTrackingException::initializationError,
416  // "Division by zero")) ;
417  // }
418  //
419  // // contraste = fabs(convolution / convlt) ;
420  // contraste = convolution / convlt ;
421  // // likelihood ratios
422  // if((contraste > contraste_min) && (contraste < contraste_max))
423  // likelihood[n] = fabs(convolution + convlt ) ;
424  // else
425  // likelihood[n] = 0 ;
426  // }
427  // else
428  // likelihood[n] = fabs(2*convolution) ;
429  //
430  //
431  // // establishment of the maximal likelihood ratios's rank
432  // // in the array, the value of the likelihood ratio can now be
433  // // referenced by its rank in the array
434  // if (likelihood[n] > max)
435  // {
436  // max_convolution= convolution;
437  // max = likelihood[n] ;
438  // max_rank = n ;
439  // max_rank2 = max_rank1;
440  // max_rank1 = max_rank;
441  // }
442  //
443  // }
444  //
445  // // test on the likelihood threshold if threshold==-1 then
446  // // the me->threshold is selected
447  //
448  // vpImagePoint ip;
449  //
450  // // if (test_contrast)
451  // if(max > threshold)
452  // {
453  // if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RESULT))
454  // {
455  // ip.set_i( list_query_pixels[max_rank].i );
456  // ip.set_j( list_query_pixels[max_rank].j );
457  // vpDisplay::displayPoint(I, ip, vpColor::red);
458  // }
459  //
460  // *this = list_query_pixels[max_rank] ;//The vpMeSite is replaced by
461  // the vpMeSite of max likelihood normGradient =
462  // vpMath::sqr(max_convolution);
463  //
464  // convlt = max_convolution;
465  // i_1 = ii_1; //list_query_pixels[max_rank].i ;
466  // j_1 = jj_1; //list_query_pixels[max_rank].j ;
467  // delete []list_query_pixels ;
468  // delete []likelihood;
469  // }
470  // else //none of the query sites is better than the threshold
471  // {
472  // if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RESULT))
473  // {
474  // ip.set_i( list_query_pixels[max_rank].i );
475  // ip.set_j( list_query_pixels[max_rank].j );
476  // vpDisplay::displayPoint(I, ip, vpColor::green);
477  // }
478  // normGradient = 0 ;
479  // if(max == 0)
480  // suppress = 1; // contrast suppression
481  // else
482  // suppress = 2; // threshold suppression
483  //
484  // delete []list_query_pixels ;
485  // delete []likelihood; // modif portage
486  // }
487 
488  vpMeSite *list_query_pixels;
489  int max_rank = -1;
490  // int max_rank1=-1 ;
491  // int max_rank2 = -1;
492  double max_convolution = 0;
493  double max = 0;
494  double contraste = 0;
495  // vpDisplay::display(I) ;
496  // vpERROR_TRACE("getclcik %d",me->range) ;
497  // vpDisplay::getClick(I) ;
498 
499  // range = +/- range of pixels within which the correspondent
500  // of the current pixel will be sought
501  unsigned int range = me->getRange();
502 
503  // std::cout << i << " " << j<<" " << range << " " << suppress <<
504  // std::endl ;
505  list_query_pixels = getQueryList(I, (int)range);
506 
507  double contraste_max = 1 + me->getMu2();
508  double contraste_min = 1 - me->getMu1();
509 
510  // array in which likelihood ratios will be stored
511  double *likelihood = new double[2 * range + 1];
512 
513  int ii_1 = i;
514  int jj_1 = j;
515  i_1 = i;
516  j_1 = j;
517  double threshold;
518  threshold = me->getThreshold();
519  double diff = 1e6;
520 
521  // std::cout <<"---------------------"<<std::endl ;
522  for (unsigned int n = 0; n < 2 * range + 1; n++) {
523  // convolution results
524  double convolution_ = list_query_pixels[n].convolution(I, me);
525 
526  // luminance ratio of reference pixel to potential correspondent pixel
527  // the luminance must be similar, hence the ratio value should
528  // lay between, for instance, 0.5 and 1.5 (parameter tolerance)
529  if (test_contraste) {
530  likelihood[n] = fabs(convolution_ + convlt);
531  if (likelihood[n] > threshold) {
532  contraste = convolution_ / convlt;
533  if ((contraste > contraste_min) && (contraste < contraste_max) && fabs(1 - contraste) < diff) {
534  diff = fabs(1 - contraste);
535  max_convolution = convolution_;
536  max = likelihood[n];
537  max_rank = (int)n;
538  // max_rank2 = max_rank1;
539  // max_rank1 = max_rank;
540  }
541  }
542  }
543 
544  else {
545  likelihood[n] = fabs(2 * convolution_);
546  if (likelihood[n] > max && likelihood[n] > threshold) {
547  max_convolution = convolution_;
548  max = likelihood[n];
549  max_rank = (int)n;
550  // max_rank2 = max_rank1;
551  // max_rank1 = max_rank;
552  }
553  }
554  }
555 
556  // test on the likelihood threshold if threshold==-1 then
557  // the me->threshold is selected
558 
559  vpImagePoint ip;
560 
561  // if (test_contrast)
562  if (max_rank >= 0) {
563  if ((selectDisplay == RANGE_RESULT) || (selectDisplay == RESULT)) {
564  ip.set_i(list_query_pixels[max_rank].i);
565  ip.set_j(list_query_pixels[max_rank].j);
567  }
568 
569  *this = list_query_pixels[max_rank]; // The vpMeSite2 is replaced by the
570  // vpMeSite2 of max likelihood
571  normGradient = vpMath::sqr(max_convolution);
572 
573  convlt = max_convolution;
574  i_1 = ii_1; // list_query_pixels[max_rank].i ;
575  j_1 = jj_1; // list_query_pixels[max_rank].j ;
576  delete[] list_query_pixels;
577  delete[] likelihood;
578  } else // none of the query sites is better than the threshold
579  {
580  if ((selectDisplay == RANGE_RESULT) || (selectDisplay == RESULT)) {
581  ip.set_i(list_query_pixels[0].i);
582  ip.set_j(list_query_pixels[0].j);
584  }
585  normGradient = 0;
586  // if(contraste != 0)
587  if (std::fabs(contraste) > std::numeric_limits<double>::epsilon())
588  state = CONSTRAST; // contrast suppression
589  else
590  state = THRESHOLD; // threshold suppression
591 
592  delete[] list_query_pixels;
593  delete[] likelihood; // modif portage
594  }
595 }
596 
597 int vpMeSite::operator!=(const vpMeSite &m) { return ((m.i != i) || (m.j != j)); }
598 
599 VISP_EXPORT std::ostream &operator<<(std::ostream &os, vpMeSite &vpMeS)
600 {
601 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
602  return (os << "Alpha: " << vpMeS.alpha << " Convolution: " << vpMeS.convlt << " Flag: " << vpMeS.suppress
603  << " Weight: " << vpMeS.weight);
604 #else
605  return (os << "Alpha: " << vpMeS.alpha << " Convolution: " << vpMeS.convlt << " Weight: " << vpMeS.weight);
606 #endif
607 }
608 
610 
611 // Static functions
612 
631 void vpMeSite::display(const vpImage<unsigned char> &I, const double &i, const double &j, const vpMeSiteState &state)
632 {
633  switch (state) {
634  case NO_SUPPRESSION:
636  break;
637 
638  case CONSTRAST:
640  break;
641 
642  case THRESHOLD:
644  break;
645 
646  case M_ESTIMATOR:
648  break;
649 
650  case TOO_NEAR:
652  break;
653 
654  default:
656  }
657 }
658 
677 void vpMeSite::display(const vpImage<vpRGBa> &I, const double &i, const double &j, const vpMeSiteState &state)
678 {
679  switch (state) {
680  case NO_SUPPRESSION:
682  break;
683 
684  case CONSTRAST:
686  break;
687 
688  case THRESHOLD:
690  break;
691 
692  case M_ESTIMATOR:
694  break;
695 
696  case TOO_NEAR:
698  break;
699 
700  default:
702  }
703 }
friend VISP_EXPORT std::ostream & operator<<(std::ostream &os, vpMeSite &vpMeS)
Definition: vpMeSite.cpp:599
void init()
Definition: vpMeSite.cpp:66
double jfloat
Definition: vpMeSite.h:88
void display(const vpImage< unsigned char > &I)
Definition: vpMeSite.cpp:609
double convolution(const vpImage< unsigned char > &ima, const vpMe *me)
Definition: vpMeSite.cpp:301
Performs search in a given direction(normal) for a given distance(pixels) for a given &#39;site&#39;...
Definition: vpMeSite.h:71
double alpha
Definition: vpMeSite.h:92
int i
Definition: vpMeSite.h:86
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
Definition: vpMe.h:60
int mask_sign
Definition: vpMeSite.h:90
double normGradient
Definition: vpMeSite.h:96
static const vpColor green
Definition: vpColor.h:183
vpMatrix * getMask() const
Definition: vpMe.h:120
static int round(const double x)
Definition: vpMath.h:235
unsigned int getMaskSize() const
Definition: vpMe.h:142
double getMu1() const
Definition: vpMe.h:155
static const vpColor red
Definition: vpColor.h:180
vpMeSite()
Definition: vpMeSite.cpp:95
double ifloat
Definition: vpMeSite.h:88
int suppress
Definition: vpMeSite.h:247
void set_i(const double ii)
Definition: vpImagePoint.h:167
static const vpColor cyan
Definition: vpColor.h:189
double getThreshold() const
Definition: vpMe.h:193
static double sqr(double x)
Definition: vpMath.h:108
void setDisplay(vpMeSiteDisplayType select)
Definition: vpMeSite.h:137
double convlt
Definition: vpMeSite.h:94
int getStrip() const
Definition: vpMe.h:185
unsigned char v
Definition: vpMeSite.h:89
vpMeSite * getQueryList(const vpImage< unsigned char > &I, const int range)
Definition: vpMeSite.cpp:219
vp_deprecated void getSign(const vpImage< unsigned char > &I, const int range)
Definition: vpMeSite.cpp:274
int j_1
Definition: vpMeSite.h:87
void set_j(const double jj)
Definition: vpImagePoint.h:178
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
int j
Definition: vpMeSite.h:86
unsigned int getHeight() const
Definition: vpImage.h:178
double weight
Definition: vpMeSite.h:98
vpMeSite & operator=(const vpMeSite &m)
Definition: vpMeSite.cpp:185
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:362
double getMu2() const
Definition: vpMe.h:161
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
int i_1
Definition: vpMeSite.h:87
static const vpColor yellow
Definition: vpColor.h:188
static const vpColor purple
Definition: vpColor.h:191
unsigned int getWidth() const
Definition: vpImage.h:229
unsigned int getRange() const
Definition: vpMe.h:179
int operator!=(const vpMeSite &m)
Definition: vpMeSite.cpp:597
unsigned int getAngleStep() const
Definition: vpMe.h:114
vpMeSiteState
Definition: vpMeSite.h:76
static const vpColor blue
Definition: vpColor.h:186