ViSP  2.8.0
vpMeSite.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMeSite.cpp 4062 2013-01-09 10:30:06Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Moving edges.
36  *
37  * Authors:
38  * Eric Marchand
39  * Andrew Comport
40  * Aurelien Yol
41  *
42  *****************************************************************************/
43 
51 #include <visp/vpMeSite.h>
52 #include <visp/vpMe.h>
53 #include <visp/vpTrackingException.h>
54 #include <stdlib.h>
55 #include <cmath> // std::fabs
56 #include <limits> // numeric_limits
57 #include "vpMeSite.h"
58 
59 
60 #ifndef DOXYGEN_SHOULD_SKIP_THIS
61 static
62 bool horsImage(int i , int j, int half, int rows, int cols)
63 {
64  //return((i < half + 1) || ( i > (rows - half - 3) )||(j < half + 1) || (j > (cols - half - 3) )) ;
65  int half_1 = half + 1;
66  int half_3 = half + 3;
67  //return((i < half + 1) || ( i > (rows - half - 3) )||(j < half + 1) || (j > (cols - half - 3) )) ;
68  return( (0 < (half_1 - i) ) || ( (i - rows + half_3) > 0 ) || ( 0 < (half_1 -j) ) || ( (j - cols + half_3) > 0 ) ) ;
69 }
70 #endif
71 
72 void
74 {
75  // Site components
76  alpha = 0.0 ;
77  convlt = 0.0 ;
78  weight=-1;
79 
80  selectDisplay = NONE ;
81 
82  // Pixel components
83  i = 0 ;
84  j = 0 ;
85  v = 0 ;
86  ifloat =i ;
87  jfloat = j ;
88  i_1 = 0 ;
89  j_1 = 0 ;
90 
91  mask_sign = 1 ;
92 
93  normGradient = 0;
94 
95  state = NO_SUPPRESSION;
96 
97 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
98  suppress = 0;
99 #endif
100 }
101 
103 {
104  init() ;
105 }
106 
107 vpMeSite::vpMeSite(double ip, double jp)
108 {
109  init() ;
110 
111  selectDisplay = NONE ;
112  i = vpMath::round(ip) ;
113  j = vpMath::round(jp) ;
114  ifloat = ip ;
115  jfloat = jp ;
116 }
117 
122 {
123  *this = mesite;
124 }
125 
126 // More an Update than init
127 // For points in meter form (to avoid approximations)
128 void
129 vpMeSite::init(double ip, double jp, double alphap)
130 {
131  // Note: keep old value of convlt, suppress and contrast
132  selectDisplay = NONE ;
133 
134  ifloat = ip;
135  i= vpMath::round(ip);
136  jfloat = jp ;
137  j = vpMath::round(jp);
138  alpha = alphap ;
139  mask_sign =1 ;
140 
141  v = 0 ;
142  i_1 = 0 ;
143  j_1 = 0 ;
144 
145 }
146 
147 // initialise with convolution
148 void
149 vpMeSite::init(double ip, double jp, double alphap, double convltp)
150 {
151  selectDisplay = NONE ;
152  ifloat = ip ;
153  i= (int)ip ;
154  jfloat = jp ;
155  j =(int)jp ;
156  alpha = alphap ;
157  convlt = convltp;
158  mask_sign =1 ;
159 
160  v = 0 ;
161  i_1 = 0 ;
162  j_1 = 0 ;
163 }
164 // initialise with convolution and sign
165 void
166 vpMeSite::init(double ip, double jp, double alphap, double convltp, int sign)
167 {
168  selectDisplay = NONE ;
169  ifloat = ip ;
170  i= (int)ip ;
171  jfloat = jp ;
172  j =(int)jp ;
173  alpha = alphap ;
174  convlt = convltp;
175  mask_sign = sign ;
176 
177  v = 0 ;
178  i_1 = 0 ;
179  j_1 = 0 ;
180 }
181 
183 {
184  i = m.i;
185  j = m.j;
186  i_1 = m.i_1;
187  j_1 = m.j_1;
188  ifloat = m.ifloat;
189  jfloat = m.jfloat;
190  v = m.v;
191  mask_sign = m.mask_sign;
192  alpha = m.alpha;
193  convlt = m.convlt;
195  weight = m.weight;
196  selectDisplay = m.selectDisplay;
197  state = m.state;
198 
199 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
200  suppress = m.suppress;
201 #endif
202 
203  return *this ;
204 }
205 
206 
207 // ===================================================================
215 // ===================================================================
216 
217 vpMeSite*
219 {
220 
221  int k ;
222 
223  int n;
224  double ii , jj ;
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  {
242  ii = (ifloat+k*salpha);
243  jj = (jfloat+k*calpha);
244 
245  // Display
246  if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RANGE)) {
247  ip.set_i( ii );
248  ip.set_j( jj );
250  }
251 
252  // Copy parent's convolution
253  vpMeSite pel ;
254  pel.init(ii, jj, alpha, convlt,mask_sign) ;
255  pel.setDisplay(selectDisplay) ;// Display
256 
257  // Add site to the query list
258  list_query_pixels[n] = pel ;
259  n++ ;
260  }
261 
262  return(list_query_pixels) ;
263 }
264 
265 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
266 // ===================================================================
274 // ===================================================================
275 void
276 vpMeSite::getSign(const vpImage<unsigned char> &I, const int range)
277 {
278 
279  int k ;
280 
281  double salpha = sin(alpha);
282  double calpha = cos(alpha);
283 
284  //First extremity
285  k = -range ;
286  unsigned int i1 = static_cast<unsigned int>(vpMath::round(ifloat+k*salpha));
287  unsigned int j1 = static_cast<unsigned int>(vpMath::round(jfloat+k*calpha));
288 
289  //Second extremity
290  k = range ;
291  unsigned int i2 = static_cast<unsigned int>(vpMath::round(ifloat+k*salpha));
292  unsigned int j2 = static_cast<unsigned int>(vpMath::round(jfloat+k*calpha));
293 
294  // TODO: Here check if i1,j1,i2,j2 > 0 else ??
295  if (I[i1][j1] > I[i2][j2]) mask_sign = 1 ; else mask_sign = -1 ;
296 }
297 #endif
298 
299 // Specific function for ME
300 double
302 {
303  int half;
304  unsigned int index_mask ;
305  int height_ = static_cast<int>(I.getHeight());
306  int width_ = static_cast<int>(I.getWidth());
307 
308  double conv = 0.0 ;
309  unsigned int msize = me->getMaskSize();
310  half = (static_cast<int>(msize) - 1) >> 1 ;
311 
312  if(horsImage( i , j , half + me->getStrip() , height_, width_))
313  {
314  conv = 0.0 ;
315  i = 0 ; j = 0 ;
316  }
317  else
318  {
319  // Calculate tangent angle from normal
320  double theta = alpha+M_PI/2;
321  // Move tangent angle to within 0->M_PI for a positive
322  // mask index
323  while (theta<0) theta += M_PI;
324  while (theta>M_PI) theta -= M_PI;
325 
326  // Convert radians to degrees
327  int thetadeg = vpMath::round(theta * 180 / M_PI) ;
328 
329  if(abs(thetadeg) == 180 )
330  {
331  thetadeg= 0 ;
332  }
333 
334  index_mask = (unsigned int)(thetadeg/(double)me->getAngleStep());
335 
336  unsigned int i_ = static_cast<unsigned int>(i);
337  unsigned int j_ = static_cast<unsigned int>(j);
338  unsigned int half_ = static_cast<unsigned int>(half);
339 
340  unsigned int ihalf = i_-half_ ;
341  unsigned int jhalf = j_-half_ ;
342  unsigned int ihalfa ;
343 
344  for(unsigned int a = 0 ; a < msize ; a++ )
345  {
346  ihalfa = ihalf+a ;
347  for(unsigned int b = 0 ; b < msize ; b++ )
348  {
349  conv += mask_sign* me->getMask()[index_mask][a][b] *
350  // I(i-half+a,j-half+b) ;
351  I(ihalfa,jhalf+b) ;
352  }
353  }
354 
355  }
356 
357  return(conv) ;
358 }
359 
360 
369 void
371  const vpMe *me,
372  const bool test_contraste)
373 {
374  // vpMeSite *list_query_pixels ;
375  // int max_rank =0 ;
376  // int max_rank1=0 ;
377  // int max_rank2 = 0;
378  // double convolution = 0 ;
379  // double max_convolution = 0 ;
380  // double max = 0 ;
381  // double contraste = 0;
382  // // vpDisplay::display(I) ;
383  // // vpERROR_TRACE("getclcik %d",me->getRange()) ;
384  // // vpDisplay::getClick(I) ;
385  //
386  // // range = +/- range of pixels within which the correspondent
387  // // of the current pixel will be sought
388  // int range = me->getRange() ;
389  //
390  // // std::cout << i << " " << j<<" " << range << " " << suppress << std::endl ;
391  // list_query_pixels = getQueryList(I, range) ;
392  //
393  // double contraste_max = 1 + me->getMu2();
394  // double contraste_min = 1 - me->getMu1();
395  //
396  // // array in which likelihood ratios will be stored
397  // double *likelihood= new double[ 2 * range + 1 ] ;
398  //
399  // int ii_1 = i ;
400  // int jj_1 = j ;
401  // i_1 = i ;
402  // j_1 = j ;
403  // double threshold;
404  // threshold = me->getThreshold();
405  //
406  // // std::cout <<"---------------------"<<std::endl ;
407  // for(int n = 0 ; n < 2 * range + 1 ; n++)
408  // {
409  //
410  // // convolution results
411  // convolution = list_query_pixels[n].convolution(I, me) ;
412  //
413  // // luminance ratio of reference pixel to potential correspondent pixel
414  // // the luminance must be similar, hence the ratio value should
415  // // lay between, for instance, 0.5 and 1.5 (parameter tolerance)
416  // if( test_contraste )
417  // {
418  // // Include this to eliminate temporal calculation
419  // if (convlt==0)
420  // {
421  // std::cout << "vpMeSite::track : Division by zero convlt = 0" << std::endl ;
422  // delete []list_query_pixels ;
423  // delete []likelihood;
424  // throw(vpTrackingException(vpTrackingException::initializationError,
425  // "Division by zero")) ;
426  // }
427  //
428  // // contraste = fabs(convolution / convlt) ;
429  // contraste = convolution / convlt ;
430  // // likelihood ratios
431  // if((contraste > contraste_min) && (contraste < contraste_max))
432  // likelihood[n] = fabs(convolution + convlt ) ;
433  // else
434  // likelihood[n] = 0 ;
435  // }
436  // else
437  // likelihood[n] = fabs(2*convolution) ;
438  //
439  //
440  // // establishment of the maximal likelihood ratios's rank
441  // // in the array, the value of the likelihood ratio can now be
442  // // referenced by its rank in the array
443  // if (likelihood[n] > max)
444  // {
445  // max_convolution= convolution;
446  // max = likelihood[n] ;
447  // max_rank = n ;
448  // max_rank2 = max_rank1;
449  // max_rank1 = max_rank;
450  // }
451  //
452  // }
453  //
454  // // test on the likelihood threshold if threshold==-1 then
455  // // the me->threshold is selected
456  //
457  // vpImagePoint ip;
458  //
459  // // if (test_contrast)
460  // if(max > threshold)
461  // {
462  // if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RESULT))
463  // {
464  // ip.set_i( list_query_pixels[max_rank].i );
465  // ip.set_j( list_query_pixels[max_rank].j );
466  // vpDisplay::displayPoint(I, ip, vpColor::red);
467  // }
468  //
469  // *this = list_query_pixels[max_rank] ;//The vpMeSite is replaced by the vpMeSite of max likelihood
470  // normGradient = vpMath::sqr(max_convolution);
471  //
472  // convlt = max_convolution;
473  // i_1 = ii_1; //list_query_pixels[max_rank].i ;
474  // j_1 = jj_1; //list_query_pixels[max_rank].j ;
475  // delete []list_query_pixels ;
476  // delete []likelihood;
477  // }
478  // else //none of the query sites is better than the threshold
479  // {
480  // if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RESULT))
481  // {
482  // ip.set_i( list_query_pixels[max_rank].i );
483  // ip.set_j( list_query_pixels[max_rank].j );
484  // vpDisplay::displayPoint(I, ip, vpColor::green);
485  // }
486  // normGradient = 0 ;
487  // if(max == 0)
488  // suppress = 1; // contrast suppression
489  // else
490  // suppress = 2; // threshold suppression
491  //
492  // delete []list_query_pixels ;
493  // delete []likelihood; // modif portage
494  // }
495 
496  vpMeSite *list_query_pixels ;
497  int max_rank =-1 ;
498  // int max_rank1=-1 ;
499  // int max_rank2 = -1;
500  double convolution = 0 ;
501  double max_convolution = 0 ;
502  double max = 0 ;
503  double contraste = 0;
504  // vpDisplay::display(I) ;
505  // vpERROR_TRACE("getclcik %d",me->range) ;
506  // vpDisplay::getClick(I) ;
507 
508  // range = +/- range of pixels within which the correspondent
509  // of the current pixel will be sought
510  unsigned int range = me->getRange() ;
511 
512  // std::cout << i << " " << j<<" " << range << " " << suppress << std::endl ;
513  list_query_pixels = getQueryList(I, (int)range) ;
514 
515  double contraste_max = 1 + me->getMu2();
516  double contraste_min = 1 - me->getMu1();
517 
518  // array in which likelihood ratios will be stored
519  double *likelihood= new double[ 2 * range + 1 ] ;
520 
521  int ii_1 = i ;
522  int jj_1 = j ;
523  i_1 = i ;
524  j_1 = j ;
525  double threshold;
526  threshold = me->getThreshold() ;
527  double diff = 1e6;
528 
529  // std::cout <<"---------------------"<<std::endl ;
530  for(unsigned int n = 0 ; n < 2 * range + 1 ; n++)
531  {
532  // convolution results
533  convolution = list_query_pixels[n].convolution(I, me) ;
534 
535  // luminance ratio of reference pixel to potential correspondent pixel
536  // the luminance must be similar, hence the ratio value should
537  // lay between, for instance, 0.5 and 1.5 (parameter tolerance)
538  if( test_contraste )
539  {
540  likelihood[n] = fabs(convolution + convlt );
541  if (likelihood[n]> threshold)
542  {
543  contraste = convolution / convlt;
544  if((contraste > contraste_min) && (contraste < contraste_max) && fabs(1-contraste) < diff)
545  {
546  diff = fabs(1-contraste);
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  else
557  {
558  likelihood[n] = fabs(2*convolution) ;
559  if (likelihood[n] > max && likelihood[n] > threshold)
560  {
561  max_convolution= convolution;
562  max = likelihood[n] ;
563  max_rank = (int)n ;
564  // max_rank2 = max_rank1;
565  // max_rank1 = max_rank;
566  }
567  }
568  }
569 
570  // test on the likelihood threshold if threshold==-1 then
571  // the me->threshold is selected
572 
573  vpImagePoint ip;
574 
575  // if (test_contrast)
576  if(max_rank >= 0)
577  {
578  if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RESULT))
579  {
580  ip.set_i( list_query_pixels[max_rank].i );
581  ip.set_j( list_query_pixels[max_rank].j );
583  }
584 
585  *this = list_query_pixels[max_rank] ;//The vpMeSite2 is replaced by the vpMeSite2 of max likelihood
586  normGradient = vpMath::sqr(max_convolution);
587 
588  convlt = max_convolution;
589  i_1 = ii_1; //list_query_pixels[max_rank].i ;
590  j_1 = jj_1; //list_query_pixels[max_rank].j ;
591  delete []list_query_pixels ;
592  delete []likelihood;
593  }
594  else //none of the query sites is better than the threshold
595  {
596  if ((selectDisplay==RANGE_RESULT)||(selectDisplay==RESULT))
597  {
598  ip.set_i( list_query_pixels[0].i );
599  ip.set_j( list_query_pixels[0].j );
601  }
602  normGradient = 0 ;
603  //if(contraste != 0)
604  if(std::fabs(contraste) > std::numeric_limits<double>::epsilon())
605  state = CONSTRAST; // contrast suppression
606  else
607  state = THRESHOLD; // threshold suppression
608 
609  delete []list_query_pixels ;
610  delete []likelihood; // modif portage
611  }
612 }
613 
615 {
616  return((m.i != i) || (m.j != j)) ;
617 
618 }
619 
620 std::ostream& operator<<(std::ostream& os, vpMeSite& vpMeS)
621 {
622 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
623  return (os << "Alpha: " << vpMeS.alpha
624  << " Convolution: " << vpMeS.convlt
625  << " Flag: " << vpMeS.suppress
626  << " Weight: " << vpMeS.weight );
627 #endif
628 
629  return (os << "Alpha: " << vpMeS.alpha
630  << " Convolution: " << vpMeS.convlt
631  << " Weight: " << vpMeS.weight );
632 }
633 
635 {
637 }
638 
639 //Static functions
640 
656 void vpMeSite::display(const vpImage<unsigned char>& I, const double &i, const double &j, const vpMeSiteState &state)
657 {
658  switch(state)
659  {
660  case NO_SUPPRESSION:
662  break;
663 
664  case CONSTRAST:
666  break;
667 
668  case THRESHOLD:
670  break;
671 
672  case M_ESTIMATOR:
674  break;
675 
676  case TOO_NEAR:
678 
679  default:
681  }
682 }
683 
699 void vpMeSite::display(const vpImage<vpRGBa>& I, const double &i, const double &j, const vpMeSiteState &state)
700 {
701  switch(state)
702  {
703  case NO_SUPPRESSION:
705  break;
706 
707  case CONSTRAST:
709  break;
710 
711  case THRESHOLD:
713  break;
714 
715  case M_ESTIMATOR:
717  break;
718 
719  case TOO_NEAR:
721 
722  default:
724  }
725 }
void set_j(const double j)
Definition: vpImagePoint.h:156
unsigned int getRange() const
Definition: vpMe.h:236
unsigned int getMaskSize() const
Definition: vpMe.h:164
void init()
Definition: vpMeSite.cpp:73
unsigned int getWidth() const
Definition: vpImage.h:159
double jfloat
Definition: vpMeSite.h:100
void display(const vpImage< unsigned char > &I)
Definition: vpMeSite.cpp:634
double getMu1() const
Definition: vpMe.h:178
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 'site'...
Definition: vpMeSite.h:76
void set_i(const double i)
Definition: vpImagePoint.h:145
double alpha
Definition: vpMeSite.h:104
int i
Definition: vpMeSite.h:98
Contains predetermined masks for sites and holds moving edges tracking parameters.
Definition: vpMe.h:70
int mask_sign
Definition: vpMeSite.h:102
double normGradient
Definition: vpMeSite.h:108
static const vpColor green
Definition: vpColor.h:170
static int round(const double x)
Definition: vpMath.h:228
static const vpColor red
Definition: vpColor.h:167
double ifloat
Definition: vpMeSite.h:100
int suppress
Definition: vpMeSite.h:257
int getStrip() const
Definition: vpMe.h:292
double getThreshold() const
Definition: vpMe.h:306
unsigned int getAngleStep() const
Definition: vpMe.h:250
static const vpColor cyan
Definition: vpColor.h:176
static double sqr(double x)
Definition: vpMath.h:106
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void setDisplay(vpMeSiteDisplayType select)
Definition: vpMeSite.h:152
double convlt
Definition: vpMeSite.h:106
unsigned char v
Definition: vpMeSite.h:101
vpMeSite * getQueryList(const vpImage< unsigned char > &I, const int range)
Definition: vpMeSite.cpp:218
VISP_EXPORT std::ostream & operator<<(std::ostream &os, const vpImagePoint &ip)
Definition: vpImagePoint.h:529
vp_deprecated void getSign(const vpImage< unsigned char > &I, const int range)
Definition: vpMeSite.cpp:276
int j_1
Definition: vpMeSite.h:99
vpMatrix * getMask() const
Definition: vpMe.h:116
double getMu2() const
Definition: vpMe.h:192
int j
Definition: vpMeSite.h:98
double weight
Definition: vpMeSite.h:110
vpMeSite & operator=(const vpMeSite &m)
Definition: vpMeSite.cpp:182
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:370
unsigned int getHeight() const
Definition: vpImage.h:150
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
int i_1
Definition: vpMeSite.h:99
static const vpColor yellow
Definition: vpColor.h:175
static const vpColor purple
Definition: vpColor.h:178
int operator!=(const vpMeSite &m)
Definition: vpMeSite.cpp:614
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
vpMeSiteState
Definition: vpMeSite.h:87
static const vpColor blue
Definition: vpColor.h:173