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