Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
vpMeNurbs.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  * Nicolas Melchior
35  *
36  *****************************************************************************/
37 
38 
44 #include <visp3/me/vpMeTracker.h>
45 #include <visp3/me/vpMe.h>
46 #include <visp3/me/vpMeSite.h>
47 #include <visp3/me/vpMeNurbs.h>
48 #include <visp3/core/vpRobust.h>
49 #include <visp3/core/vpTrackingException.h>
50 #include <visp3/core/vpImagePoint.h>
51 #include <visp3/core/vpMath.h>
52 #include <visp3/core/vpRect.h>
53 #include <visp3/core/vpImageTools.h>
54 #include <visp3/core/vpImageConvert.h>
55 #include <visp3/core/vpImageFilter.h>
56 #include <stdlib.h>
57 #include <cmath> // std::fabs
58 #include <limits> // numeric_limits
59 #ifdef VISP_HAVE_OPENCV
60 # if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
61 //# include <opencv2/imgproc/imgproc.hpp>
62 # include <opencv2/imgproc/imgproc_c.h>
63 # else
64 # include <cv.h>
65 # endif
66 #endif
67 
68 double computeDelta(double deltai, double deltaj);
69 void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP,
70  vpMe* me, double &angle, double &convlt);
71 vpImagePoint findFirstBorder(const vpImage<unsigned char>& Isub, const vpImagePoint &iP);
72 bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list);
73 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
74 vp_deprecated bool findCenterPoint(vpList<vpImagePoint> *ip_edges_list);
75 #endif
76 
77 //Compute the angle delta = arctan(deltai/deltaj)
78 //and normalize it between 0 and pi
79 double
80 computeDelta(double deltai, double deltaj)
81 {
82  double delta;
83  delta = atan2(deltai,deltaj) ;
84  delta -= M_PI/2.0 ;
85  while (delta > M_PI) { delta -= M_PI ; }
86  while (delta < 0) { delta += M_PI ; }
87  return(delta);
88 }
89 
90 //Check if the image point is in the image and not to close to
91 //its edge to enable the computation of a convolution whith a mask.
92 static
93 bool outOfImage( vpImagePoint iP , int half , int rows , int cols)
94 {
95  return((iP.get_i() < half + 1) || ( iP.get_i() > (rows - half - 3) )
96  ||(iP.get_j() < half + 1) || (iP.get_j() > (cols - half - 3) )) ;
97 }
98 
99 //if iP is a edge point, it computes the angle corresponding to the
100 //highest convolution result. the angle is between 0 an 179.
101 //The result gives the angle in RADIAN + pi/2 (to deal with the moving edeg alpha angle)
102 //and the corresponding convolution result.
103 void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP,
104  vpMe* me, double &angle, double &convlt)
105 {
106  int Iheight = (int)I.getHeight();
107  int Iwidth = (int)I.getWidth();
108  angle = 0.0;
109  convlt = 0.0;
110  for (int i = 0; i < 180; i++)
111  {
112  double conv = 0.0;
113  unsigned int half;
114  half = (me->getMaskSize() - 1) >> 1 ;
115 
116  if(outOfImage( iP , (int)half + me->getStrip() , Iheight, Iwidth))
117  {
118  conv = 0.0 ;
119  }
120  else
121  {
122  int index_mask;
123 
124  if (me->getAngleStep() !=0)
125  index_mask = (int)(i/(double)me->getAngleStep());
126  else
127  throw (vpException(vpException::divideByZeroError,"angle step = 0"));
128 
129  unsigned int ihalf = (unsigned int)(iP.get_i()-half) ;
130  unsigned int jhalf = (unsigned int)(iP.get_j()-half) ;
131  unsigned int a ;
132  unsigned int b ;
133  for( a = 0 ; a < me->getMaskSize() ; a++ )
134  {
135  unsigned int ihalfa = ihalf+a ;
136  for( b = 0 ; b < me->getMaskSize() ; b++ )
137  {
138  conv += me->getMask()[index_mask][a][b] *
139  I(ihalfa,jhalf+b) ;
140  }
141  }
142  }
143  conv = fabs(conv);
144  if (conv > convlt)
145  {
146  convlt = conv;
147  angle = vpMath::rad(i);
148  angle += M_PI/2;
149  while (angle > M_PI) { angle -= M_PI ; }
150  while (angle < 0) { angle += M_PI ; }
151  }
152  }
153 }
154 
155 //Find the point belonging to the edge of the sub image which respects the following hypotheses:
156 //- the value of the pixel is upper than zero.
157 //- the distantce between the point and iP is less than 4 pixels.
158 //The function returns the nearest point of iP which respect the hypotheses
159 //If no point is found the returned point is (-1,-1)
160 vpImagePoint findFirstBorder(const vpImage<unsigned char>& Isub, const vpImagePoint &iP)
161 {
162  double dist = 1e6;
163  double dist_1 = 1e6;
164  vpImagePoint index(-1,-1);
165  for (unsigned int i = 0; i <= Isub.getHeight(); i++)
166  {
167  for (unsigned int j = 0; j <= Isub.getWidth(); j++)
168  {
169  if(i == 0 || i == Isub.getHeight()-1 || j == 0 || j == Isub.getWidth()-1)
170  {
171  if (Isub(i,j) > 0)
172  {
174  if (dist <= 16 && dist < dist_1)
175  {
176  dist_1 = dist;
177  index.set_ij(i,j);
178  }
179  }
180  }
181  }
182  }
183  return index;
184 }
185 
186 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
187 //Check if the list of vpImagePoint contains a distant point of less tha 4 pixels
188 //from the center of the sub image (ie the point (15,15).
189 vp_deprecated bool findCenterPoint(vpList<vpImagePoint> *ip_edges_list)
190 {
191  ip_edges_list->front();
192  while (!ip_edges_list->outside())
193  {
194  vpImagePoint iP = ip_edges_list->value();
195  double dist = vpImagePoint::sqrDistance(iP,vpImagePoint(15,15));
196  if (dist <= 16)
197  {
198  return true;
199  }
200  ip_edges_list->next();
201  }
202  return false;
203 }
204 #endif
205 
206 //Check if the list of vpImagePoint contains a distant point of less tha 4 pixels
207 //from the center of the sub image (ie the point (15,15).
208 bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list)
209 {
210  for(std::list<vpImagePoint>::const_iterator it=ip_edges_list->begin(); it!=ip_edges_list->end(); ++it){
211  vpImagePoint iP = *it;
212  double dist = vpImagePoint::sqrDistance(iP, vpImagePoint(15,15));
213  if (dist <= 16)
214  {
215  return true;
216  }
217  }
218  return false;
219 }
220 
221 /***************************************/
222 
227  : nurbs(), dist(0.), nbControlPoints(20), beginPtFound(0), endPtFound(0), enableCannyDetection(false),
228  cannyTh1(100.), cannyTh2(200.)
229 {
230 }
231 
236  : vpMeTracker(menurbs),
237  nurbs(), dist(0.), nbControlPoints(20), beginPtFound(0), endPtFound(0), enableCannyDetection(false),
238  cannyTh1(100.), cannyTh2(200.)
239 {
240  nurbs = menurbs.nurbs;
241  dist = menurbs.dist;
242  nbControlPoints = menurbs.nbControlPoints;
243  beginPtFound = menurbs.beginPtFound;
244  endPtFound = menurbs.endPtFound;
245  enableCannyDetection = menurbs.enableCannyDetection;
246  cannyTh1 = menurbs.cannyTh1;
247  cannyTh2 = menurbs.cannyTh2;
248 }
249 
254 {
255 }
256 
257 
264 void
266 {
267  std::list<vpImagePoint> ptList;
268  vpImagePoint pt;
270 
271  while (vpDisplay::getClick(I, pt, b))
272  {
273  if (b == vpMouseButton::button1)
274  {
275  //std::cout<<pt<<std::endl;
276  ptList.push_back(pt);
278  vpDisplay::flush(I);
279  }
280  if (b == vpMouseButton::button3) break;
281  }
282  if (ptList.size() > 3)
283  initTracking(I, ptList);
284  else
285  throw (vpException(vpException::notInitialized,"Not enough points to initialize the Nurbs"));
286 }
287 
295 void
297  const std::list<vpImagePoint> &ptList)
298 {
299  nurbs.globalCurveInterp(ptList);
300 
301  sample(I);
302 
304  track(I);
305 }
306 
313 void
315 {
316  int rows = (int)I.getHeight() ;
317  int cols = (int)I.getWidth() ;
318  double step = 1.0 / (double)me->getPointsToTrack();
319 
320  // Delete old list
321  list.clear();
322 
323  vpImagePoint ip;
324  double u = 0.0;
325  vpImagePoint *pt = NULL;
326  vpImagePoint pt_1(-rows,-cols);
327  while (u <= 1.0)
328  {
329  if (pt!=NULL) delete[] pt;
330  pt = nurbs.computeCurveDersPoint(u, 1);
331  double delta = computeDelta(pt[1].get_i(),pt[1].get_j());
332 
333  // If point is in the image, add to the sample list
334  if(!outOfImage(pt[0], 0, rows, cols) && vpImagePoint::sqrDistance(pt[0],pt_1) >= vpMath::sqr(me->getSampleStep()))
335  {
336  vpMeSite pix ; //= list.value();
337  pix.init(pt[0].get_i(), pt[0].get_j(), delta) ;
339 
340  list.push_back(pix);
341  pt_1 = pt[0];
342  }
343  u = u+step;
344  }
345  if (pt!=NULL) delete[] pt;
346 }
347 
348 
355 void
357 {
358  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ){
359  vpMeSite s = *it;//current reference pixel
360 
362  {
363  it = list.erase(it);
364  }
365  else
366  ++it;
367  }
368 }
369 
370 
375 void
377 {
378  double u = 0.0;
379  double d = 1e6;
380  double d_1 = 1e6;
381  std::list<vpMeSite>::iterator it=list.begin();
382 
383  vpImagePoint Cu;
384  vpImagePoint* der = NULL;
385  double step = 0.01;
386  while (u < 1 && it!=list.end())
387  {
388  vpMeSite s = *it;
389  vpImagePoint pt(s.i,s.j);
390  while (d <= d_1 && u<1)
391  {
392  Cu = nurbs.computeCurvePoint(u);
393  d_1=d;
394  d = vpImagePoint::distance(pt,Cu);
395  u +=step;
396  }
397 
398  u-=step;
399  if (der != NULL) delete[] der;
400  der = nurbs.computeCurveDersPoint(u, 1);
401  //vpImagePoint toto(der[0].get_i(),der[0].get_j());
402  //vpDisplay::displayCross(I,toto,4,vpColor::red);
403 
404  s.alpha = computeDelta(der[1].get_i(),der[1].get_j());
405  *it = s;
406  ++it;
407  d = 1e6;
408  d_1 = 1.5e6;
409  }
410  if (der != NULL) delete[] der;
411 }
412 
413 
421 void
423 {
424  int rows = (int)I.getHeight() ;
425  int cols = (int)I.getWidth() ;
426 
427  vpImagePoint* begin = NULL;
428  vpImagePoint* end = NULL;
429 
430  begin = nurbs.computeCurveDersPoint(0.0,1);
431  end = nurbs.computeCurveDersPoint(1.0,1);
432 
433  //Check if the two extremities are not to close to eachother.
434  double d = vpImagePoint::distance(begin[0],end[0]);
435  double threshold = 3*me->getSampleStep();
436  double sample_step = me->getSampleStep();
437  vpImagePoint pt;
438  if ( d > threshold /*|| (list.firstValue()).mask_sign != (list.lastValue()).mask_sign*/)
439  {
440  vpMeSite P ;
441 
442  //Init vpMeSite
443  P.init(begin[0].get_i(), begin[0].get_j(), (list.front()).alpha, 0, (list.front()).mask_sign) ;
445 
446  //Set the range
447  unsigned int memory_range = me->getRange() ;
448  me->setRange(2);
449 
450  //Point at the beginning of the list
451  bool beginPtAdded = false;
452  vpImagePoint pt_max = begin[0];
453  double angle = atan2(begin[1].get_i(),begin[1].get_j());
454  double co = vpMath::abs(cos(angle));
455  co = co * vpMath::sign(begin[1].get_j());
456  double si = vpMath::abs(sin(angle));
457  si = si * vpMath::sign(begin[1].get_i());
458  for (int i=0 ; i < 3 ; i++)
459  {
460  P.ifloat = P.ifloat - si*sample_step ; P.i = (int)P.ifloat ;
461  P.jfloat = P.jfloat - co*sample_step ; P.j = (int)P.jfloat ;
462  pt.set_ij(P.ifloat,P.jfloat);
463  if (vpImagePoint::distance(end[0],pt) < threshold) break;
464  if(!outOfImage(P.i, P.j, 5, rows, cols))
465  {
466  P.track(I,me,false);
467 
469  {
470  list.push_front(P) ;
471  beginPtAdded = true;
472  pt_max = pt;
473  if (vpDEBUG_ENABLE(3)) {
475  }
476  }
477  else {
478  if (vpDEBUG_ENABLE(3)) {
480  }
481  }
482  }
483  }
484 
485  if (!beginPtAdded) beginPtFound++;
486 
487  P.init(end[0].get_i(), end[0].get_j(), (list.back()).alpha, 0, (list.back()).mask_sign);
489 
490  bool endPtAdded = false;
491  angle = atan2(end[1].get_i(),end[1].get_j());
492  co = vpMath::abs(cos(angle));
493  co = co * vpMath::sign(end[1].get_j());
494  si = vpMath::abs(sin(angle));
495  si = si * vpMath::sign(end[1].get_i());
496  for (int i=0 ; i < 3 ; i++)
497  {
498  P.ifloat = P.ifloat + si*sample_step ; P.i = (int)P.ifloat ;
499  P.jfloat = P.jfloat + co*sample_step ; P.j = (int)P.jfloat ;
500  pt.set_ij(P.ifloat,P.jfloat);
501  if (vpImagePoint::distance(begin[0],pt) < threshold) break;
502  if(!outOfImage(P.i, P.j, 5, rows, cols))
503  {
504  P.track(I,me,false);
505 
507  {
508  list.push_back(P) ;
509  endPtAdded = true;
510  if (vpDEBUG_ENABLE(3)) {
512  }
513  }
514  else {
515  if (vpDEBUG_ENABLE(3)) {
517  }
518  }
519  }
520  }
521  if (!endPtAdded) endPtFound++;
522  me->setRange(memory_range);
523  }
524  else
525  {
526  list.pop_front();
527  }
528  /*if(begin != NULL)*/ delete[] begin;
529  /*if(end != NULL) */ delete[] end;
530 }
531 
532 
544 #if (defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
545 void
547 #else
548 void
550 #endif
551 {
552 #if (defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
553  vpMeSite pt = list.front();
554  vpImagePoint firstPoint(pt.ifloat,pt.jfloat);
555  pt = list.back();
556  vpImagePoint lastPoint(pt.ifloat,pt.jfloat);
557  if (beginPtFound >=3 && farFromImageEdge(I, firstPoint))
558  {
559  vpImagePoint *begin = NULL;
560  begin = nurbs.computeCurveDersPoint(0.0,1);
561  vpImage<unsigned char> Isub(32,32); //Sub image.
562  vpImagePoint topLeft(begin[0].get_i()-15,begin[0].get_j()-15);
563  vpRect rect(topLeft,32,32);
564 
566 
567  vpImageTools::crop(I,rect,Isub);
568 
569  vpImagePoint lastPtInSubIm(begin[0]);
570  double u = 0.0;
571  double step =0.0001;
572  //Find the point of the nurbs closest from the edge of the subImage and in the subImage.
573  while (inRectangle(lastPtInSubIm,rect) && u < 1)
574  {
575  u += step;
576  lastPtInSubIm = nurbs.computeCurvePoint(u);
577  }
578 
579  u -= step;
580  if( u > 0)
581  lastPtInSubIm = nurbs.computeCurvePoint(u);
582 
583 #if (VISP_HAVE_OPENCV_VERSION >= 0x020408)
584  vpImageFilter::canny(Isub, Isub, 3, cannyTh1, 3);
585 #else
586  IplImage* Ip = NULL;
587  vpImageConvert::convert(Isub, Ip);
588 
589  IplImage* dst = cvCreateImage( cvSize((int)Isub.getWidth(), (int)Isub.getHeight()), 8, 1 );
590  cvCanny( Ip, dst, cannyTh1, cannyTh2, 3 );
591 
592  vpImageConvert::convert(dst, Isub);
593 #endif
594 
595  vpImagePoint firstBorder(-1,-1);
596 
597  firstBorder = findFirstBorder(Isub, lastPtInSubIm-topLeft);
598 
599  std::list<vpImagePoint> ip_edges_list;
600  if (firstBorder != vpImagePoint(-1, -1))
601  {
602  unsigned int dir;
603  double fi = firstBorder.get_i();
604  double fj = firstBorder.get_j();
605  double w = Isub.getWidth()-1;
606  double h = Isub.getHeight()-1;
607  //if (firstBorder.get_i() == 0) dir = 4;
608  if (std::fabs(fi) <= std::numeric_limits<double>::epsilon()) dir = 4;
609  //else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
610  else if (std::fabs(fi-h) <= std::fabs(vpMath::maximum(fi,h))*std::numeric_limits<double>::epsilon()) dir = 0;
611  //else if (firstBorder.get_j() == 0) dir = 2;
612  else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon()) dir = 2;
613  //else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
614  else if (std::fabs(fj-w) <= std::fabs(vpMath::maximum(fj,w))*std::numeric_limits<double>::epsilon()) dir = 6;
615  computeFreemanChainElement(Isub, firstBorder , dir);
616  unsigned int firstDir = dir;
617  ip_edges_list.push_back( firstBorder );
618  vpImagePoint border(firstBorder);
619  vpImagePoint dBorder;
620  do
621  {
622  computeFreemanParameters(dir, dBorder);
623  border = border + dBorder;
624  vpDisplay::displayPoint(I, border+topLeft, vpColor::orange) ;
625 
626  ip_edges_list.push_back( border );
627 
628  computeFreemanChainElement(Isub, border , dir);
629  } while( (border != firstBorder || dir != firstDir) && isInImage(Isub,border) );
630  }
631 
632  if (findCenterPoint(&ip_edges_list))
633  {
634  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); /*++it*/){
635  vpMeSite s = *it;
636  vpImagePoint iP(s.ifloat,s.jfloat);
637  if (inRectangle(iP,rect))
638  it = list.erase(it) ;
639  else
640  break;
641  }
642 
643  std::list<vpMeSite>::iterator itList=list.begin();
644  double convlt;
645  double delta = 0;
646  int nbr = 0;
647  std::list<vpMeSite> addedPt;
648  for(std::list<vpImagePoint>::const_iterator itEdges=ip_edges_list.begin(); itEdges!=ip_edges_list.end(); ++itEdges){
649  vpMeSite s = *itList;
650  vpImagePoint iPtemp = *itEdges + topLeft;
651  vpMeSite pix;
652  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta);
653  dist = vpMeSite::sqrDistance(s,pix);
654  if (dist >= vpMath::sqr(me->getSampleStep())/*25*/)
655  {
656  bool exist = false;
657  for(std::list<vpMeSite>::const_iterator itAdd=addedPt.begin(); itAdd!=addedPt.end(); ++itAdd){
658  dist = vpMeSite::sqrDistance(pix, *itAdd);
659  if (dist < vpMath::sqr(me->getSampleStep())/*25*/)
660  exist = true;
661  }
662  if (!exist)
663  {
664  findAngle(I, iPtemp, me, delta, convlt);
665  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
666  pix.setDisplay(selectDisplay);
667  --itList;
668  list.insert(itList, pix);
669  ++itList;
670  addedPt.push_front(pix);
671  nbr++;
672  }
673  }
674  }
675 
676  unsigned int memory_range = me->getRange();
677  me->setRange(3);
678  std::list<vpMeSite>::iterator itList2=list.begin();
679  for (int j = 0; j < nbr; j++)
680  {
681  vpMeSite s = *itList2;
682  s.track(I,me,false);
683  *itList2 = s;
684  ++itList2;
685  }
686  me->setRange(memory_range);
687  }
688 
689  /* if (begin != NULL) */ delete[] begin;
690  beginPtFound = 0;
691  }
692 
693  if(endPtFound >= 3 && farFromImageEdge(I, lastPoint))
694  {
695  vpImagePoint *end = NULL;
696  end = nurbs.computeCurveDersPoint(1.0,1);
697 
698  vpImage<unsigned char> Isub(32,32); //Sub image.
699  vpImagePoint topLeft(end[0].get_i()-15,end[0].get_j()-15);
700  vpRect rect(topLeft,32,32);
701 
703 
704  vpImageTools::crop(I,rect,Isub);
705 
706  vpImagePoint lastPtInSubIm(end[0]);
707  double u = 1.0;
708  double step =0.0001;
709  //Find the point of the nurbs closest from the edge of the subImage and in the subImage.
710  while (inRectangle(lastPtInSubIm,rect) && u > 0)
711  {
712  u -= step;
713  lastPtInSubIm = nurbs.computeCurvePoint(u);
714  }
715 
716  u += step;
717  if( u < 1.0)
718  lastPtInSubIm = nurbs.computeCurvePoint(u);
719 
720 #if (VISP_HAVE_OPENCV_VERSION >= 0x020408)
721  vpImageFilter::canny(Isub, Isub, 3, cannyTh1, 3);
722 #else
723  IplImage* Ip = NULL;
724  vpImageConvert::convert(Isub, Ip);
725 
726  IplImage* dst = cvCreateImage( cvSize((int)Isub.getWidth(), (int)Isub.getHeight()), 8, 1 );
727  cvCanny( Ip, dst, cannyTh1, cannyTh2, 3 );
728 
729  vpImageConvert::convert(dst, Isub);
730 #endif
731 
732  vpImagePoint firstBorder(-1,-1);
733 
734  firstBorder = findFirstBorder(Isub, lastPtInSubIm-topLeft);
735 
736  std::list<vpImagePoint> ip_edges_list;
737  if (firstBorder != vpImagePoint(-1, -1))
738  {
739  unsigned int dir;
740  double fi = firstBorder.get_i();
741  double fj = firstBorder.get_j();
742  double w = Isub.getWidth()-1;
743  double h = Isub.getHeight()-1;
744  //if (firstBorder.get_i() == 0) dir = 4;
745  if (std::fabs(fi) <= std::numeric_limits<double>::epsilon()) dir = 4;
746  //else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
747  else if (std::fabs(fi-h) <= std::fabs(vpMath::maximum(fi,h))*std::numeric_limits<double>::epsilon()) dir = 0;
748  //else if (firstBorder.get_j() == 0) dir = 2;
749  else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon()) dir = 2;
750  //else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
751  else if (std::fabs(fj-w) <= std::fabs(vpMath::maximum(fj,w))*std::numeric_limits<double>::epsilon()) dir = 6;
752 
753 
754  computeFreemanChainElement(Isub, firstBorder , dir);
755  unsigned int firstDir = dir;
756  ip_edges_list.push_back( firstBorder );
757  vpImagePoint border(firstBorder);
758  vpImagePoint dBorder;
759  do
760  {
761  computeFreemanParameters(dir, dBorder);
762  border = border + dBorder;
763  vpDisplay::displayPoint(I, border+topLeft, vpColor::orange) ;
764 
765  ip_edges_list.push_back( border );
766 
767  computeFreemanChainElement(Isub, border , dir);
768  } while( (border != firstBorder || dir != firstDir) && isInImage(Isub,border) );
769  }
770 
771  if (findCenterPoint(&ip_edges_list))
772  {
773 // list.end();
774  vpMeSite s;
775  while(true)//{//!list.outside())
776  {
777  s = list.back();//list.value() ;
778  vpImagePoint iP(s.ifloat,s.jfloat);
779  if (inRectangle(iP,rect))
780  {
781  list.erase(list.end()) ;
782 // list.end();
783  }
784  else
785  break;
786  }
787 
788  std::list<vpMeSite>::iterator itList = list.end();
789  --itList; // Move on the last element
790  double convlt;
791  double delta;
792  int nbr = 0;
793  std::list<vpMeSite> addedPt;
794  for(std::list<vpImagePoint>::const_iterator itEdges=ip_edges_list.begin(); itEdges!=ip_edges_list.end(); ++itEdges){
795  s = *itList;
796  vpImagePoint iPtemp = *itEdges + topLeft;
797  vpMeSite pix;
798  pix.init(iPtemp.get_i(), iPtemp.get_j(), 0);
799  dist = vpMeSite::sqrDistance(s,pix);
800  if (dist >= vpMath::sqr(me->getSampleStep()))
801  {
802  bool exist = false;
803  for(std::list<vpMeSite>::const_iterator itAdd=addedPt.begin(); itAdd!=addedPt.end(); ++itAdd){
804  dist = vpMeSite::sqrDistance(pix, *itAdd);
805  if (dist < vpMath::sqr(me->getSampleStep()))
806  exist = true;
807  }
808  if (!exist)
809  {
810  findAngle(I, iPtemp, me, delta, convlt);
811  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
812  pix.setDisplay(selectDisplay);
813  list.push_back(pix);
814  addedPt.push_back(pix);
815  nbr++;
816  }
817  }
818  }
819 
820  unsigned int memory_range = me->getRange();
821  me->setRange(3);
822  std::list<vpMeSite>::iterator itList2 = list.end();
823  --itList2; // Move to the last element
824  for (int j = 0; j < nbr; j++)
825  {
826  vpMeSite me_s = *itList2;
827  me_s.track(I,me,false);
828  *itList2 = me_s;
829  --itList2;
830  }
831  me->setRange(memory_range);
832  }
833 
834  /* if (end != NULL) */ delete[] end;
835  endPtFound = 0;
836  }
837 #else
838  vpTRACE("To use the canny detection, OpenCV has to be installed.");
839 #endif
840 }
841 
842 
853 void
855 {
856  unsigned int n = numberOfSignal();
857  double nbPt = floor(dist / me->getSampleStep());
858 
859  if ((double)n < 0.7*nbPt)
860  {
861  sample(I);
863  }
864 }
865 
866 
873 void
875 {
876  int rows = (int)I.getHeight() ;
877  int cols = (int)I.getWidth() ;
878  vpImagePoint* iP = NULL;
879 
880  int n = (int)numberOfSignal();
881 
882 // list.front();
883  std::list<vpMeSite>::iterator it=list.begin();
884  std::list<vpMeSite>::iterator itNext=list.begin();
885  ++itNext;
886 
887  unsigned int range_tmp = me->getRange();
888  me->setRange(2);
889 
890  while(itNext!=list.end() && n <= me->getPointsToTrack())
891  {
892  vpMeSite s = *it;//current reference pixel
893  vpMeSite s_next = *itNext;//current reference pixel
894 
895  double d = vpMeSite::sqrDistance(s,s_next);
896  if(d > 4 * vpMath::sqr(me->getSampleStep()) && d < 1600)
897  {
898  vpImagePoint iP0(s.ifloat,s.jfloat);
899  vpImagePoint iPend(s_next.ifloat,s_next.jfloat);
900  vpImagePoint iP_1(s.ifloat,s.jfloat);
901 
902  double u = 0.0;
903  double ubegin = 0.0;
904  double uend = 0.0;
905  double dmin1_1 = 1e6;
906  double dmin2_1 = 1e6;
907  while(u < 1)
908  {
909  u+=0.01;
910  double dmin1 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u),iP0);
911  double dmin2 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u),iPend);
912 
913  if (dmin1 < dmin1_1)
914  {
915  dmin1_1 = dmin1;
916  ubegin = u;
917  }
918 
919  if (dmin2 < dmin2_1)
920  {
921  dmin2_1 = dmin2;
922  uend = u;
923  }
924  }
925  u = ubegin;
926 
927  //if(( u != 1.0 || uend != 1.0)
928  if( (std::fabs(u-1.0) > std::fabs(vpMath::maximum(u, 1.0))*std::numeric_limits<double>::epsilon())
929  || (std::fabs(uend-1.0) > std::fabs(vpMath::maximum(uend, 1.0))*std::numeric_limits<double>::epsilon()))
930  {
931  iP = nurbs.computeCurveDersPoint(u, 1);
932 
933  while (vpImagePoint::sqrDistance(iP[0],iPend) > vpMath::sqr(me->getSampleStep()) && u < uend)
934  {
935  u+=0.01;
936  /*if (iP!=NULL)*/ {
937  delete[] iP;
938  iP = NULL;
939  }
940  iP = nurbs.computeCurveDersPoint(u, 1);
941  if ( vpImagePoint::sqrDistance(iP[0],iP_1) > vpMath::sqr(me->getSampleStep()) && !outOfImage(iP[0], 0, rows, cols))
942  {
943  double delta = computeDelta(iP[1].get_i(),iP[1].get_j());
944  vpMeSite pix ; //= list.value();
945  pix.init(iP[0].get_i(), iP[0].get_j(), delta) ;
947  pix.track(I,me,false);
948  if (pix.getState() == vpMeSite::NO_SUPPRESSION)
949  {
950  list.insert(it, pix);
951  iP_1 = iP[0];
952  }
953  }
954  }
955  /*if (iP!=NULL)*/ {
956  delete[] iP;
957  iP = NULL;
958  }
959  }
960  }
961  ++it;
962  ++itNext;
963  }
964  me->setRange(range_tmp);
965 }
966 
967 
973 void
975 {
976 #if 0
977  // Loop through list of sites to track
978  list.front();
979  while(!list.nextOutside())
980  {
981  vpMeSite s = list.value() ;//current reference pixel
982  vpMeSite s_next = list.nextValue() ;//current reference pixel
983 
984  if(vpMeSite::sqrDistance(s,s_next) < vpMath::sqr(me->getSampleStep()))
985  {
987 
988  list.next();
989  list.modify(s_next);
990  if (!list.nextOutside()) list.next();
991  }
992  else
993  list.next() ;
994  }
995 #endif
996  std::list<vpMeSite>::const_iterator it=list.begin();
997  std::list<vpMeSite>::iterator itNext=list.begin();
998  ++itNext;
999  for(;itNext!=list.end();){
1000  vpMeSite s = *it;//current reference pixel
1001  vpMeSite s_next = *itNext;//current reference pixel
1002 
1003  if(vpMeSite::sqrDistance(s,s_next) < vpMath::sqr(me->getSampleStep())){
1004  s_next.setState(vpMeSite::TOO_NEAR);
1005 
1006  *itNext = s_next;
1007  ++it;
1008  ++itNext;
1009  if(itNext!=list.end()){
1010  ++it;
1011  ++itNext;
1012  }
1013  }
1014  else{
1015  ++it;
1016  ++itNext;
1017  }
1018  }
1019 }
1020 
1021 
1027 void
1029 {
1030  //Tracking des vpMeSites
1031  vpMeTracker::track(I);
1032 
1033  //Suppress points which are too close to each other
1035 
1036  //Suppressions des points ejectes par le tracking
1037  suppressPoints();
1038 
1039  if (list.size() == 1)
1040  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "Not enough valid me to track"));
1041 
1042  //Recalcule les parametres
1043 // nurbs.globalCurveInterp(list);
1044  nurbs.globalCurveApprox(list,nbControlPoints);
1045 
1046  //On resample localement
1047  localReSample(I);
1048 
1049  seekExtremities(I);
1050  if(enableCannyDetection)
1052 
1053 // nurbs.globalCurveInterp(list);
1054  nurbs.globalCurveApprox(list,nbControlPoints);
1055 
1056  double u = 0.0;
1057  vpImagePoint pt;
1058  vpImagePoint pt_1;
1059  dist = 0;
1060  while (u<=1.0)
1061  {
1062  pt = nurbs.computeCurvePoint(u);
1063  //if(u!=0)
1064  if(std::fabs(u) > std::numeric_limits<double>::epsilon())
1065  dist = dist + vpImagePoint::distance(pt,pt_1);
1066  pt_1 = pt;
1067  u=u+0.01;
1068  }
1069 
1070  updateDelta();
1071 
1072  reSample(I);
1073 }
1074 
1075 
1086 void
1088 {
1089  vpMeNurbs::display(I,nurbs,col);
1090 }
1091 
1092 
1109 bool
1110 vpMeNurbs::computeFreemanChainElement(const vpImage<unsigned char> &I,
1111  vpImagePoint &iP,
1112  unsigned int &element)
1113 {
1114  vpImagePoint diP;
1115  vpImagePoint iPtemp;
1116  if (hasGoodLevel( I, iP )) {
1117  // get the point on the right of the point passed in
1118  computeFreemanParameters((element + 2) %8, diP);
1119  iPtemp = iP + diP;
1120  if (hasGoodLevel( I, iPtemp )) {
1121  element = (element + 2) % 8; // turn right
1122  }
1123  else {
1124  computeFreemanParameters((element + 1) %8, diP);
1125  iPtemp = iP + diP;
1126 
1127  if ( hasGoodLevel( I, iPtemp )) {
1128  element = (element + 1) % 8; // turn diag right
1129  }
1130  else {
1131  computeFreemanParameters(element, diP);
1132  iPtemp = iP + diP;
1133 
1134  if ( hasGoodLevel( I, iPtemp )) {
1135  //element = element; // keep same dir
1136  }
1137  else {
1138  computeFreemanParameters((element + 7) %8, diP);
1139  iPtemp = iP + diP;
1140 
1141  if ( hasGoodLevel( I, iPtemp )) {
1142  element = (element + 7) %8; // turn diag left
1143  }
1144  else {
1145  computeFreemanParameters((element + 6) %8, diP);
1146  iPtemp = iP + diP;
1147 
1148  if ( hasGoodLevel( I, iPtemp )) {
1149  element = (element + 6) %8 ; // turn left
1150  }
1151  else {
1152  computeFreemanParameters((element + 5) %8, diP);
1153  iPtemp = iP + diP;
1154 
1155  if ( hasGoodLevel( I, iPtemp )) {
1156  element = (element + 5) %8 ; // turn diag down
1157  }
1158  else {
1159  computeFreemanParameters((element + 4) %8, diP);
1160  iPtemp = iP + diP;
1161 
1162  if ( hasGoodLevel( I, iPtemp )) {
1163  element = (element + 4) %8 ; // turn down
1164  }
1165  else {
1166  computeFreemanParameters((element + 3) %8, diP);
1167  iPtemp = iP + diP;
1168 
1169  if ( hasGoodLevel( I, iPtemp )) {
1170  element = (element + 3) %8 ; // turn diag right down
1171  }
1172  else {
1173  // No neighbor with a good level
1174  //
1175  return false;
1176  }
1177  }
1178  }
1179  }
1180  }
1181  }
1182  }
1183  }
1184  }
1185  else {
1186  return false;
1187  }
1188  return true;
1189 }
1190 
1191 
1204 bool vpMeNurbs::hasGoodLevel(const vpImage<unsigned char>& I,
1205  const vpImagePoint& iP) const
1206 {
1207  if( !isInImage( I, iP ) )
1208  return false;
1209 
1210  if( I((unsigned int)vpMath::round(iP.get_i()), (unsigned int)vpMath::round(iP.get_j())) > 0)
1211  {
1212  return true;
1213  }
1214  else
1215  {
1216  return false;
1217  }
1218 }
1219 
1220 
1231 bool vpMeNurbs::isInImage(const vpImage<unsigned char>& I, const vpImagePoint &iP) const
1232 {
1233  return (iP.get_i() >= 0
1234  && iP.get_j() >= 0
1235  && iP.get_i() < I.getHeight()
1236  && iP.get_j() < I.getWidth());
1237 }
1238 
1239 
1255 void
1256 vpMeNurbs::computeFreemanParameters( unsigned int element, vpImagePoint &diP)
1257 {
1258  /*
1259  5 6 7
1260  \ | /
1261  \|/
1262  4 ------- 0
1263  /|\
1264  / | \
1265  3 2 1
1266  */
1267  switch(element) {
1268  case 0: // go right
1269  diP.set_ij(0,1);
1270  break;
1271 
1272  case 1: // go right top
1273  diP.set_ij(1,1);
1274  break;
1275 
1276  case 2: // go top
1277  diP.set_ij(1,0);
1278  break;
1279 
1280  case 3:
1281  diP.set_ij(1,-1);
1282  break;
1283 
1284  case 4:
1285  diP.set_ij(0,-1);
1286  break;
1287 
1288  case 5:
1289  diP.set_ij(-1,-1);
1290  break;
1291 
1292  case 6:
1293  diP.set_ij(-1,0);
1294  break;
1295 
1296  case 7:
1297  diP.set_ij(-1,1);
1298  break;
1299  }
1300 }
1301 
1302 
1311 bool
1312 vpMeNurbs::farFromImageEdge(const vpImage<unsigned char>& I, const vpImagePoint& iP)
1313 {
1314  unsigned int height = I.getHeight();
1315  unsigned int width = I.getWidth();
1316  return (iP.get_i() < height - 20
1317  && iP.get_j() < width - 20
1318  && iP.get_i() > 20
1319  && iP.get_j() > 20);
1320 }
1321 
1333 {
1334  double u = 0.0;
1335  vpImagePoint pt;
1336  while (u <= 1)
1337  {
1338  pt = n.computeCurvePoint(u);
1339  vpDisplay::displayCross(I,pt,4,color);
1340  u+=0.01;
1341  }
1342 }
1343 
1355 {
1356  double u = 0.0;
1357  vpImagePoint pt;
1358  while (u <= 1)
1359  {
1360  pt = n.computeCurvePoint(u);
1361  vpDisplay::displayCross(I,pt,4,color);
1362  u+=0.01;
1363  }
1364 }
1365 
unsigned int getRange() const
Definition: vpMe.h:167
unsigned int getMaskSize() const
Definition: vpMe.h:131
void suppressPoints()
Definition: vpMeNurbs.cpp:356
virtual ~vpMeNurbs()
Definition: vpMeNurbs.cpp:253
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
void init()
Definition: vpMeSite.cpp:69
double get_i() const
Definition: vpImagePoint.h:199
bool outside(void) const
Test if the current element is outside the list (on the virtual element)
Definition: vpList.h:434
unsigned int getWidth() const
Definition: vpImage.h:226
double jfloat
Definition: vpMeSite.h:96
#define vpDEBUG_ENABLE(level)
Definition: vpDebug.h:526
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
unsigned int numberOfSignal()
static vpImagePoint computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:96
void track(const vpImage< unsigned char > &Im)
Definition: vpMeNurbs.cpp:1028
void seekExtremitiesCanny(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:546
Provide simple list management.
Definition: vpList.h:118
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
int outOfImage(int i, int j, int half, int rows, int cols)
double alpha
Definition: vpMeSite.h:100
int i
Definition: vpMeSite.h:94
error that can be emited by ViSP classes.
Definition: vpException.h:73
void initTracking(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:265
static void globalCurveInterp(std::vector< vpImagePoint > &l_crossingPoints, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:695
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
Definition: vpMe.h:59
Class that tracks in an image a edge defined by a Nurbs.
Definition: vpMeNurbs.h:125
static const vpColor green
Definition: vpColor.h:166
static void flush(const vpImage< unsigned char > &I)
static int round(const double x)
Definition: vpMath.h:249
double get_j() const
Definition: vpImagePoint.h:210
void next(void)
position the current element on the next one
Definition: vpList.h:278
static Type abs(const Type &x)
Definition: vpMath.h:161
vpMeSiteState getState() const
Definition: vpMeSite.h:198
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:140
static const vpColor orange
Definition: vpColor.h:173
double ifloat
Definition: vpMeSite.h:96
int getStrip() const
Definition: vpMe.h:173
std::list< vpMeSite > list
Definition: vpMeTracker.h:73
unsigned int getAngleStep() const
Definition: vpMe.h:104
Error that can be emited by the vpTracker class and its derivates.
void supressNearPoints()
Definition: vpMeNurbs.cpp:974
#define vpTRACE
Definition: vpDebug.h:414
static double sqr(double x)
Definition: vpMath.h:110
void display(const vpImage< unsigned char > &I, vpColor col)
Definition: vpMeNurbs.cpp:1087
void front(void)
Position the current element on the first element of the list.
Definition: vpList.h:389
type & value(void)
return the value of the current element
Definition: vpList.h:306
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 reSample(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:854
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
static double sqrDistance(const vpMeSite S1, const vpMeSite S2)
Definition: vpMeSite.h:240
void sample(const vpImage< unsigned char > &image)
Definition: vpMeNurbs.cpp:314
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:185
static void globalCurveApprox(std::vector< vpImagePoint > &l_crossingPoints, unsigned int l_p, unsigned int l_n, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:872
static double rad(double deg)
Definition: vpMath.h:104
void localReSample(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:874
int getPointsToTrack() const
Definition: vpMe.h:161
vpMatrix * getMask() const
Definition: vpMe.h:110
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:94
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
Definition: vpImageTools.h:266
static double sqrDistance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:294
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:374
void seekExtremities(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:422
void initTracking(const vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:175
Defines a rectangle in the plane.
Definition: vpRect.h:82
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static void canny(const vpImage< unsigned char > &I, vpImage< unsigned char > &Ic, const unsigned int gaussianFilterSize, const double thresholdCanny, const unsigned int apertureSobel)
vpNurbs nurbs
The Nurbs which represents the tracked edge.
Definition: vpMeNurbs.h:133
void setRange(const unsigned int &r)
Definition: vpMe.h:256
double getSampleStep() const
Definition: vpMe.h:270
static int() sign(double x)
Definition: vpMath.h:275
vpMeSite::vpMeSiteDisplayType selectDisplay
Definition: vpMeTracker.h:80
Class that provides tools to compute and manipulate a Non Uniform Rational B-Spline curve...
Definition: vpNurbs.h:85
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:279
void set_ij(const double ii, const double jj)
Definition: vpImagePoint.h:185
static vpImagePoint * computeCurveDersPoint(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:266
static const vpColor blue
Definition: vpColor.h:169
void updateDelta()
Definition: vpMeNurbs.cpp:376