Visual Servoing Platform  version 3.0.0
vpMbtMeEllipse.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  *
36  *****************************************************************************/
37 
38 #ifndef DOXYGEN_SHOULD_SKIP_THIS
39 
40 #include <visp3/mbt/vpMbtMeEllipse.h>
41 
42 #include <visp3/me/vpMe.h>
43 #include <visp3/core/vpRobust.h>
44 #include <visp3/core/vpTrackingException.h>
45 #include <visp3/core/vpDebug.h>
46 #include <visp3/core/vpImagePoint.h>
47 
48 #include <cmath> // std::fabs
49 #include <limits> // numeric_limits
50 #include <algorithm> // std::min
51 
52 
56 vpMbtMeEllipse::vpMbtMeEllipse()
57  : iPc(), a(0.), b(0.), e(0.),
58  ce(0.), se(0.), mu11(0.), mu20(0.), mu02(0.), thresholdWeight(0.), expecteddensity(0.)
59 {
60 }
61 
65 vpMbtMeEllipse::vpMbtMeEllipse(const vpMbtMeEllipse &meellipse)
66  : vpMeTracker(meellipse), iPc(), a(0.), b(0.), e(0.),
67  ce(0.), se(0.), mu11(0.), mu20(0.), mu02(0.), thresholdWeight(0.), expecteddensity(0.)
68 {
69  iPc = meellipse.iPc;
70  a = meellipse.a;
71  b = meellipse.b;
72  e = meellipse.e;
73 
74  ce = meellipse.ce;
75  se = meellipse.se;
76 
77  mu11 = meellipse.mu11;
78  mu20 = meellipse.mu20;
79  mu02 = meellipse.mu02;
80 
81  expecteddensity = meellipse.expecteddensity;
82 }
83 
87 vpMbtMeEllipse::~vpMbtMeEllipse()
88 {
89  list.clear();
90 }
91 
101 void
102 vpMbtMeEllipse::computeProjectionError(const vpImage<unsigned char>& _I, double &_sumErrorRad, unsigned int &_nbFeatures)
103 {
104  _sumErrorRad = 0;
105  _nbFeatures = 0;
106 
107 // vpMatrix filterX(3,3);
108 // filterX[0][0] = -1;
109 // filterX[1][0] = -2;
110 // filterX[2][0] = -1;
111 
112 // filterX[0][1] = 0;
113 // filterX[1][1] = 0;
114 // filterX[2][1] = 0;
115 
116 // filterX[0][2] = 1;
117 // filterX[1][2] = 2;
118 // filterX[2][2] = 1;
119 
120 // vpMatrix filterY(3,3);
121 // filterY[0][0] = -1;
122 // filterY[0][1] = -2;
123 // filterY[0][2] = -1;
124 
125 // filterY[1][0] = 0;
126 // filterY[1][1] = 0;
127 // filterY[1][2] = 0;
128 
129 // filterY[2][0] = 1;
130 // filterY[2][1] = 2;
131 // filterY[2][2] = 1;
132 
133  vpMatrix filterX(5,5);
134  filterX[0][0] = -1;
135  filterX[1][0] = -4;
136  filterX[2][0] = -6;
137  filterX[3][0] = -4;
138  filterX[4][0] = -1;
139 
140  filterX[0][1] = -2;
141  filterX[1][1] = -8;
142  filterX[2][1] = -12;
143  filterX[3][1] = -8;
144  filterX[4][1] = -2;
145 
146  filterX[0][2] = 0;
147  filterX[1][2] = 0;
148  filterX[2][2] = 0;
149  filterX[3][2] = 0;
150  filterX[4][2] = 0;
151 
152  filterX[0][3] = 2;
153  filterX[1][3] = 8;
154  filterX[2][3] = 12;
155  filterX[3][3] = 8;
156  filterX[4][3] = 2;
157 
158  filterX[0][4] = 1;
159  filterX[1][4] = 4;
160  filterX[2][4] = 6;
161  filterX[3][4] = 4;
162  filterX[4][4] = 1;
163 
164  vpMatrix filterY(5,5);
165  filterY[0][0] = -1;
166  filterY[0][1] = -4;
167  filterY[0][2] = -6;
168  filterY[0][3] = -4;
169  filterY[0][4] = -1;
170 
171  filterY[1][0] = -2;
172  filterY[1][1] = -8;
173  filterY[1][2] = -12;
174  filterY[1][3] = -8;
175  filterY[1][4] = -2;
176 
177  filterY[2][0] = 0;
178  filterY[2][1] = 0;
179  filterY[2][2] = 0;
180  filterY[2][3] = 0;
181  filterY[2][4] = 0;
182 
183  filterY[3][0] = 2;
184  filterY[3][1] = 8;
185  filterY[3][2] = 12;
186  filterY[3][3] = 8;
187  filterY[3][4] = 2;
188 
189  filterY[4][0] = 1;
190  filterY[4][1] = 4;
191  filterY[4][2] = 6;
192  filterY[4][3] = 4;
193  filterY[4][4] = 1;
194 
195  double offset = std::floor(filterX.getRows() / 2.0f);
196 // std::cout << "offset=" << offset << std::endl;
197  int height = (int) _I.getHeight() ;
198  int width = (int) _I.getWidth() ;
199 
200  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ++it){
201  double iSite = it->ifloat;
202  double jSite = it->jfloat;
203 
204  if(!outOfImage(vpMath::round(iSite), vpMath::round(jSite), 0, height, width)) { // Check if necessary
205  // The tangent angle to the ellipse at a site
206  double theta = atan( (-mu02*jSite + mu02*iPc.get_j() + mu11*iSite - mu11*iPc.get_i())
207  / (mu20*iSite - mu11*jSite + mu11*iPc.get_j() - mu20*iPc.get_i()))
208  - M_PI/2;
209 
210  double deltaNormalized = theta;
211  while (deltaNormalized<0) deltaNormalized += M_PI;
212  while (deltaNormalized>M_PI) deltaNormalized -= M_PI;
213 
214  vpColVector vecSite(2);
215  vecSite[0] = cos(deltaNormalized);
216  vecSite[1] = sin(deltaNormalized);
217  vecSite.normalize();
218 
219  double gradientX = 0;
220  double gradientY = 0;
221 
222  for(unsigned int i = 0; i<filterX.getRows() ; i++){
223  double iImg = iSite + (i - offset);
224  for (unsigned int j = 0; j< filterX.getCols(); j++){
225  double jImg = jSite + (j-offset);
226 
227  if(iImg < 0) iImg = 0.0;
228  if(jImg < 0) jImg = 0.0;
229 
230  if(iImg > _I.getHeight()-1) iImg = _I.getHeight()-1;
231  if(jImg > _I.getWidth()-1) jImg = _I.getWidth()-1;
232 
233  gradientX += filterX[i][j] * _I((unsigned int)iImg, (unsigned int)jImg);
234  }
235  }
236 
237  for(unsigned int i = 0; i<filterY.getRows() ; i++){
238  double iImg = iSite + (i - offset);
239  for (unsigned int j = 0; j< filterY.getCols(); j++){
240  double jImg = jSite + (j-offset);
241 
242  if(iImg < 0) iImg = 0.0;
243  if(jImg < 0) jImg = 0.0;
244 
245  if(iImg > _I.getHeight()-1) iImg = _I.getHeight()-1;
246  if(jImg > _I.getWidth()-1) jImg = _I.getWidth()-1;
247 
248  gradientY += filterY[i][j] * _I((unsigned int)iImg, (unsigned int)jImg);
249  }
250  }
251 
252  double angle = atan2(gradientY,gradientX);
253  while (angle<0) angle += M_PI;
254  while (angle>M_PI) angle -= M_PI;
255 
256 // if(std::fabs(deltaNormalized-angle) > M_PI / 2)
257 // {
258 // sumErrorRad += sqrt(vpMath::sqr(deltaNormalized-angle)) - M_PI / 2;
259 // } else {
260 // sumErrorRad += sqrt(vpMath::sqr(deltaNormalized-angle));
261 // }
262 
263 // double angle1 = sqrt(vpMath::sqr(deltaNormalized-angle));
264 // double angle2 = sqrt(vpMath::sqr(deltaNormalized- (angle-M_PI)));
265 
266  vpColVector vecGrad(2);
267  vecGrad[0] = cos(angle);
268  vecGrad[1] = sin(angle);
269  vecGrad.normalize();
270 
271  double angle1 = acos(vecSite * vecGrad);
272  double angle2 = acos(vecSite * (-vecGrad));
273 
274  _sumErrorRad += std::min(angle1,angle2);
275 
276  _nbFeatures++;
277  }
278  }
279 }
280 
291 void
292 vpMbtMeEllipse::sample(const vpImage<unsigned char> & I)
293 {
294  if (!me) {
295  vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
297  "Moving edges not initialized")) ;
298  }
299 
300  int height = (int)I.getHeight() ;
301  int width = (int)I.getWidth() ;
302 
303  //if (me->getSampleStep()==0)
304  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon())
305  {
306  std::cout << "In vpMbtMeEllipse::sample: " ;
307  std::cout << "function called with sample step = 0" ;
308  //return fatalError ;
309  }
310 
311  double j, i;//, j11, i11;
312  vpImagePoint iP11;
313  j = i = 0.0 ;
314 
315  // Approximation of the circumference of an ellipse:
316  // [Ramanujan, S., "Modular Equations and Approximations to ,"
317  // Quart. J. Pure. Appl. Math., vol. 45 (1913-1914), pp. 350-372]
318  double t = (a-b)/(a+b);
319  double circumference = M_PI*(a+b)*(1 + 3*vpMath::sqr(t)/(10 + sqrt(4 - 3*vpMath::sqr(t))));
320  int nb_points_to_track = (int)(circumference / me->getSampleStep());
321  double incr = 2*M_PI/nb_points_to_track;
322 
323  expecteddensity = 0;//nb_points_to_track;
324 
325  // Delete old list
326  list.clear();
327 
328  // sample positions
329  double k = 0 ;
330  double iP_i, iP_j;
331  for (int pt=0; pt < nb_points_to_track; pt++)
332  {
333  j = a *cos(k) ; // equation of an ellipse
334  i = b *sin(k) ; // equation of an ellipse
335 
336  iP_j = iPc.get_j() + ce *j - se *i;
337  iP_i = iPc.get_i() + se *j + ce *i;
338 
339  //vpColor col = vpColor::red ;
340  //vpDisplay::displayCross(I, vpImagePoint(iP_i, iP_j), 5, col) ; //debug only
341 
342  // If point is in the image, add to the sample list
343  if(!outOfImage(vpMath::round(iP_i), vpMath::round(iP_j), 0, height, width))
344  {
345  // The tangent angle to the ellipse at a site
346  double theta = atan( (-mu02*iP_j + mu02*iPc.get_j() + mu11*iP_i - mu11*iPc.get_i())
347  / (mu20*iP_i - mu11*iP_j + mu11*iPc.get_j() - mu20*iPc.get_i()))
348  - M_PI/2;
349 
350  vpMeSite pix ;
351  pix.init((int)iP_i, (int)iP_j, theta) ;
352  pix.setDisplay(selectDisplay) ;
354 
355  list.push_back(pix);
356  expecteddensity ++;
357  }
358  k += incr ;
359 
360  }
361 
363 }
364 
365 
380 void
381 vpMbtMeEllipse::reSample(const vpImage<unsigned char> &I)
382 {
383  if (!me) {
384  vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
386  "Moving edges not initialized")) ;
387  }
388 
389  unsigned int n = numberOfSignal() ;
390  if ((double)n<0.9*expecteddensity){
391  sample(I) ;
392  vpMeTracker::track(I) ;
393  }
394 }
395 
401 void
402 vpMbtMeEllipse::updateTheta()
403 {
404  vpMeSite p_me;
405  double theta;
406  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ++it){
407  p_me = *it;
408  vpImagePoint iP;
409  iP.set_i(p_me.ifloat);
410  iP.set_j(p_me.jfloat);
411 
412  // The tangent angle to the ellipse at a site
413  theta = atan( (-mu02*p_me.jfloat + mu02*iPc.get_j() + mu11*p_me.ifloat - mu11*iPc.get_i())
414  / (mu20*p_me.ifloat - mu11*p_me.jfloat + mu11*iPc.get_j() - mu20*iPc.get_i()))
415  - M_PI/2;
416 
417  p_me.alpha = theta ;
418  *it = p_me;
419  }
420 }
421 
425 void
426 vpMbtMeEllipse::suppressPoints()
427 {
428  // Loop through list of sites to track
429  for(std::list<vpMeSite>::iterator itList=list.begin(); itList!=list.end();){
430  vpMeSite s = *itList;//current reference pixel
432  itList = list.erase(itList);
433  else
434  ++itList;
435  }
436 }
437 
447 void
448 vpMbtMeEllipse::display(const vpImage<unsigned char> &I, vpColor col)
449 {
450  vpDisplay::displayEllipse(I, iPc, mu20, mu11, mu02, true, col);
451 }
452 
453 void
454 vpMbtMeEllipse::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ic,
455  double mu20_p, double mu11_p, double mu02_p)
456 {
457  iPc = ic;
458  mu20 = mu20_p;
459  mu11 = mu11_p;
460  mu02 = mu02_p;
461 
462  if (std::fabs(mu11_p) > std::numeric_limits<double>::epsilon()) {
463 
464  double val_p = sqrt(vpMath::sqr(mu20_p-mu02_p) + 4*vpMath::sqr(mu11_p));
465  a = sqrt((mu20_p + mu02_p + val_p)/2);
466  b = sqrt((mu20_p + mu02_p - val_p)/2);
467 
468  e = (mu02_p - mu20_p + val_p)/(2*mu11_p);
469  }
470  else {
471  a = sqrt(mu20_p);
472  b = sqrt(mu02_p);
473  e = 0.;
474  }
475 
476  e = atan(e);
477 
478  ce = cos(e);
479  se = sin(e);
480 
481  sample(I) ;
482 
484 
485  try{
486  track(I) ;
487  }
488  catch(vpException &exception)
489  {
490  throw(exception) ;
491  }
492 }
493 
499 void
500 vpMbtMeEllipse::track(const vpImage<unsigned char> &I)
501 {
502  try{
503  vpMeTracker::track(I) ;
504  }
505  catch(vpException &exception)
506  {
507  throw(exception) ;
508  }
509 }
510 
511 void
512 vpMbtMeEllipse::updateParameters(const vpImage<unsigned char> &I, const vpImagePoint &ic, double mu20_p, double mu11_p, double mu02_p)
513 {
514  iPc = ic;
515  mu20 = mu20_p;
516  mu11 = mu11_p;
517  mu02 = mu02_p;
518 
519  if (std::fabs(mu11_p) > std::numeric_limits<double>::epsilon()) {
520 
521  double val_p = sqrt(vpMath::sqr(mu20_p-mu02_p) + 4*vpMath::sqr(mu11_p));
522  a = sqrt((mu20_p + mu02_p + val_p)/2);
523  b = sqrt((mu20_p + mu02_p - val_p)/2);
524 
525  e = (mu02_p - mu20_p + val_p)/(2*mu11_p);
526  }
527  else {
528  a = sqrt(mu20_p);
529  b = sqrt(mu02_p);
530  e = 0.;
531  }
532 
533  e = atan(e);
534 
535  ce = cos(e);
536  se = sin(e);
537 
538  suppressPoints();
539  reSample(I);
540 
541  // remet a jour l'angle delta pour chaque point de la liste
542  updateTheta();
543 }
544 
545 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:92
static void displayEllipse(const vpImage< unsigned char > &I, const vpImagePoint &center, const double &coef1, const double &coef2, const double &coef3, bool use_centered_moments, const vpColor &color, unsigned int thickness=1)
Definition: vpDisplay.cpp:3609
void init()
Definition: vpMeSite.cpp:69
unsigned int getWidth() const
Definition: vpImage.h:161
double jfloat
Definition: vpMeSite.h:96
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'...
Definition: vpMeSite.h:72
Class to define colors available for display functionnalities.
Definition: vpColor.h:121
double alpha
Definition: vpMeSite.h:100
error that can be emited by ViSP classes.
Definition: vpException.h:73
static int round(const double x)
Definition: vpMath.h:248
vpMeSiteState getState() const
Definition: vpMeSite.h:198
double ifloat
Definition: vpMeSite.h:96
void set_i(const double ii)
Definition: vpImagePoint.h:154
Error that can be emited by the vpTracker class and its derivates.
static double sqr(double x)
Definition: vpMath.h:110
void setDisplay(vpMeSiteDisplayType select)
Definition: vpMeSite.h:148
void track(const vpImage< unsigned char > &I)
Track sampled pixels.
Contains abstract elements for a Distance to Feature type feature.
Definition: vpMeTracker.h:64
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:185
void set_j(const double jj)
Definition: vpImagePoint.h:165
#define vpDERROR_TRACE
Definition: vpDebug.h:455
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
void initTracking(const vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:152
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88