ViSP  2.9.0
vpMeNurbs.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMeNurbs.cpp 4649 2014-02-07 14:57:11Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 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 
48 #include <visp/vpMeTracker.h>
49 #include <visp/vpMe.h>
50 #include <visp/vpMeSite.h>
51 #include <visp/vpMeNurbs.h>
52 #include <visp/vpRobust.h>
53 #include <visp/vpTrackingException.h>
54 #include <visp/vpImagePoint.h>
55 #include <visp/vpMath.h>
56 #include <visp/vpRect.h>
57 #include <visp/vpImageTools.h>
58 #include <visp/vpImageConvert.h>
59 #include <stdlib.h>
60 #include <cmath> // std::fabs
61 #include <limits> // numeric_limits
62 #ifdef VISP_HAVE_OPENCV
63 # if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
64 //# include <opencv2/imgproc/imgproc.hpp>
65 # include <opencv2/imgproc/imgproc_c.h>
66 # else
67 # include <cv.h>
68 # endif
69 #endif
70 
71 double computeDelta(double deltai, double deltaj);
72 void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP,
73  vpMe* me, double &angle, double &convlt);
74 vpImagePoint findFirstBorder(const vpImage<unsigned char>& Isub, const vpImagePoint &iP);
75 bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list);
76 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
77 vp_deprecated bool findCenterPoint(vpList<vpImagePoint> *ip_edges_list);
78 #endif
79 
80 //Compute the angle delta = arctan(deltai/deltaj)
81 //and normalize it between 0 and pi
82 double
83 computeDelta(double deltai, double deltaj)
84 {
85  double delta;
86  delta = atan2(deltai,deltaj) ;
87  delta -= M_PI/2.0 ;
88  while (delta > M_PI) { delta -= M_PI ; }
89  while (delta < 0) { delta += M_PI ; }
90  return(delta);
91 }
92 
93 //Check if the image point is in the image and not to close to
94 //its edge to enable the computation of a convolution whith a mask.
95 static
96 bool outOfImage( vpImagePoint iP , int half , int rows , int cols)
97 {
98  return((iP.get_i() < half + 1) || ( iP.get_i() > (rows - half - 3) )
99  ||(iP.get_j() < half + 1) || (iP.get_j() > (cols - half - 3) )) ;
100 }
101 
102 //if iP is a edge point, it computes the angle corresponding to the
103 //highest convolution result. the angle is between 0 an 179.
104 //The result gives the angle in RADIAN + pi/2 (to deal with the moving edeg alpha angle)
105 //and the corresponding convolution result.
106 void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP,
107  vpMe* me, double &angle, double &convlt)
108 {
109  int Iheight = (int)I.getHeight();
110  int Iwidth = (int)I.getWidth();
111  angle = 0.0;
112  convlt = 0.0;
113  for (int i = 0; i < 180; i++)
114  {
115  double conv = 0.0;
116  unsigned int half;
117  int index_mask;
118  half = (me->getMaskSize() - 1) >> 1 ;
119 
120  if(outOfImage( iP , (int)half + me->getStrip() , Iheight, Iwidth))
121  {
122  conv = 0.0 ;
123  }
124  else
125  {
126  if (me->getAngleStep() !=0)
127  index_mask = (int)(i/(double)me->getAngleStep());
128  else
129  throw (vpException(vpException::divideByZeroError,"angle step = 0"));
130 
131  unsigned int ihalf = (unsigned int)(iP.get_i()-half) ;
132  unsigned int jhalf = (unsigned int)(iP.get_j()-half) ;
133  unsigned int ihalfa ;
134  unsigned int a ;
135  unsigned int b ;
136  for( a = 0 ; a < me->getMaskSize() ; a++ )
137  {
138  ihalfa = ihalf+a ;
139  for( b = 0 ; b < me->getMaskSize() ; b++ )
140  {
141  conv += me->getMask()[index_mask][a][b] *
142  I(ihalfa,jhalf+b) ;
143  }
144  }
145  }
146  conv = fabs(conv);
147  if (conv > convlt)
148  {
149  convlt = conv;
150  angle = vpMath::rad(i);
151  angle += M_PI/2;
152  while (angle > M_PI) { angle -= M_PI ; }
153  while (angle < 0) { angle += M_PI ; }
154  }
155  }
156 }
157 
158 
159 //Find the point belonging to the edge of the sub image which respects the following hypotheses:
160 //- the value of the pixel is upper than zero.
161 //- the distantce between the point and iP is less than 4 pixels.
162 //The function returns the nearest point of iP which respect the hypotheses
163 //If no point is found the returned point is (-1,-1)
164 vpImagePoint findFirstBorder(const vpImage<unsigned char>& Isub, const vpImagePoint &iP)
165 {
166  double dist = 1e6;
167  double dist_1 = 1e6;
168  vpImagePoint index(-1,-1);
169  for (unsigned int i = 0; i <= Isub.getHeight(); i++)
170  {
171  for (unsigned int j = 0; j <= Isub.getWidth(); j++)
172  {
173  if(i == 0 || i == Isub.getHeight()-1 || j == 0 || j == Isub.getWidth()-1)
174  {
175  if (Isub(i,j) > 0)
176  {
178  if (dist <= 16 && dist < dist_1)
179  {
180  dist_1 = dist;
181  index.set_ij(i,j);
182  }
183  }
184  }
185  }
186  }
187  return index;
188 }
189 
190 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
191 //Check if the list of vpImagePoint contains a distant point of less tha 4 pixels
192 //from the center of the sub image (ie the point (15,15).
193 vp_deprecated bool findCenterPoint(vpList<vpImagePoint> *ip_edges_list)
194 {
195  ip_edges_list->front();
196  double dist;
197  while (!ip_edges_list->outside())
198  {
199  vpImagePoint iP = ip_edges_list->value();
200  dist = vpImagePoint::sqrDistance(iP,vpImagePoint(15,15));
201  if (dist <= 16)
202  {
203  return true;
204  }
205  ip_edges_list->next();
206  }
207  return false;
208 }
209 #endif
210 
211 //Check if the list of vpImagePoint contains a distant point of less tha 4 pixels
212 //from the center of the sub image (ie the point (15,15).
213 bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list)
214 {
215  double dist;
216  for(std::list<vpImagePoint>::const_iterator it=ip_edges_list->begin(); it!=ip_edges_list->end(); ++it){
217  vpImagePoint iP = *it;
218  dist = vpImagePoint::sqrDistance(iP, vpImagePoint(15,15));
219  if (dist <= 16)
220  {
221  return true;
222  }
223  }
224  return false;
225 }
226 
227 /***************************************/
228 
233  : nurbs(), dist(0.), nbControlPoints(20), beginPtFound(0), endPtFound(0), enableCannyDetection(false),
234  cannyTh1(100.), cannyTh2(200.)
235 {
236 }
237 
242  : vpMeTracker(menurbs),
243  nurbs(), dist(0.), nbControlPoints(20), beginPtFound(0), endPtFound(0), enableCannyDetection(false),
244  cannyTh1(100.), cannyTh2(200.)
245 {
246  nurbs = menurbs.nurbs;
247  dist = menurbs.dist;
248  nbControlPoints = menurbs.nbControlPoints;
249  beginPtFound = menurbs.beginPtFound;
250  endPtFound = menurbs.endPtFound;
251  enableCannyDetection = menurbs.enableCannyDetection;
252  cannyTh1 = menurbs.cannyTh1;
253  cannyTh2 = menurbs.cannyTh2;
254 }
255 
260 {
261 }
262 
263 
270 void
272 {
273  std::list<vpImagePoint> ptList;
274  vpImagePoint pt;
276 
277  while (vpDisplay::getClick(I, pt, b))
278  {
279  if (b == vpMouseButton::button1)
280  {
281  //std::cout<<pt<<std::endl;
282  ptList.push_back(pt);
284  vpDisplay::flush(I);
285  }
286  if (b == vpMouseButton::button3) break;
287  }
288  if (ptList.size() > 3)
289  initTracking(I, ptList);
290  else
291  throw (vpException(vpException::notInitialized,"Not enough points to initialize the Nurbs"));
292 }
293 
294 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
295 
305 vp_deprecated void
307  vpList<vpImagePoint> &ptList)
308 {
309  std::list<vpImagePoint> listStd;
310  for(ptList.front(); !ptList.outside(); ptList.next()){
311  listStd.push_back(ptList.value());
312  }
313  nurbs.globalCurveInterp(listStd);
314 
315  sample(I);
316 
318  track(I);
319 }
320 #endif
321 
329 void
331  const std::list<vpImagePoint> &ptList)
332 {
333  nurbs.globalCurveInterp(ptList);
334 
335  sample(I);
336 
338  track(I);
339 }
340 
347 void
349 {
350  int rows = (int)I.getHeight() ;
351  int cols = (int)I.getWidth() ;
352  double step = 1.0 / (double)me->getPointsToTrack();
353 
354  // Delete old list
355  list.clear();
356 
357  vpImagePoint ip;
358  double u = 0.0;
359  vpImagePoint *pt = NULL;
360  vpImagePoint pt_1(-rows,-cols);
361  while (u <= 1.0)
362  {
363  if (pt!=NULL) delete[] pt;
364  pt = nurbs.computeCurveDersPoint(u, 1);
365  double delta = computeDelta(pt[1].get_i(),pt[1].get_j());
366 
367  // If point is in the image, add to the sample list
368  if(!outOfImage(pt[0], 0, rows, cols) && vpImagePoint::sqrDistance(pt[0],pt_1) >= vpMath::sqr(me->getSampleStep()))
369  {
370  vpMeSite pix ; //= list.value();
371  pix.init(pt[0].get_i(), pt[0].get_j(), delta) ;
373 
374  list.push_back(pix);
375  pt_1 = pt[0];
376  }
377  u = u+step;
378  }
379  if (pt!=NULL) delete[] pt;
380 }
381 
382 
389 void
391 {
392  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ){
393  vpMeSite s = *it;//current reference pixel
394 
396  {
397  it = list.erase(it);
398  }
399  else
400  ++it;
401  }
402 }
403 
404 
409 void
411 {
412  double u = 0.0;
413  double d = 1e6;
414  double d_1 = 1e6;
415  std::list<vpMeSite>::iterator it=list.begin();
416 
417  vpImagePoint Cu;
418  vpImagePoint* der = NULL;
419  double step = 0.01;
420  while (u < 1 && it!=list.end())
421  {
422  vpMeSite s = *it;
423  vpImagePoint pt(s.i,s.j);
424  while (d <= d_1 && u<1)
425  {
426  Cu = nurbs.computeCurvePoint(u);
427  d_1=d;
428  d = vpImagePoint::distance(pt,Cu);
429  u +=step;
430  }
431 
432  u-=step;
433  if (der != NULL) delete[] der;
434  der = nurbs.computeCurveDersPoint(u, 1);
435  //vpImagePoint toto(der[0].get_i(),der[0].get_j());
436  //vpDisplay::displayCross(I,toto,4,vpColor::red);
437 
438  s.alpha = computeDelta(der[1].get_i(),der[1].get_j());
439  *it = s;
440  ++it;
441  d = 1e6;
442  d_1 = 1.5e6;
443  }
444  if (der != NULL) delete[] der;
445 }
446 
447 
455 void
457 {
458  int rows = (int)I.getHeight() ;
459  int cols = (int)I.getWidth() ;
460 
461  vpImagePoint* begin = NULL;
462  vpImagePoint* end = NULL;
463 
464  begin = nurbs.computeCurveDersPoint(0.0,1);
465  end = nurbs.computeCurveDersPoint(1.0,1);
466 
467  //Check if the two extremities are not to close to eachother.
468  double d = vpImagePoint::distance(begin[0],end[0]);
469  double threshold = 3*me->getSampleStep();
470  double sample_step = me->getSampleStep();
471  vpImagePoint pt;
472  if ( d > threshold /*|| (list.firstValue()).mask_sign != (list.lastValue()).mask_sign*/)
473  {
474  vpMeSite P ;
475 
476  //Init vpMeSite
477  P.init(begin[0].get_i(), begin[0].get_j(), (list.front()).alpha, 0, (list.front()).mask_sign) ;
479 
480  //Set the range
481  unsigned int memory_range = me->getRange() ;
482  me->setRange(2);
483 
484  //Point at the beginning of the list
485  bool beginPtAdded = false;
486  vpImagePoint pt_max = begin[0];
487  double angle = atan2(begin[1].get_i(),begin[1].get_j());
488  double co = vpMath::abs(cos(angle));
489  co = co * vpMath::sign(begin[1].get_j());
490  double si = vpMath::abs(sin(angle));
491  si = si * vpMath::sign(begin[1].get_i());
492  for (int i=0 ; i < 3 ; i++)
493  {
494  P.ifloat = P.ifloat - si*sample_step ; P.i = (int)P.ifloat ;
495  P.jfloat = P.jfloat - co*sample_step ; P.j = (int)P.jfloat ;
496  pt.set_ij(P.ifloat,P.jfloat);
497  if (vpImagePoint::distance(end[0],pt) < threshold) break;
498  if(!outOfImage(P.i, P.j, 5, rows, cols))
499  {
500  P.track(I,me,false);
501 
503  {
504  list.push_front(P) ;
505  beginPtAdded = true;
506  pt_max = pt;
507  if (vpDEBUG_ENABLE(3)) {
509  }
510  }
511  else {
512  if (vpDEBUG_ENABLE(3)) {
514  }
515  }
516  }
517  }
518 
519  if (!beginPtAdded) beginPtFound++;
520 
521  P.init(end[0].get_i(), end[0].get_j(), (list.back()).alpha, 0, (list.back()).mask_sign);
523 
524  bool endPtAdded = false;
525  angle = atan2(end[1].get_i(),end[1].get_j());
526  co = vpMath::abs(cos(angle));
527  co = co * vpMath::sign(end[1].get_j());
528  si = vpMath::abs(sin(angle));
529  si = si * vpMath::sign(end[1].get_i());
530  for (int i=0 ; i < 3 ; i++)
531  {
532  P.ifloat = P.ifloat + si*sample_step ; P.i = (int)P.ifloat ;
533  P.jfloat = P.jfloat + co*sample_step ; P.j = (int)P.jfloat ;
534  pt.set_ij(P.ifloat,P.jfloat);
535  if (vpImagePoint::distance(begin[0],pt) < threshold) break;
536  if(!outOfImage(P.i, P.j, 5, rows, cols))
537  {
538  P.track(I,me,false);
539 
541  {
542  list.push_back(P) ;
543  endPtAdded = true;
544  if (vpDEBUG_ENABLE(3)) {
546  }
547  }
548  else {
549  if (vpDEBUG_ENABLE(3)) {
551  }
552  }
553  }
554  }
555  if (!endPtAdded) endPtFound++;
556  me->setRange(memory_range);
557  }
558  else
559  {
560  list.pop_front();
561  }
562  /*if(begin != NULL)*/ delete[] begin;
563  /*if(end != NULL) */ delete[] end;
564 }
565 
566 
578 #ifdef VISP_HAVE_OPENCV
579 void
581 #else
582 void
584 #endif
585 {
586 #ifdef VISP_HAVE_OPENCV
587  vpMeSite pt = list.front();
588  vpImagePoint firstPoint(pt.ifloat,pt.jfloat);
589  pt = list.back();
590  vpImagePoint lastPoint(pt.ifloat,pt.jfloat);
591  if (beginPtFound >=3 && farFromImageEdge(I, firstPoint))
592  {
593  vpImagePoint *begin = NULL;
594  begin = nurbs.computeCurveDersPoint(0.0,1);
595  vpImage<unsigned char> Isub(32,32); //Sub image.
596  vpImagePoint topLeft(begin[0].get_i()-15,begin[0].get_j()-15);
597  vpRect rect(topLeft,32,32);
598 
600 
601  vpImageTools::createSubImage(I,rect,Isub);
602 
603  vpImagePoint lastPtInSubIm(begin[0]);
604  double u = 0.0;
605  double step =0.0001;
606  //Find the point of the nurbs closest from the edge of the subImage and in the subImage.
607  while (inRectangle(lastPtInSubIm,rect) && u < 1)
608  {
609  u += step;
610  lastPtInSubIm = nurbs.computeCurvePoint(u);
611  }
612 
613  u -= step;
614  if( u > 0)
615  lastPtInSubIm = nurbs.computeCurvePoint(u);
616 
617  IplImage* Ip = NULL;
618  vpImageConvert::convert(Isub, Ip);
619 
620 
621  IplImage* dst = cvCreateImage( cvSize((int)Isub.getWidth(), (int)Isub.getHeight()), 8, 1 );
622  cvCanny( Ip, dst, cannyTh1, cannyTh2, 3 );
623 
624  vpImageConvert::convert(dst, Isub);
625 
626  vpImagePoint firstBorder(-1,-1);
627 
628  firstBorder = findFirstBorder(Isub, lastPtInSubIm-topLeft);
629 
630  std::list<vpImagePoint> ip_edges_list;
631  if (firstBorder != vpImagePoint(-1, -1))
632  {
633  unsigned int dir;
634  double fi = firstBorder.get_i();
635  double fj = firstBorder.get_j();
636  double w = Isub.getWidth()-1;
637  double h = Isub.getHeight()-1;
638  //if (firstBorder.get_i() == 0) dir = 4;
639  if (std::fabs(fi) <= std::numeric_limits<double>::epsilon()) dir = 4;
640  //else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
641  else if (std::fabs(fi-h) <= std::fabs(vpMath::maximum(fi,h))*std::numeric_limits<double>::epsilon()) dir = 0;
642  //else if (firstBorder.get_j() == 0) dir = 2;
643  else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon()) dir = 2;
644  //else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
645  else if (std::fabs(fj-w) <= std::fabs(vpMath::maximum(fj,w))*std::numeric_limits<double>::epsilon()) dir = 6;
646  computeFreemanChainElement(Isub, firstBorder , dir);
647  unsigned int firstDir = dir;
648  ip_edges_list.push_back( firstBorder );
649  vpImagePoint border(firstBorder);
650  vpImagePoint dBorder;
651  do
652  {
653  computeFreemanParameters(dir, dBorder);
654  border = border + dBorder;
655  vpDisplay::displayPoint(I, border+topLeft, vpColor::orange) ;
656 
657  ip_edges_list.push_back( border );
658 
659  computeFreemanChainElement(Isub, border , dir);
660  } while( (border != firstBorder || dir != firstDir) && isInImage(Isub,border) );
661  }
662 
663  if (findCenterPoint(&ip_edges_list))
664  {
665  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); /*++it*/){
666  vpMeSite s = *it;
667  vpImagePoint iP(s.ifloat,s.jfloat);
668  if (inRectangle(iP,rect))
669  it = list.erase(it) ;
670  else
671  break;
672  }
673 
674  std::list<vpMeSite>::iterator itList=list.begin();
675  double convlt;
676  double delta = 0;
677  int nbr = 0;
678  std::list<vpMeSite> addedPt;
679  for(std::list<vpImagePoint>::const_iterator itEdges=ip_edges_list.begin(); itEdges!=ip_edges_list.end(); ++itEdges){
680  vpMeSite s = *itList;
681  vpImagePoint iPtemp = *itEdges + topLeft;
682  vpMeSite pix;
683  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta);
684  dist = vpMeSite::sqrDistance(s,pix);
685  if (dist >= vpMath::sqr(me->getSampleStep())/*25*/)
686  {
687  bool exist = false;
688  for(std::list<vpMeSite>::const_iterator itAdd=addedPt.begin(); itAdd!=addedPt.end(); ++itAdd){
689  dist = vpMeSite::sqrDistance(pix, *itAdd);
690  if (dist < vpMath::sqr(me->getSampleStep())/*25*/)
691  exist = true;
692  }
693  if (!exist)
694  {
695  findAngle(I, iPtemp, me, delta, convlt);
696  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
697  pix.setDisplay(selectDisplay);
698  --itList;
699  list.insert(itList, pix);
700  ++itList;
701  addedPt.push_front(pix);
702  nbr++;
703  }
704  }
705  }
706 
707  unsigned int memory_range = me->getRange();
708  me->setRange(3);
709  std::list<vpMeSite>::iterator itList2=list.begin();
710  for (int j = 0; j < nbr; j++)
711  {
712  vpMeSite s = *itList2;
713  s.track(I,me,false);
714  *itList2 = s;
715  ++itList2;
716  }
717  me->setRange(memory_range);
718  }
719 
720  /* if (begin != NULL) */ delete[] begin;
721  beginPtFound = 0;
722  }
723 
724  if(endPtFound >= 3 && farFromImageEdge(I, lastPoint))
725  {
726  vpImagePoint *end = NULL;
727  end = nurbs.computeCurveDersPoint(1.0,1);
728 
729  vpImage<unsigned char> Isub(32,32); //Sub image.
730  vpImagePoint topLeft(end[0].get_i()-15,end[0].get_j()-15);
731  vpRect rect(topLeft,32,32);
732 
734 
735  vpImageTools::createSubImage(I,rect,Isub);
736 
737  vpImagePoint lastPtInSubIm(end[0]);
738  double u = 1.0;
739  double step =0.0001;
740  //Find the point of the nurbs closest from the edge of the subImage and in the subImage.
741  while (inRectangle(lastPtInSubIm,rect) && u > 0)
742  {
743  u -= step;
744  lastPtInSubIm = nurbs.computeCurvePoint(u);
745  }
746 
747  u += step;
748  if( u < 1.0)
749  lastPtInSubIm = nurbs.computeCurvePoint(u);
750 
751  IplImage* Ip = NULL;
752  vpImageConvert::convert(Isub, Ip);
753 
754 
755  IplImage* dst = cvCreateImage( cvSize((int)Isub.getWidth(), (int)Isub.getHeight()), 8, 1 );
756  cvCanny( Ip, dst, cannyTh1, cannyTh2, 3 );
757 
758  vpImageConvert::convert(dst, Isub);
759 
760  vpImagePoint firstBorder(-1,-1);
761 
762  firstBorder = findFirstBorder(Isub, lastPtInSubIm-topLeft);
763 
764  std::list<vpImagePoint> ip_edges_list;
765  if (firstBorder != vpImagePoint(-1, -1))
766  {
767  unsigned int dir;
768  double fi = firstBorder.get_i();
769  double fj = firstBorder.get_j();
770  double w = Isub.getWidth()-1;
771  double h = Isub.getHeight()-1;
772  //if (firstBorder.get_i() == 0) dir = 4;
773  if (std::fabs(fi) <= std::numeric_limits<double>::epsilon()) dir = 4;
774  //else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
775  else if (std::fabs(fi-h) <= std::fabs(vpMath::maximum(fi,h))*std::numeric_limits<double>::epsilon()) dir = 0;
776  //else if (firstBorder.get_j() == 0) dir = 2;
777  else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon()) dir = 2;
778  //else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
779  else if (std::fabs(fj-w) <= std::fabs(vpMath::maximum(fj,w))*std::numeric_limits<double>::epsilon()) dir = 6;
780 
781 
782  computeFreemanChainElement(Isub, firstBorder , dir);
783  unsigned int firstDir = dir;
784  ip_edges_list.push_back( firstBorder );
785  vpImagePoint border(firstBorder);
786  vpImagePoint dBorder;
787  do
788  {
789  computeFreemanParameters(dir, dBorder);
790  border = border + dBorder;
791  vpDisplay::displayPoint(I, border+topLeft, vpColor::orange) ;
792 
793  ip_edges_list.push_back( border );
794 
795  computeFreemanChainElement(Isub, border , dir);
796  } while( (border != firstBorder || dir != firstDir) && isInImage(Isub,border) );
797  }
798 
799  if (findCenterPoint(&ip_edges_list))
800  {
801 // list.end();
802  vpMeSite s;
803  while(true)//{//!list.outside())
804  {
805  s = list.back();//list.value() ;
806  vpImagePoint iP(s.ifloat,s.jfloat);
807  if (inRectangle(iP,rect))
808  {
809  list.erase(list.end()) ;
810 // list.end();
811  }
812  else
813  break;
814  }
815 
816  std::list<vpMeSite>::iterator itList = list.end();
817  --itList; // Move on the last element
818  double convlt;
819  double delta;
820  int nbr = 0;
821  std::list<vpMeSite> addedPt;
822  for(std::list<vpImagePoint>::const_iterator itEdges=ip_edges_list.begin(); itEdges!=ip_edges_list.end(); ++itEdges){
823  s = *itList;
824  vpImagePoint iPtemp = *itEdges + topLeft;
825  vpMeSite pix;
826  pix.init(iPtemp.get_i(), iPtemp.get_j(), 0);
827  dist = vpMeSite::sqrDistance(s,pix);
828  if (dist >= vpMath::sqr(me->getSampleStep()))
829  {
830  bool exist = false;
831  for(std::list<vpMeSite>::const_iterator itAdd=addedPt.begin(); itAdd!=addedPt.end(); ++itAdd){
832  dist = vpMeSite::sqrDistance(pix, *itAdd);
833  if (dist < vpMath::sqr(me->getSampleStep()))
834  exist = true;
835  }
836  if (!exist)
837  {
838  findAngle(I, iPtemp, me, delta, convlt);
839  pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
840  pix.setDisplay(selectDisplay);
841  list.push_back(pix);
842  addedPt.push_back(pix);
843  nbr++;
844  }
845  }
846  }
847 
848  unsigned int memory_range = me->getRange();
849  me->setRange(3);
850  std::list<vpMeSite>::iterator itList2 = list.end();
851  --itList2; // Move to the last element
852  for (int j = 0; j < nbr; j++)
853  {
854  vpMeSite me_s = *itList2;
855  me_s.track(I,me,false);
856  *itList2 = me_s;
857  --itList2;
858  }
859  me->setRange(memory_range);
860  }
861 
862  /* if (end != NULL) */ delete[] end;
863  endPtFound = 0;
864  }
865 #else
866  vpTRACE("To use the canny detection, OpenCV has to be installed.");
867 #endif
868 }
869 
870 
881 void
883 {
884  unsigned int n = numberOfSignal();
885  double nbPt = floor(dist / me->getSampleStep());
886 
887  if ((double)n < 0.7*nbPt)
888  {
889  sample(I);
891  }
892 }
893 
894 
901 void
903 {
904  int rows = (int)I.getHeight() ;
905  int cols = (int)I.getWidth() ;
906  vpImagePoint* iP = NULL;
907 
908  int n = (int)numberOfSignal();
909 
910 // list.front();
911  std::list<vpMeSite>::iterator it=list.begin();
912  std::list<vpMeSite>::iterator itNext=list.begin();
913  ++itNext;
914 
915  unsigned int range_tmp = me->getRange();
916  me->setRange(2);
917 
918  while(itNext!=list.end() && n <= me->getPointsToTrack())
919  {
920  vpMeSite s = *it;//current reference pixel
921  vpMeSite s_next = *itNext;//current reference pixel
922 
923  double d = vpMeSite::sqrDistance(s,s_next);
924  if(d > 4 * vpMath::sqr(me->getSampleStep()) && d < 1600)
925  {
926  vpImagePoint iP0(s.ifloat,s.jfloat);
927  vpImagePoint iPend(s_next.ifloat,s_next.jfloat);
928  vpImagePoint iP_1(s.ifloat,s.jfloat);
929 
930  double u = 0.0;
931  double ubegin = 0.0;
932  double uend = 0.0;
933  double dmin1_1 = 1e6;
934  double dmin2_1 = 1e6;
935  while(u < 1)
936  {
937  u+=0.01;
938  double dmin1 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u),iP0);
939  double dmin2 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u),iPend);
940 
941  if (dmin1 < dmin1_1)
942  {
943  dmin1_1 = dmin1;
944  ubegin = u;
945  }
946 
947  if (dmin2 < dmin2_1)
948  {
949  dmin2_1 = dmin2;
950  uend = u;
951  }
952  }
953  u = ubegin;
954 
955  //if(( u != 1.0 || uend != 1.0)
956  if( (std::fabs(u-1.0) > std::fabs(vpMath::maximum(u, 1.0))*std::numeric_limits<double>::epsilon())
957  || (std::fabs(uend-1.0) > std::fabs(vpMath::maximum(uend, 1.0))*std::numeric_limits<double>::epsilon()))
958  {
959  iP = nurbs.computeCurveDersPoint(u, 1);
960 
961  while (vpImagePoint::sqrDistance(iP[0],iPend) > vpMath::sqr(me->getSampleStep()) && u < uend)
962  {
963  u+=0.01;
964  /*if (iP!=NULL)*/ {
965  delete[] iP;
966  iP = NULL;
967  }
968  iP = nurbs.computeCurveDersPoint(u, 1);
969  if ( vpImagePoint::sqrDistance(iP[0],iP_1) > vpMath::sqr(me->getSampleStep()) && !outOfImage(iP[0], 0, rows, cols))
970  {
971  double delta = computeDelta(iP[1].get_i(),iP[1].get_j());
972  vpMeSite pix ; //= list.value();
973  pix.init(iP[0].get_i(), iP[0].get_j(), delta) ;
975  pix.track(I,me,false);
976  if (pix.getState() == vpMeSite::NO_SUPPRESSION)
977  {
978  list.insert(it, pix);
979  iP_1 = iP[0];
980  }
981  }
982  }
983  /*if (iP!=NULL)*/ {
984  delete[] iP;
985  iP = NULL;
986  }
987  }
988  }
989  ++it;
990  ++itNext;
991  }
992  me->setRange(range_tmp);
993 }
994 
995 
1001 void
1003 {
1004 #if 0
1005  // Loop through list of sites to track
1006  list.front();
1007  while(!list.nextOutside())
1008  {
1009  vpMeSite s = list.value() ;//current reference pixel
1010  vpMeSite s_next = list.nextValue() ;//current reference pixel
1011 
1012  if(vpMeSite::sqrDistance(s,s_next) < vpMath::sqr(me->getSampleStep()))
1013  {
1014  s_next.setState(vpMeSite::TOO_NEAR);
1015 
1016  list.next();
1017  list.modify(s_next);
1018  if (!list.nextOutside()) list.next();
1019  }
1020  else
1021  list.next() ;
1022  }
1023 #endif
1024  std::list<vpMeSite>::const_iterator it=list.begin();
1025  std::list<vpMeSite>::iterator itNext=list.begin();
1026  ++itNext;
1027  for(;itNext!=list.end();){
1028  vpMeSite s = *it;//current reference pixel
1029  vpMeSite s_next = *itNext;//current reference pixel
1030 
1031  if(vpMeSite::sqrDistance(s,s_next) < vpMath::sqr(me->getSampleStep())){
1032  s_next.setState(vpMeSite::TOO_NEAR);
1033 
1034  *itNext = s_next;
1035  ++it;
1036  ++itNext;
1037  if(itNext!=list.end()){
1038  ++it;
1039  ++itNext;
1040  }
1041  }
1042  else{
1043  ++it;
1044  ++itNext;
1045  }
1046  }
1047 }
1048 
1049 
1055 void
1057 {
1058  //Tracking des vpMeSites
1059  vpMeTracker::track(I);
1060 
1061  //Suppress points which are too close to each other
1063 
1064  //Suppressions des points ejectes par le tracking
1065  suppressPoints();
1066 
1067  //Recalcule les param�tres
1068 // nurbs.globalCurveInterp(list);
1069  nurbs.globalCurveApprox(list,nbControlPoints);
1070 
1071  //On resample localement
1072  localReSample(I);
1073 
1074  seekExtremities(I);
1075  if(enableCannyDetection)
1077 
1078 // nurbs.globalCurveInterp(list);
1079  nurbs.globalCurveApprox(list,nbControlPoints);
1080 
1081  double u = 0.0;
1082  vpImagePoint pt;
1083  vpImagePoint pt_1;
1084  dist = 0;
1085  while (u<=1.0)
1086  {
1087  pt = nurbs.computeCurvePoint(u);
1088  //if(u!=0)
1089  if(std::fabs(u) > std::numeric_limits<double>::epsilon())
1090  dist = dist + vpImagePoint::distance(pt,pt_1);
1091  pt_1 = pt;
1092  u=u+0.01;
1093  }
1094 
1095  updateDelta();
1096 
1097  reSample(I);
1098 }
1099 
1100 
1111 void
1113 {
1114  vpMeNurbs::display(I,nurbs,col);
1115 }
1116 
1117 
1134 bool
1135 vpMeNurbs::computeFreemanChainElement(const vpImage<unsigned char> &I,
1136  vpImagePoint &iP,
1137  unsigned int &element)
1138 {
1139  vpImagePoint diP;
1140  vpImagePoint iPtemp;
1141  if (hasGoodLevel( I, iP )) {
1142  // get the point on the right of the point passed in
1143  computeFreemanParameters((element + 2) %8, diP);
1144  iPtemp = iP + diP;
1145  if (hasGoodLevel( I, iPtemp )) {
1146  element = (element + 2) % 8; // turn right
1147  }
1148  else {
1149  computeFreemanParameters((element + 1) %8, diP);
1150  iPtemp = iP + diP;
1151 
1152  if ( hasGoodLevel( I, iPtemp )) {
1153  element = (element + 1) % 8; // turn diag right
1154  }
1155  else {
1156  computeFreemanParameters(element, diP);
1157  iPtemp = iP + diP;
1158 
1159  if ( hasGoodLevel( I, iPtemp )) {
1160  //element = element; // keep same dir
1161  }
1162  else {
1163  computeFreemanParameters((element + 7) %8, diP);
1164  iPtemp = iP + diP;
1165 
1166  if ( hasGoodLevel( I, iPtemp )) {
1167  element = (element + 7) %8; // turn diag left
1168  }
1169  else {
1170  computeFreemanParameters((element + 6) %8, diP);
1171  iPtemp = iP + diP;
1172 
1173  if ( hasGoodLevel( I, iPtemp )) {
1174  element = (element + 6) %8 ; // turn left
1175  }
1176  else {
1177  computeFreemanParameters((element + 5) %8, diP);
1178  iPtemp = iP + diP;
1179 
1180  if ( hasGoodLevel( I, iPtemp )) {
1181  element = (element + 5) %8 ; // turn diag down
1182  }
1183  else {
1184  computeFreemanParameters((element + 4) %8, diP);
1185  iPtemp = iP + diP;
1186 
1187  if ( hasGoodLevel( I, iPtemp )) {
1188  element = (element + 4) %8 ; // turn down
1189  }
1190  else {
1191  computeFreemanParameters((element + 3) %8, diP);
1192  iPtemp = iP + diP;
1193 
1194  if ( hasGoodLevel( I, iPtemp )) {
1195  element = (element + 3) %8 ; // turn diag right down
1196  }
1197  else {
1198  // No neighbor with a good level
1199  //
1200  return false;
1201  }
1202  }
1203  }
1204  }
1205  }
1206  }
1207  }
1208  }
1209  }
1210  else {
1211  return false;
1212  }
1213  return true;
1214 }
1215 
1216 
1229 bool vpMeNurbs::hasGoodLevel(const vpImage<unsigned char>& I,
1230  const vpImagePoint& iP) const
1231 {
1232  if( !isInImage( I, iP ) )
1233  return false;
1234 
1235  if( I((unsigned int)vpMath::round(iP.get_i()), (unsigned int)vpMath::round(iP.get_j())) > 0)
1236  {
1237  return true;
1238  }
1239  else
1240  {
1241  return false;
1242  }
1243 }
1244 
1245 
1256 bool vpMeNurbs::isInImage(const vpImage<unsigned char>& I, const vpImagePoint &iP) const
1257 {
1258  return (iP.get_i() >= 0
1259  && iP.get_j() >= 0
1260  && iP.get_i() < I.getHeight()
1261  && iP.get_j() < I.getWidth());
1262 }
1263 
1264 
1280 void
1281 vpMeNurbs::computeFreemanParameters( unsigned int element, vpImagePoint &diP)
1282 {
1283  /*
1284  5 6 7
1285  \ | /
1286  \|/
1287  4 ------- 0
1288  /|\
1289  / | \
1290  3 2 1
1291  */
1292  switch(element) {
1293  case 0: // go right
1294  diP.set_ij(0,1);
1295  break;
1296 
1297  case 1: // go right top
1298  diP.set_ij(1,1);
1299  break;
1300 
1301  case 2: // go top
1302  diP.set_ij(1,0);
1303  break;
1304 
1305  case 3:
1306  diP.set_ij(1,-1);
1307  break;
1308 
1309  case 4:
1310  diP.set_ij(0,-1);
1311  break;
1312 
1313  case 5:
1314  diP.set_ij(-1,-1);
1315  break;
1316 
1317  case 6:
1318  diP.set_ij(-1,0);
1319  break;
1320 
1321  case 7:
1322  diP.set_ij(-1,1);
1323  break;
1324  }
1325 }
1326 
1327 
1336 bool
1337 vpMeNurbs::farFromImageEdge(const vpImage<unsigned char>& I, const vpImagePoint& iP)
1338 {
1339  unsigned int height = I.getHeight();
1340  unsigned int width = I.getWidth();
1341  return (iP.get_i() < height - 20
1342  && iP.get_j() < width - 20
1343  && iP.get_i() > 20
1344  && iP.get_j() > 20);
1345 }
1346 
1358 {
1359  double u = 0.0;
1360  vpImagePoint pt;
1361  while (u <= 1)
1362  {
1363  pt = n.computeCurvePoint(u);
1364  vpDisplay::displayCross(I,pt,4,color);
1365  u+=0.01;
1366  }
1367 }
1368 
1380 {
1381  double u = 0.0;
1382  vpImagePoint pt;
1383  while (u <= 1)
1384  {
1385  pt = n.computeCurvePoint(u);
1386  vpDisplay::displayCross(I,pt,4,color);
1387  u+=0.01;
1388  }
1389 }
1390 
unsigned int getRange() const
Definition: vpMe.h:236
unsigned int getMaskSize() const
Definition: vpMe.h:164
void suppressPoints()
Definition: vpMeNurbs.cpp:390
virtual ~vpMeNurbs()
Definition: vpMeNurbs.cpp:259
void init()
Definition: vpMeSite.cpp:73
double get_i() const
Definition: vpImagePoint.h:194
bool outside(void) const
Test if the current element is outside the list (on the virtual element)
Definition: vpList.h:429
unsigned int getWidth() const
Definition: vpImage.h:159
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:100
void track(const vpImage< unsigned char > &Im)
Definition: vpMeNurbs.cpp:1056
void seekExtremitiesCanny(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:580
#define vpTRACE
Definition: vpDebug.h:418
Provide simple list management.
Definition: vpList.h:113
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:125
int outOfImage(int i, int j, int half, int rows, int cols)
double alpha
Definition: vpMeSite.h:104
int i
Definition: vpMeSite.h:98
error that can be emited by ViSP classes.
Definition: vpException.h:76
void initTracking(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:271
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:700
Contains predetermined masks for sites and holds moving edges tracking parameters.
Definition: vpMe.h:70
#define vpDEBUG_ENABLE(level)
Definition: vpDebug.h:530
Class that tracks in an image a edge defined by a Nurbs.
Definition: vpMeNurbs.h:129
static const vpColor green
Definition: vpColor.h:170
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1994
static int round(const double x)
Definition: vpMath.h:228
double get_j() const
Definition: vpImagePoint.h:205
void next(void)
position the current element on the next one
Definition: vpList.h:273
static Type abs(const Type &x)
Definition: vpMath.h:158
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:177
double ifloat
Definition: vpMeSite.h:100
int getStrip() const
Definition: vpMe.h:292
std::list< vpMeSite > list
Definition: vpMeTracker.h:80
unsigned int getAngleStep() const
Definition: vpMe.h:250
void supressNearPoints()
Definition: vpMeNurbs.cpp:1002
static double sqr(double x)
Definition: vpMath.h:106
void display(const vpImage< unsigned char > &I, vpColor col)
Definition: vpMeNurbs.cpp:1112
void front(void)
Position the current element on the first element of the list.
Definition: vpList.h:384
type & value(void)
return the value of the current element
Definition: vpList.h:301
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:882
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:348
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:876
static double rad(double deg)
Definition: vpMath.h:100
void localReSample(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:902
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:133
static double sqrDistance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:286
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:381
void seekExtremities(const vpImage< unsigned char > &I)
Definition: vpMeNurbs.cpp:456
void initTracking(const vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:150
Defines a rectangle in the plane.
Definition: vpRect.h:85
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:278
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:274
void set_ij(const double ii, const double jj)
Definition: vpImagePoint.h:180
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:270
static const vpColor blue
Definition: vpColor.h:173
void updateDelta()
Definition: vpMeNurbs.cpp:410