ViSP  2.6.2
vpMeNurbs.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMeNurbs.cpp 3672 2012-04-04 15:49:57Z ayol $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2012 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  * Nicolas Melchior
39  *
40  *****************************************************************************/
41 
42 
51 #include <visp/vpMeTracker.h>
52 #include <visp/vpMe.h>
53 #include <visp/vpMeSite.h>
54 #include <visp/vpMeNurbs.h>
55 #include <visp/vpRobust.h>
56 #include <visp/vpTrackingException.h>
57 #include <visp/vpImagePoint.h>
58 #include <visp/vpMath.h>
59 #include <visp/vpRect.h>
60 #include <visp/vpImageTools.h>
61 #include <visp/vpImageConvert.h>
62 #include <stdlib.h>
63 #include <cmath> // std::fabs
64 #include <limits> // numeric_limits
65 #ifdef VISP_HAVE_OPENCV
66 # if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
67 //# include <opencv2/imgproc/imgproc.hpp>
68 # include <opencv2/imgproc/imgproc_c.h>
69 # else
70 # include <cv.h>
71 # endif
72 #endif
73 
74 //Compute the angle delta = arctan(deltai/deltaj)
75 //and normalize it between 0 and pi
76 double
77 computeDelta(double deltai, double deltaj)
78 {
79  double delta;
80  delta = atan2(deltai,deltaj) ;
81  delta -= M_PI/2.0 ;
82  while (delta > M_PI) { delta -= M_PI ; }
83  while (delta < 0) { delta += M_PI ; }
84  return(delta);
85 }
86 
87 //Check if the image point is in the image and not to close to
88 //its edge to enable the computation of a convolution whith a mask.
89 static
90 bool outOfImage( vpImagePoint iP , int half , int rows , int cols)
91 {
92  return((iP.get_i() < half + 1) || ( iP.get_i() > (rows - half - 3) )
93  ||(iP.get_j() < half + 1) || (iP.get_j() > (cols - half - 3) )) ;
94 }
95 
96 //if iP is a edge point, it computes the angle corresponding to the
97 //highest convolution result. the angle is between 0 an 179.
98 //The result gives the angle in RADIAN + pi/2 (to deal with the moving edeg alpha angle)
99 //and the corresponding convolution result.
100 void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP,
101  vpMe* me, double &angle, double &convlt)
102 {
103  int Iheight = (int)I.getHeight();
104  int Iwidth = (int)I.getWidth();
105  angle = 0.0;
106  convlt = 0.0;
107  for (int i = 0; i < 180; i++)
108  {
109  double conv = 0.0;
110  unsigned int half;
111  int index_mask;
112  half = (me->getMaskSize() - 1) >> 1 ;
113 
114  if(outOfImage( iP , (int)half + me->getStrip() , Iheight, Iwidth))
115  {
116  conv = 0.0 ;
117  }
118  else
119  {
120  if (me->getAngleStep() !=0)
121  index_mask = (int)(i/(double)me->getAngleStep());
122  else
123  throw (vpException(vpException::divideByZeroError,"angle step = 0"));
124 
125  unsigned int ihalf = (unsigned int)(iP.get_i()-half) ;
126  unsigned int jhalf = (unsigned int)(iP.get_j()-half) ;
127  unsigned int ihalfa ;
128  unsigned int a ;
129  unsigned int b ;
130  for( a = 0 ; a < me->getMaskSize() ; a++ )
131  {
132  ihalfa = ihalf+a ;
133  for( b = 0 ; b < me->getMaskSize() ; b++ )
134  {
135  conv += me->getMask()[index_mask][a][b] *
136  I(ihalfa,jhalf+b) ;
137  }
138  }
139  }
140  conv = fabs(conv);
141  if (conv > convlt)
142  {
143  convlt = conv;
144  angle = vpMath::rad(i);
145  angle += M_PI/2;
146  while (angle > M_PI) { angle -= M_PI ; }
147  while (angle < 0) { angle += M_PI ; }
148  }
149  }
150 }
151 
152 
153 //Find the point belonging to the edge of the sub image which respects the following hypotheses:
154 //- the value of the pixel is upper than zero.
155 //- the distantce between the point and iP is less than 4 pixels.
156 //The function returns the nearest point of iP which respect the hypotheses
157 //If no point is found the returned point is (-1,-1)
158 vpImagePoint findFirstBorder(const vpImage<unsigned char>& Isub, const vpImagePoint &iP)
159 {
160  double dist = 1e6;
161  double dist_1 = 1e6;
162  vpImagePoint index(-1,-1);
163  for (unsigned int i = 0; i <= Isub.getHeight(); i++)
164  {
165  for (unsigned int j = 0; j <= Isub.getWidth(); j++)
166  {
167  if(i == 0 || i == Isub.getHeight()-1 || j == 0 || j == Isub.getWidth()-1)
168  {
169  if (Isub(i,j) > 0)
170  {
172  if (dist <= 16 && dist < dist_1)
173  {
174  dist_1 = dist;
175  index.set_ij(i,j);
176  }
177  }
178  }
179  }
180  }
181  return index;
182 }
183 
184 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
185 //Check if the list of vpImagePoint contains a distant point of less tha 4 pixels
186 //from the center of the sub image (ie the point (15,15).
187 vp_deprecated bool findCenterPoint(vpList<vpImagePoint> *ip_edges_list)
188 {
189  ip_edges_list->front();
190  double dist;
191  while (!ip_edges_list->outside())
192  {
193  vpImagePoint iP = ip_edges_list->value();
194  dist = vpImagePoint::sqrDistance(iP,vpImagePoint(15,15));
195  if (dist <= 16)
196  {
197  return true;
198  }
199  ip_edges_list->next();
200  }
201  return false;
202 }
203 #endif
204 
205 //Check if the list of vpImagePoint contains a distant point of less tha 4 pixels
206 //from the center of the sub image (ie the point (15,15).
207 bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list)
208 {
209  double dist;
210  for(std::list<vpImagePoint>::const_iterator it=ip_edges_list->begin(); it!=ip_edges_list->end(); ++it){
211  vpImagePoint iP = *it;
212  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 {
228  nbControlPoints = 20;
229  beginPtFound = 0;
230  endPtFound =0;
231  enableCannyDetection = false;
232  cannyTh1 = 100.0;
233  cannyTh2 = 200.0;
234 }
235 
240 {
241  nurbs = menurbs.nurbs;
242  dist = menurbs.dist;
243  nbControlPoints = menurbs.nbControlPoints;
244  beginPtFound = menurbs.beginPtFound;
245  endPtFound = menurbs.endPtFound;
246  enableCannyDetection = menurbs.enableCannyDetection;
247  cannyTh1 = menurbs.cannyTh1;
248  cannyTh2 = menurbs.cannyTh2;
249 }
250 
255 {
256 }
257 
258 
265 void
267 {
268  std::list<vpImagePoint> ptList;
269  vpImagePoint pt;
271 
272  while (vpDisplay::getClick(I, pt, b))
273  {
274  if (b == vpMouseButton::button1)
275  {
276  //std::cout<<pt<<std::endl;
277  ptList.push_back(pt);
279  vpDisplay::flush(I);
280  }
281  if (b == vpMouseButton::button3) break;
282  }
283  if (ptList.size() > 3)
284  initTracking(I, ptList);
285  else
286  throw (vpException(vpException::notInitialized,"Not enough points to initialize the Nurbs"));
287 }
288 
289 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
290 
300 vp_deprecated void
302  vpList<vpImagePoint> &ptList)
303 {
304  std::list<vpImagePoint> listStd;
305  for(ptList.front(); !ptList.outside(); ptList.next()){
306  listStd.push_back(ptList.value());
307  }
308  nurbs.globalCurveInterp(listStd);
309 
310  sample(I);
311 
313  track(I);
314 }
315 #endif
316 
324 void
326  const std::list<vpImagePoint> &ptList)
327 {
328  nurbs.globalCurveInterp(ptList);
329 
330  sample(I);
331 
333  track(I);
334 }
335 
342 void
344 {
345  int rows = (int)I.getHeight() ;
346  int cols = (int)I.getWidth() ;
347  double step = 1.0 / (double)me->getPointsToTrack();
348 
349  // Delete old list
350  list.clear();
351 
352  vpImagePoint ip;
353  double u = 0.0;
354  vpImagePoint *pt = NULL;
355  vpImagePoint pt_1(-rows,-cols);
356  while (u <= 1.0)
357  {
358  if (pt!=NULL) delete[] pt;
359  pt = nurbs.computeCurveDersPoint(u, 1);
360  double delta = computeDelta(pt[1].get_i(),pt[1].get_j());
361 
362  // If point is in the image, add to the sample list
363  if(!outOfImage(pt[0], 0, rows, cols) && vpImagePoint::sqrDistance(pt[0],pt_1) >= vpMath::sqr(me->getSampleStep()))
364  {
365  vpMeSite pix ; //= list.value();
366  pix.init(pt[0].get_i(), pt[0].get_j(), delta) ;
368 
369  list.push_back(pix);
370  pt_1 = pt[0];
371  }
372  u = u+step;
373  }
374  if (pt!=NULL) delete[] pt;
375 }
376 
377 
384 void
386 {
387  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ){
388  vpMeSite s = *it;//current reference pixel
389 
391  {
392  it = list.erase(it);
393  }
394  else
395  ++it;
396  }
397 }
398 
399 
404 void
406 {
407  double u = 0.0;
408  double d = 1e6;
409  double d_1 = 1e6;
410  std::list<vpMeSite>::iterator it=list.begin();
411 
412  vpImagePoint Cu;
413  vpImagePoint* der = NULL;
414  double step = 0.01;
415  while (u < 1 && it!=list.end())
416  {
417  vpMeSite s = *it;
418  vpImagePoint pt(s.i,s.j);
419  while (d <= d_1 && u<1)
420  {
421  Cu = nurbs.computeCurvePoint(u);
422  d_1=d;
423  d = vpImagePoint::distance(pt,Cu);
424  u +=step;
425  }
426 
427  u-=step;
428  if (der != NULL) delete[] der;
429  der = nurbs.computeCurveDersPoint(u, 1);
430  //vpImagePoint toto(der[0].get_i(),der[0].get_j());
431  //vpDisplay::displayCross(I,toto,4,vpColor::red);
432 
433  s.alpha = computeDelta(der[1].get_i(),der[1].get_j());
434  *it = s;
435  ++it;
436  d = 1e6;
437  d_1 = 1.5e6;
438  }
439  if (der != NULL) delete[] der;
440 }
441 
442 
450 void
452 {
453  int rows = (int)I.getHeight() ;
454  int cols = (int)I.getWidth() ;
455 
456  vpImagePoint* begin = NULL;
457  vpImagePoint* end = NULL;
458 
459  begin = nurbs.computeCurveDersPoint(0.0,1);
460  end = nurbs.computeCurveDersPoint(1.0,1);
461 
462  //Check if the two extremities are not to close to eachother.
463  double d = vpImagePoint::distance(begin[0],end[0]);
464  double threshold = 3*me->getSampleStep();
465  double sample = me->getSampleStep();
466  vpImagePoint pt;
467  if ( d > threshold /*|| (list.firstValue()).mask_sign != (list.lastValue()).mask_sign*/)
468  {
469  vpMeSite P ;
470 
471  //Init vpMeSite
472  P.init(begin[0].get_i(), begin[0].get_j(), (list.front()).alpha, 0, (list.front()).mask_sign) ;
474 
475  //Set the range
476  unsigned int memory_range = me->getRange() ;
477  me->setRange(2);
478 
479  //Point at the beginning of the list
480  bool beginPtAdded = false;
481  vpImagePoint pt_max = begin[0];
482  double angle = atan2(begin[1].get_i(),begin[1].get_j());
483  double co = vpMath::abs(cos(angle));
484  co = co * vpMath::sign(begin[1].get_j());
485  double si = vpMath::abs(sin(angle));
486  si = si * vpMath::sign(begin[1].get_i());
487  for (int i=0 ; i < 3 ; i++)
488  {
489  P.ifloat = P.ifloat - si*sample ; P.i = (int)P.ifloat ;
490  P.jfloat = P.jfloat - co*sample ; P.j = (int)P.jfloat ;
491  pt.set_ij(P.ifloat,P.jfloat);
492  if (vpImagePoint::distance(end[0],pt) < threshold) break;
493  if(!outOfImage(P.i, P.j, 5, rows, cols))
494  {
495  P.track(I,me,false);
496 
498  {
499  list.push_front(P) ;
500  beginPtAdded = true;
501  pt_max = pt;
502  if (vpDEBUG_ENABLE(3)) {
504  }
505  }
506  else {
507  if (vpDEBUG_ENABLE(3)) {
509  }
510  }
511  }
512  }
513 
514  if (!beginPtAdded) beginPtFound++;
515 
516  P.init(end[0].get_i(), end[0].get_j(), (list.back()).alpha, 0, (list.back()).mask_sign);
518 
519  bool endPtAdded = false;
520  angle = atan2(end[1].get_i(),end[1].get_j());
521  co = vpMath::abs(cos(angle));
522  co = co * vpMath::sign(end[1].get_j());
523  si = vpMath::abs(sin(angle));
524  si = si * vpMath::sign(end[1].get_i());
525  for (int i=0 ; i < 3 ; i++)
526  {
527  P.ifloat = P.ifloat + si*sample ; P.i = (int)P.ifloat ;
528  P.jfloat = P.jfloat + co*sample ; P.j = (int)P.jfloat ;
529  pt.set_ij(P.ifloat,P.jfloat);
530  if (vpImagePoint::distance(begin[0],pt) < threshold) break;
531  if(!outOfImage(P.i, P.j, 5, rows, cols))
532  {
533  P.track(I,me,false);
534 
536  {
537  list.push_back(P) ;
538  endPtAdded = true;
539  if (vpDEBUG_ENABLE(3)) {
541  }
542  }
543  else {
544  if (vpDEBUG_ENABLE(3)) {
546  }
547  }
548  }
549  }
550  if (!endPtAdded) endPtFound++;
551  me->setRange(memory_range);
552  }
553  else
554  {
555  list.pop_front();
556  }
557  if(begin != NULL) delete[] begin;
558  if(end != NULL) delete[] end;
559 }
560 
561 
573 #ifdef VISP_HAVE_OPENCV
574 void
576 #else
577 void
579 #endif
580 {
581 #ifdef VISP_HAVE_OPENCV
582  vpMeSite pt = list.front();
583  vpImagePoint firstPoint(pt.ifloat,pt.jfloat);
584  pt = list.back();
585  vpImagePoint lastPoint(pt.ifloat,pt.jfloat);
586  if (beginPtFound >=3 && farFromImageEdge(I, firstPoint))
587  {
588  vpImagePoint *begin = NULL;
589  begin = nurbs.computeCurveDersPoint(0.0,1);
590  vpImage<unsigned char> Isub(32,32); //Sub image.
591  vpImagePoint topLeft(begin[0].get_i()-15,begin[0].get_j()-15);
592  vpRect rect(topLeft,32,32);
593 
595 
596  vpImageTools::createSubImage(I,rect,Isub);
597 
598  vpImagePoint lastPtInSubIm(begin[0]);
599  double u = 0.0;
600  double step =0.0001;
601  //Find the point of the nurbs closest from the edge of the subImage and in the subImage.
602  while (inRectangle(lastPtInSubIm,rect) && u < 1)
603  {
604  u += step;
605  lastPtInSubIm = nurbs.computeCurvePoint(u);
606  }
607 
608  u -= step;
609  if( u > 0)
610  lastPtInSubIm = nurbs.computeCurvePoint(u);
611 
612  IplImage* Ip = NULL;
613  vpImageConvert::convert(Isub, Ip);
614 
615 
616  IplImage* dst = cvCreateImage( cvSize((int)Isub.getWidth(), (int)Isub.getHeight()), 8, 1 );
617  cvCanny( Ip, dst, cannyTh1, cannyTh2, 3 );
618 
619  vpImageConvert::convert(dst, Isub);
620 
621  vpImagePoint firstBorder(-1,-1);
622 
623  firstBorder = findFirstBorder(Isub, lastPtInSubIm-topLeft);
624 
625  std::list<vpImagePoint> ip_edges_list;
626  if (firstBorder != vpImagePoint(-1, -1))
627  {
628  unsigned int dir;
629  double fi = firstBorder.get_i();
630  double fj = firstBorder.get_j();
631  double w = Isub.getWidth()-1;
632  double h = Isub.getHeight()-1;
633  //if (firstBorder.get_i() == 0) dir = 4;
634  if (std::fabs(fi) <= std::numeric_limits<double>::epsilon()) dir = 4;
635  //else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
636  else if (std::fabs(fi-h) <= std::fabs(vpMath::maximum(fi,h))*std::numeric_limits<double>::epsilon()) dir = 0;
637  //else if (firstBorder.get_j() == 0) dir = 2;
638  else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon()) dir = 2;
639  //else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
640  else if (std::fabs(fj-w) <= std::fabs(vpMath::maximum(fj,w))*std::numeric_limits<double>::epsilon()) dir = 6;
641  computeFreemanChainElement(Isub, firstBorder , dir);
642  unsigned int firstDir = dir;
643  ip_edges_list.push_back( firstBorder );
644  vpImagePoint border(firstBorder);
645  vpImagePoint dBorder;
646  do
647  {
648  computeFreemanParameters(dir, dBorder);
649  border = border + dBorder;
650  vpDisplay::displayPoint(I, border+topLeft, vpColor::orange) ;
651 
652  ip_edges_list.push_back( border );
653 
654  computeFreemanChainElement(Isub, border , dir);
655  } while( (border != firstBorder || dir != firstDir) && isInImage(Isub,border) );
656  }
657 
658  if (findCenterPoint(&ip_edges_list))
659  {
660  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); /*++it*/){
661  vpMeSite s = *it;
662  vpImagePoint iP(s.ifloat,s.jfloat);
663  if (inRectangle(iP,rect))
664  it = list.erase(it) ;
665  else
666  break;
667  }
668 
669  std::list<vpMeSite>::iterator itList=list.begin();
670  double convlt;
671  double delta = 0;
672  int nbr = 0;
673  std::list<vpMeSite> addedPt;
674  for(std::list<vpImagePoint>::const_iterator itEdges=ip_edges_list.begin(); itEdges!=ip_edges_list.end(); ++itEdges){
675  vpMeSite s = *itList;
676  vpImagePoint iPtemp = *itEdges + topLeft;
677  vpMeSite pix;
678  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta);
679  dist = vpMeSite::sqrDistance(s,pix);
680  if (dist >= vpMath::sqr(me->getSampleStep())/*25*/)
681  {
682  bool exist = false;
683  for(std::list<vpMeSite>::const_iterator itAdd=addedPt.begin(); itAdd!=addedPt.end(); ++itAdd){
684  dist = vpMeSite::sqrDistance(pix, *itAdd);
685  if (dist < vpMath::sqr(me->getSampleStep())/*25*/)
686  exist = true;
687  }
688  if (!exist)
689  {
690  findAngle(I, iPtemp, me, delta, convlt);
691  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
692  pix.setDisplay(selectDisplay);
693  --itList;
694  list.insert(itList, pix);
695  ++itList;
696  addedPt.push_front(pix);
697  nbr++;
698  }
699  }
700  }
701 
702  unsigned int memory_range = me->getRange();
703  me->setRange(3);
704  std::list<vpMeSite>::iterator itList2=list.begin();
705  for (int j = 0; j < nbr; j++)
706  {
707  vpMeSite s = *itList2;
708  s.track(I,me,false);
709  *itList2 = s;
710  ++itList2;
711  }
712  me->setRange(memory_range);
713  }
714 
715  if (begin != NULL) delete[] begin;
716  beginPtFound = 0;
717  }
718 
719  if(endPtFound >= 3 && farFromImageEdge(I, lastPoint))
720  {
721  vpImagePoint *end = NULL;
722  end = nurbs.computeCurveDersPoint(1.0,1);
723 
724  vpImage<unsigned char> Isub(32,32); //Sub image.
725  vpImagePoint topLeft(end[0].get_i()-15,end[0].get_j()-15);
726  vpRect rect(topLeft,32,32);
727 
729 
730  vpImageTools::createSubImage(I,rect,Isub);
731 
732  vpImagePoint lastPtInSubIm(end[0]);
733  double u = 1.0;
734  double step =0.0001;
735  //Find the point of the nurbs closest from the edge of the subImage and in the subImage.
736  while (inRectangle(lastPtInSubIm,rect) && u > 0)
737  {
738  u -= step;
739  lastPtInSubIm = nurbs.computeCurvePoint(u);
740  }
741 
742  u += step;
743  if( u < 1.0)
744  lastPtInSubIm = nurbs.computeCurvePoint(u);
745 
746  IplImage* Ip = NULL;
747  vpImageConvert::convert(Isub, Ip);
748 
749 
750  IplImage* dst = cvCreateImage( cvSize((int)Isub.getWidth(), (int)Isub.getHeight()), 8, 1 );
751  cvCanny( Ip, dst, cannyTh1, cannyTh2, 3 );
752 
753  vpImageConvert::convert(dst, Isub);
754 
755  vpImagePoint firstBorder(-1,-1);
756 
757  firstBorder = findFirstBorder(Isub, lastPtInSubIm-topLeft);
758 
759  std::list<vpImagePoint> ip_edges_list;
760  if (firstBorder != vpImagePoint(-1, -1))
761  {
762  unsigned int dir;
763  double fi = firstBorder.get_i();
764  double fj = firstBorder.get_j();
765  double w = Isub.getWidth()-1;
766  double h = Isub.getHeight()-1;
767  //if (firstBorder.get_i() == 0) dir = 4;
768  if (std::fabs(fi) <= std::numeric_limits<double>::epsilon()) dir = 4;
769  //else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
770  else if (std::fabs(fi-h) <= std::fabs(vpMath::maximum(fi,h))*std::numeric_limits<double>::epsilon()) dir = 0;
771  //else if (firstBorder.get_j() == 0) dir = 2;
772  else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon()) dir = 2;
773  //else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
774  else if (std::fabs(fj-w) <= std::fabs(vpMath::maximum(fj,w))*std::numeric_limits<double>::epsilon()) dir = 6;
775 
776 
777  computeFreemanChainElement(Isub, firstBorder , dir);
778  unsigned int firstDir = dir;
779  ip_edges_list.push_back( firstBorder );
780  vpImagePoint border(firstBorder);
781  vpImagePoint dBorder;
782  do
783  {
784  computeFreemanParameters(dir, dBorder);
785  border = border + dBorder;
786  vpDisplay::displayPoint(I, border+topLeft, vpColor::orange) ;
787 
788  ip_edges_list.push_back( border );
789 
790  computeFreemanChainElement(Isub, border , dir);
791  } while( (border != firstBorder || dir != firstDir) && isInImage(Isub,border) );
792  }
793 
794  if (findCenterPoint(&ip_edges_list))
795  {
796 // list.end();
797  vpMeSite s;
798  while(true)//{//!list.outside())
799  {
800  s = list.back();//list.value() ;
801  vpImagePoint iP(s.ifloat,s.jfloat);
802  if (inRectangle(iP,rect))
803  {
804  list.erase(list.end()) ;
805 // list.end();
806  }
807  else
808  break;
809  }
810 
811  std::list<vpMeSite>::iterator itList = list.end();
812  double convlt;
813  double delta;
814  int nbr = 0;
815  std::list<vpMeSite> addedPt;
816  for(std::list<vpImagePoint>::const_iterator itEdges=ip_edges_list.begin(); itEdges!=ip_edges_list.end(); ++itEdges){
817  s = *itList;
818  vpImagePoint iPtemp = *itEdges + topLeft;
819  vpMeSite pix;
820  pix.init(iPtemp.get_i(), iPtemp.get_j(), 0);
821  dist = vpMeSite::sqrDistance(s,pix);
822  if (dist >= vpMath::sqr(me->getSampleStep()))
823  {
824  bool exist = false;
825  for(std::list<vpMeSite>::const_iterator itAdd=addedPt.begin(); itAdd!=addedPt.end(); ++itAdd){
826  dist = vpMeSite::sqrDistance(pix, *itAdd);
827  if (dist < vpMath::sqr(me->getSampleStep()))
828  exist = true;
829  }
830  if (!exist)
831  {
832  findAngle(I, iPtemp, me, delta, convlt);
833  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
834  pix.setDisplay(selectDisplay);
835  list.push_back(pix);
836  addedPt.push_back(pix);
837  nbr++;
838  }
839  }
840  }
841 
842  unsigned int memory_range = me->getRange();
843  me->setRange(3);
844  std::list<vpMeSite>::iterator itList2 = list.end();
845  for (int j = 0; j < nbr; j++)
846  {
847  vpMeSite s = *itList2;
848  s.track(I,me,false);
849  *itList2 = s;
850  --itList2;
851  }
852  me->setRange(memory_range);
853  }
854 
855  if (end != NULL) delete[] end;
856  endPtFound = 0;
857  }
858 #else
859  vpTRACE("To use the canny detection, OpenCV has to be installed.");
860 #endif
861 }
862 
863 
874 void
876 {
877  unsigned int n = numberOfSignal();
878  double nbPt = floor(dist / me->getSampleStep());
879 
880  if ((double)n < 0.7*nbPt)
881  {
882  sample(I);
884  }
885 }
886 
887 
894 void
896 {
897  int rows = (int)I.getHeight() ;
898  int cols = (int)I.getWidth() ;
899  vpImagePoint* iP = NULL;
900 
901  int n = (int)numberOfSignal();
902 
903 // list.front();
904  std::list<vpMeSite>::iterator it=list.begin();
905  std::list<vpMeSite>::iterator itNext=list.begin();
906  ++itNext;
907 
908  unsigned int range_tmp = me->getRange();
909  me->setRange(2);
910 
911  while(itNext!=list.end() && n <= me->getPointsToTrack())
912  {
913  vpMeSite s = *it;//current reference pixel
914  vpMeSite s_next = *itNext;//current reference pixel
915 
916  double d = vpMeSite::sqrDistance(s,s_next);
917  if(d > 4 * vpMath::sqr(me->getSampleStep()) && d < 1600)
918  {
919  vpImagePoint iP0(s.ifloat,s.jfloat);
920  vpImagePoint iPend(s_next.ifloat,s_next.jfloat);
921  vpImagePoint iP_1(s.ifloat,s.jfloat);
922 
923  double u = 0.0;
924  double ubegin = 0.0;
925  double uend = 0.0;
926  double dmin1_1 = 1e6;
927  double dmin2_1 = 1e6;
928  while(u < 1)
929  {
930  u+=0.01;
931  double dmin1 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u),iP0);
932  double dmin2 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u),iPend);
933 
934  if (dmin1 < dmin1_1)
935  {
936  dmin1_1 = dmin1;
937  ubegin = u;
938  }
939 
940  if (dmin2 < dmin2_1)
941  {
942  dmin2_1 = dmin2;
943  uend = u;
944  }
945  }
946  u = ubegin;
947 
948  //if(( u != 1.0 || uend != 1.0)
949  if( (std::fabs(u-1.0) > std::fabs(vpMath::maximum(u, 1.0))*std::numeric_limits<double>::epsilon())
950  || (std::fabs(uend-1.0) > std::fabs(vpMath::maximum(u, 1.0))*std::numeric_limits<double>::epsilon()))
951  {
952  iP = nurbs.computeCurveDersPoint(u, 1);
953 
954  while (vpImagePoint::sqrDistance(iP[0],iPend) > vpMath::sqr(me->getSampleStep()) && u < uend)
955  {
956  u+=0.01;
957  if (iP!=NULL) {
958  delete[] iP;
959  iP = NULL;
960  }
961  iP = nurbs.computeCurveDersPoint(u, 1);
962  if ( vpImagePoint::sqrDistance(iP[0],iP_1) > vpMath::sqr(me->getSampleStep()) && !outOfImage(iP[0], 0, rows, cols))
963  {
964  double delta = computeDelta(iP[1].get_i(),iP[1].get_j());
965  vpMeSite pix ; //= list.value();
966  pix.init(iP[0].get_i(), iP[0].get_j(), delta) ;
968  pix.track(I,me,false);
969  if (pix.getState() == vpMeSite::NO_SUPPRESSION)
970  {
971  list.insert(it, pix);
972  iP_1 = iP[0];
973  }
974  }
975  }
976  if (iP!=NULL) {
977  delete[] iP;
978  iP = NULL;
979  }
980  }
981  }
982  ++it;
983  ++itNext;
984  }
985  me->setRange(range_tmp);
986 }
987 
988 
994 void
996 {
997 #if 0
998  // Loop through list of sites to track
999  list.front();
1000  while(!list.nextOutside())
1001  {
1002  vpMeSite s = list.value() ;//current reference pixel
1003  vpMeSite s_next = list.nextValue() ;//current reference pixel
1004 
1005  if(vpMeSite::sqrDistance(s,s_next) < vpMath::sqr(me->getSampleStep()))
1006  {
1007  s_next.setState(vpMeSite::TOO_NEAR);
1008 
1009  list.next();
1010  list.modify(s_next);
1011  if (!list.nextOutside()) list.next();
1012  }
1013  else
1014  list.next() ;
1015  }
1016 #endif
1017  std::list<vpMeSite>::const_iterator it=list.begin();
1018  std::list<vpMeSite>::iterator itNext=list.begin();
1019  ++itNext;
1020  for(;itNext!=list.end();){
1021  vpMeSite s = *it;//current reference pixel
1022  vpMeSite s_next = *itNext;//current reference pixel
1023 
1024  if(vpMeSite::sqrDistance(s,s_next) < vpMath::sqr(me->getSampleStep())){
1025  s_next.setState(vpMeSite::TOO_NEAR);
1026 
1027  *itNext = s_next;
1028  ++it;
1029  ++itNext;
1030  if(itNext!=list.end()){
1031  ++it;
1032  ++itNext;
1033  }
1034  }
1035  else{
1036  ++it;
1037  ++itNext;
1038  }
1039  }
1040 }
1041 
1042 
1048 void
1050 {
1051  //Tracking des vpMeSites
1052  vpMeTracker::track(I);
1053 
1054  //Suppress points which are too close to each other
1056 
1057  //Suppressions des points ejectes par le tracking
1058  suppressPoints();
1059 
1060  //Recalcule les param�tres
1061 // nurbs.globalCurveInterp(list);
1062  nurbs.globalCurveApprox(list,nbControlPoints);
1063 
1064  //On resample localement
1065  localReSample(I);
1066 
1067  seekExtremities(I);
1068  if(enableCannyDetection)
1070 
1071 // nurbs.globalCurveInterp(list);
1072  nurbs.globalCurveApprox(list,nbControlPoints);
1073 
1074  double u = 0.0;
1075  vpImagePoint pt;
1076  vpImagePoint pt_1;
1077  dist = 0;
1078  while (u<=1.0)
1079  {
1080  pt = nurbs.computeCurvePoint(u);
1081  //if(u!=0)
1082  if(std::fabs(u) > std::numeric_limits<double>::epsilon())
1083  dist = dist + vpImagePoint::distance(pt,pt_1);
1084  pt_1 = pt;
1085  u=u+0.01;
1086  }
1087 
1088  updateDelta();
1089 
1090  reSample(I);
1091 }
1092 
1093 
1104 void
1106 {
1107  vpMeNurbs::display(I,nurbs,col);
1108 }
1109 
1110 
1127 bool
1128 vpMeNurbs::computeFreemanChainElement(const vpImage<unsigned char> &I,
1129  vpImagePoint &iP,
1130  unsigned int &element)
1131 {
1132  vpImagePoint diP;
1133  vpImagePoint iPtemp;
1134  if (hasGoodLevel( I, iP )) {
1135  // get the point on the right of the point passed in
1136  computeFreemanParameters((element + 2) %8, diP);
1137  iPtemp = iP + diP;
1138  if (hasGoodLevel( I, iPtemp )) {
1139  element = (element + 2) % 8; // turn right
1140  }
1141  else {
1142  computeFreemanParameters((element + 1) %8, diP);
1143  iPtemp = iP + diP;
1144 
1145  if ( hasGoodLevel( I, iPtemp )) {
1146  element = (element + 1) % 8; // turn diag right
1147  }
1148  else {
1149  computeFreemanParameters(element, diP);
1150  iPtemp = iP + diP;
1151 
1152  if ( hasGoodLevel( I, iPtemp )) {
1153  element = element; // keep same dir
1154  }
1155  else {
1156  computeFreemanParameters((element + 7) %8, diP);
1157  iPtemp = iP + diP;
1158 
1159  if ( hasGoodLevel( I, iPtemp )) {
1160  element = (element + 7) %8; // turn diag left
1161  }
1162  else {
1163  computeFreemanParameters((element + 6) %8, diP);
1164  iPtemp = iP + diP;
1165 
1166  if ( hasGoodLevel( I, iPtemp )) {
1167  element = (element + 6) %8 ; // turn left
1168  }
1169  else {
1170  computeFreemanParameters((element + 5) %8, diP);
1171  iPtemp = iP + diP;
1172 
1173  if ( hasGoodLevel( I, iPtemp )) {
1174  element = (element + 5) %8 ; // turn diag down
1175  }
1176  else {
1177  computeFreemanParameters((element + 4) %8, diP);
1178  iPtemp = iP + diP;
1179 
1180  if ( hasGoodLevel( I, iPtemp )) {
1181  element = (element + 4) %8 ; // turn down
1182  }
1183  else {
1184  computeFreemanParameters((element + 3) %8, diP);
1185  iPtemp = iP + diP;
1186 
1187  if ( hasGoodLevel( I, iPtemp )) {
1188  element = (element + 3) %8 ; // turn diag right down
1189  }
1190  else {
1191  // No neighbor with a good level
1192  //
1193  return false;
1194  }
1195  }
1196  }
1197  }
1198  }
1199  }
1200  }
1201  }
1202  }
1203  else {
1204  return false;
1205  }
1206  return true;
1207 }
1208 
1209 
1222 bool vpMeNurbs::hasGoodLevel(const vpImage<unsigned char>& I,
1223  const vpImagePoint& iP) const
1224 {
1225  if( !isInImage( I, iP ) )
1226  return false;
1227 
1228  if( I((unsigned int)vpMath::round(iP.get_i()), (unsigned int)vpMath::round(iP.get_j())) > 0)
1229  {
1230  return true;
1231  }
1232  else
1233  {
1234  return false;
1235  }
1236 }
1237 
1238 
1249 bool vpMeNurbs::isInImage(const vpImage<unsigned char>& I, const vpImagePoint &iP) const
1250 {
1251  return (iP.get_i() >= 0
1252  && iP.get_j() >= 0
1253  && iP.get_i() < I.getHeight()
1254  && iP.get_j() < I.getWidth());
1255 }
1256 
1257 
1273 void
1274 vpMeNurbs::computeFreemanParameters( unsigned int element, vpImagePoint &diP)
1275 {
1276  /*
1277  5 6 7
1278  \ | /
1279  \|/
1280  4 ------- 0
1281  /|\
1282  / | \
1283  3 2 1
1284  */
1285  switch(element) {
1286  case 0: // go right
1287  diP.set_ij(0,1);
1288  break;
1289 
1290  case 1: // go right top
1291  diP.set_ij(1,1);
1292  break;
1293 
1294  case 2: // go top
1295  diP.set_ij(1,0);
1296  break;
1297 
1298  case 3:
1299  diP.set_ij(1,-1);
1300  break;
1301 
1302  case 4:
1303  diP.set_ij(0,-1);
1304  break;
1305 
1306  case 5:
1307  diP.set_ij(-1,-1);
1308  break;
1309 
1310  case 6:
1311  diP.set_ij(-1,0);
1312  break;
1313 
1314  case 7:
1315  diP.set_ij(-1,1);
1316  break;
1317  }
1318 }
1319 
1320 
1329 bool
1330 vpMeNurbs::farFromImageEdge(const vpImage<unsigned char>& I, const vpImagePoint& iP)
1331 {
1332  unsigned int height = I.getHeight();
1333  unsigned int width = I.getWidth();
1334  return (iP.get_i() < height - 20
1335  && iP.get_j() < width - 20
1336  && iP.get_i() > 20
1337  && iP.get_j() > 20);
1338 }
1339 
1351 {
1352  double u = 0.0;
1353  vpImagePoint pt;
1354  while (u <= 1)
1355  {
1356  pt = n.computeCurvePoint(u);
1357  vpDisplay::displayCross(I,pt,4,color);
1358  u+=0.01;
1359  }
1360 }
1361 
unsigned int getRange() const
Definition: vpMe.h:236
unsigned int getMaskSize() const
Definition: vpMe.h:164
void suppressPoints()
Definition: vpMeNurbs.cpp:385
virtual ~vpMeNurbs()
Definition: vpMeNurbs.cpp:254
void init()
Definition: vpMeSite.cpp:73
double get_i() const
Definition: vpImagePoint.h:181
bool outside(void) const
Test if the current element is outside the list (on the virtual element)
Definition: vpList.h:431
unsigned int getWidth() const
Definition: vpImage.h:154
double jfloat
Definition: vpMeSite.h:100
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:99
void track(const vpImage< unsigned char > &Im)
Definition: vpMeNurbs.cpp:1049
void seekExtremitiesCanny(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:575
#define vpTRACE
Definition: vpDebug.h:401
Provide simple list management.
Definition: vpList.h:112
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'...
Definition: vpMeSite.h:76
Class to define colors available for display functionnalities.
Definition: vpColor.h:123
int outOfImage(int i, int j, int half, int rows, int cols)
double alpha
Definition: vpMeSite.h:104
int i
Definition: vpMeSite.h:98
void initTracking(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:266
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
Contains predetermined masks for sites and holds moving edges tracking parameters.
Definition: vpMe.h:70
Class that tracks in an image a edge defined by a Nurbs.
Definition: vpMeNurbs.h:129
static const vpColor green
Definition: vpColor.h:168
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1964
static int round(const double x)
Definition: vpMath.h:228
double get_j() const
Definition: vpImagePoint.h:192
void next(void)
position the current element on the next one
Definition: vpList.h:275
static Type abs(const Type &x)
Definition: vpMath.h:158
#define vpDEBUG_ENABLE(niv)
Definition: vpDebug.h:502
vpMeSiteState getState() const
Definition: vpMeSite.h:202
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:137
static const vpColor orange
Definition: vpColor.h:175
double ifloat
Definition: vpMeSite.h:100
int getStrip() const
Definition: vpMe.h:298
std::list< vpMeSite > list
Definition: vpMeTracker.h:80
unsigned int getAngleStep() const
Definition: vpMe.h:250
void supressNearPoints()
Definition: vpMeNurbs.cpp:995
void set_ij(const double i, const double j)
Definition: vpImagePoint.h:167
static double sqr(double x)
Definition: vpMath.h:106
void display(const vpImage< unsigned char > &I, vpColor col)
Definition: vpMeNurbs.cpp:1105
void front(void)
Position the current element on the first element of the list.
Definition: vpList.h:386
type & value(void)
return the value of the current element
Definition: vpList.h:303
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
void track(const vpImage< unsigned char > &I)
Track sampled pixels.
Contains abstract elements for a Distance to Feature type feature.
Definition: vpMeTracker.h:71
void reSample(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:875
virtual void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)=0
static double sqrDistance(const vpMeSite S1, const vpMeSite S2)
Definition: vpMeSite.h:244
void sample(const vpImage< unsigned char > &image)
Definition: vpMeNurbs.cpp:343
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:189
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:865
static double rad(double deg)
Definition: vpMath.h:100
void localReSample(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:895
int getPointsToTrack() const
Definition: vpMe.h:222
vpMatrix * getMask() const
Definition: vpMe.h:116
int j
Definition: vpMeSite.h:98
static void createSubImage(const vpImage< Type > &I, unsigned int i_sub, unsigned int j_sub, unsigned int nrow_sub, unsigned int ncol_sub, vpImage< Type > &S)
Definition: vpImageTools.h:129
static double sqrDistance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:273
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:370
void seekExtremities(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:451
void initTracking(const vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:145
Defines a rectangle in the plane.
Definition: vpRect.h:82
virtual bool getClick(bool blocking=true)=0
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
vpNurbs nurbs
The Nurbs which represents the tracked edge.
Definition: vpMeNurbs.h:137
void setRange(const unsigned int &r)
Definition: vpMe.h:229
double getSampleStep() const
Definition: vpMe.h:284
static int sign(double x)
Definition: vpMath.h:248
vpMeSite::vpMeSiteDisplayType selectDisplay
Definition: vpMeTracker.h:87
Class that provides tools to compute and manipulate a Non Uniform Rational B-Spline curve...
Definition: vpNurbs.h:89
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:261
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:269
static const vpColor blue
Definition: vpColor.h:171
void updateDelta()
Definition: vpMeNurbs.cpp:405