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