Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
vpMbtMeEllipse.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
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  // Approximation of the circumference of an ellipse:
312  // [Ramanujan, S., "Modular Equations and Approximations to ,"
313  // Quart. J. Pure. Appl. Math., vol. 45 (1913-1914), pp. 350-372]
314  double t = (a-b)/(a+b);
315  double circumference = M_PI*(a+b)*(1 + 3*vpMath::sqr(t)/(10 + sqrt(4 - 3*vpMath::sqr(t))));
316  int nb_points_to_track = (int)(circumference / me->getSampleStep());
317  double incr = 2*M_PI/nb_points_to_track;
318 
319  expecteddensity = 0;//nb_points_to_track;
320 
321  // Delete old list
322  list.clear();
323 
324  // sample positions
325  double k = 0 ;
326  for (int pt=0; pt < nb_points_to_track; pt++)
327  {
328  double j = a *cos(k) ; // equation of an ellipse
329  double i = b *sin(k) ; // equation of an ellipse
330 
331  double iP_j = iPc.get_j() + ce *j - se *i;
332  double iP_i = iPc.get_i() + se *j + ce *i;
333 
334  //vpColor col = vpColor::red ;
335  //vpDisplay::displayCross(I, vpImagePoint(iP_i, iP_j), 5, col) ; //debug only
336 
337  // If point is in the image, add to the sample list
338  if(!outOfImage(vpMath::round(iP_i), vpMath::round(iP_j), 0, height, width))
339  {
340  // The tangent angle to the ellipse at a site
341  double theta = atan( (-mu02*iP_j + mu02*iPc.get_j() + mu11*iP_i - mu11*iPc.get_i())
342  / (mu20*iP_i - mu11*iP_j + mu11*iPc.get_j() - mu20*iPc.get_i()))
343  - M_PI/2;
344 
345  vpMeSite pix ;
346  pix.init((int)iP_i, (int)iP_j, theta) ;
347  pix.setDisplay(selectDisplay) ;
349 
350  list.push_back(pix);
351  expecteddensity ++;
352  }
353  k += incr ;
354 
355  }
356 
358 }
359 
360 
375 void
376 vpMbtMeEllipse::reSample(const vpImage<unsigned char> &I)
377 {
378  if (!me) {
379  vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
381  "Moving edges not initialized")) ;
382  }
383 
384  unsigned int n = numberOfSignal() ;
385  if ((double)n<0.9*expecteddensity){
386  sample(I) ;
387  vpMeTracker::track(I) ;
388  }
389 }
390 
396 void
397 vpMbtMeEllipse::updateTheta()
398 {
399  vpMeSite p_me;
400  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ++it){
401  p_me = *it;
402  vpImagePoint iP;
403  iP.set_i(p_me.ifloat);
404  iP.set_j(p_me.jfloat);
405 
406  // The tangent angle to the ellipse at a site
407  double theta = atan( (-mu02*p_me.jfloat + mu02*iPc.get_j() + mu11*p_me.ifloat - mu11*iPc.get_i())
408  / (mu20*p_me.ifloat - mu11*p_me.jfloat + mu11*iPc.get_j() - mu20*iPc.get_i()))
409  - M_PI/2;
410 
411  p_me.alpha = theta ;
412  *it = p_me;
413  }
414 }
415 
419 void
420 vpMbtMeEllipse::suppressPoints()
421 {
422  // Loop through list of sites to track
423  for(std::list<vpMeSite>::iterator itList=list.begin(); itList!=list.end();){
424  vpMeSite s = *itList;//current reference pixel
426  itList = list.erase(itList);
427  else
428  ++itList;
429  }
430 }
431 
441 void
442 vpMbtMeEllipse::display(const vpImage<unsigned char> &I, vpColor col)
443 {
444  vpDisplay::displayEllipse(I, iPc, mu20, mu11, mu02, true, col);
445 }
446 
447 void
448 vpMbtMeEllipse::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ic,
449  double mu20_p, double mu11_p, double mu02_p)
450 {
451  iPc = ic;
452  mu20 = mu20_p;
453  mu11 = mu11_p;
454  mu02 = mu02_p;
455 
456  if (std::fabs(mu11_p) > std::numeric_limits<double>::epsilon()) {
457 
458  double val_p = sqrt(vpMath::sqr(mu20_p-mu02_p) + 4*vpMath::sqr(mu11_p));
459  a = sqrt((mu20_p + mu02_p + val_p)/2);
460  b = sqrt((mu20_p + mu02_p - val_p)/2);
461 
462  e = (mu02_p - mu20_p + val_p)/(2*mu11_p);
463  }
464  else {
465  a = sqrt(mu20_p);
466  b = sqrt(mu02_p);
467  e = 0.;
468  }
469 
470  e = atan(e);
471 
472  ce = cos(e);
473  se = sin(e);
474 
475  sample(I) ;
476 
478 
479  try{
480  track(I) ;
481  }
482  catch(vpException &exception)
483  {
484  throw(exception) ;
485  }
486 }
487 
493 void
494 vpMbtMeEllipse::track(const vpImage<unsigned char> &I)
495 {
496  try{
497  vpMeTracker::track(I) ;
498  }
499  catch(vpException &exception)
500  {
501  throw(exception) ;
502  }
503 }
504 
505 void
506 vpMbtMeEllipse::updateParameters(const vpImage<unsigned char> &I, const vpImagePoint &ic, double mu20_p, double mu11_p, double mu02_p)
507 {
508  iPc = ic;
509  mu20 = mu20_p;
510  mu11 = mu11_p;
511  mu02 = mu02_p;
512 
513  if (std::fabs(mu11_p) > std::numeric_limits<double>::epsilon()) {
514 
515  double val_p = sqrt(vpMath::sqr(mu20_p-mu02_p) + 4*vpMath::sqr(mu11_p));
516  a = sqrt((mu20_p + mu02_p + val_p)/2);
517  b = sqrt((mu20_p + mu02_p - val_p)/2);
518 
519  e = (mu02_p - mu20_p + val_p)/(2*mu11_p);
520  }
521  else {
522  a = sqrt(mu20_p);
523  b = sqrt(mu02_p);
524  e = 0.;
525  }
526 
527  e = atan(e);
528 
529  ce = cos(e);
530  se = sin(e);
531 
532  suppressPoints();
533  reSample(I);
534 
535  // remet a jour l'angle delta pour chaque point de la liste
536  updateTheta();
537 }
538 
539 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:97
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)
void init()
Definition: vpMeSite.cpp:69
unsigned int getWidth() const
Definition: vpImage.h:226
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:249
vpMeSiteState getState() const
Definition: vpMeSite.h:198
double ifloat
Definition: vpMeSite.h:96
void set_i(const double ii)
Definition: vpImagePoint.h:163
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:174
#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:175
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88