DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
FreemanChain.ih
1 
37 
38 // IMPLEMENTATION of inline methods.
40 
41 
42 
43 
45 // Iterator on points
46 
47 
48 template <typename TInteger>
49 inline
51  const FreemanChain & aChain, unsigned int n)
52  : myFc( &aChain ), myPos( 0 )
53 {
54  if ( n < myFc->chain.size() )
55  {
56  myXY.at(0)=aChain.x0;
57  myXY.at(1)=aChain.y0;
58  while ( myPos < n ) this->next();
59  }
60  else
61  {// iterator end()
62  myXY.at(0)=aChain.xn;
63  myXY.at(1)=aChain.yn;
64  myPos = (typename DGtal::FreemanChain<TInteger>::Index)(myFc->chain.size()+1);
65  }
66 }
67 
73 template <typename TInteger>
74 inline
77 {
78  if ( this != &other )
79  {
80  myFc = other.myFc;
81  myPos = other.myPos;
82  myXY = other.myXY;
83  }
84  return *this;
85 }
86 
87 
88 template <typename TInteger>
89 inline
91 {
92  if ( myPos < myFc->chain.size() )
93  {
94  switch ( myFc->code( myPos ) )
95  {
96  case '0': (myXY.at(0))++; break;
97  case '1': (myXY.at(1))++; break;
98  case '2': (myXY.at(0))--; break;
99  case '3': (myXY.at(1))--; break;
100  }
101  ++myPos;
102  } else ++myPos;
103 }
104 
105 
106 
107 
108 template <typename TInteger>
109 inline
111 {
112  if ( myPos < myFc->chain.size() )
113  {
114  switch ( myFc->code( myPos ) )
115  {
116  case '0': (myXY.at(0))++; break;
117  case '1': (myXY.at(1))++; break;
118  case '2': (myXY.at(0))--; break;
119  case '3': (myXY.at(1))--; break;
120  }
121  myPos = ( myPos + 1 ) % myFc->chain.size();
122  }
123 }
124 
125 
126 template <typename TInteger>
127 inline
129 {
130  if ( myPos == myFc->chain.size() + 1 )
131  {
132  myXY = myFc->lastPoint();
133  --myPos;
134  }
135  else
136  {
137  if ( myPos >= 1 )
138  --myPos;
139  if ( myPos < myFc->chain.size() )
140  {
141  switch ( myFc->code( myPos ) )
142  {
143  case '0': (myXY.at(0))--; break;
144  case '1': (myXY.at(1))--; break;
145  case '2': (myXY.at(0))++; break;
146  case '3': (myXY.at(1))++; break;
147  }
148  }
149  }
150 }
151 
152 
153 template <typename TInteger>
154 inline
156 {
157  if ( myPos == 0 ) myPos = (typename DGtal::FreemanChain<TInteger>::Index)(myFc->chain.size() - 1);
158  else --myPos;
159  switch ( myFc->code( myPos ) )
160  {
161  case '0': (myXY.at(0))--; break;
162  case '1': (myXY.at(1))--; break;
163  case '2': (myXY.at(0))++; break;
164  case '3': (myXY.at(1))++; break;
165  }
166 }
167 
168 
169 
171 // ----------------------- Standard services ------------------------------
172 
173 
174 
181 template <typename TInteger>
182 DGtal::FreemanChain<TInteger>::FreemanChain( const std::string & s, TInteger x, TInteger y )
183  : chain( s ), x0( x ), y0( y ), xn( x ), yn( y )
184 {
186 }
187 
188 
192 template <typename TInteger>
194 FreemanChain( const std::vector<Point>& vectPoints )
195 {
196  readFromPointsRange(vectPoints.begin(), vectPoints.end(), *this);
197 }
198 
199 
200 
205 template <typename TInteger>
207  read(in, *this);
208  computeLastPoint();
209 }
210 
211 
216 template <typename TInteger>
218  : chain( aOther.chain ), x0( aOther.x0 ), y0( aOther.y0 ),
219  xn( aOther.xn), yn( aOther.yn)
220 { }
221 
222 
223 
224 
230 template <typename TInteger>
233 {
234  if ( this != &aOther )
235  {
236  chain = aOther.chain;
237  x0 = aOther.x0;
238  y0 = aOther.y0;
239  xn = aOther.xn;
240  yn = aOther.yn;
241  }
242  return *this;
243 }
244 
245 
246 
247 
248 
250 // Iterators services
251 
252 
253 template <typename TInteger>
256 {
257  return ConstIterator( *this, 0 );
258 }
259 
260 
261 template <typename TInteger>
264 {
265  Point p(0,0); // *(end()) is invalid
266  return ConstIterator( *this, (typename DGtal::FreemanChain<TInteger>::Index)(chain.size() + 1), p );
267 }
268 
269 
274 template <typename TInteger>
277 {
278  ++aPos;
279  if ( aPos >= chain.size() )
280  aPos = 0;
281  return aPos;
282 }
283 
288 template <typename TInteger>
291 {
292  if ( aPos == 0 ) aPos = chain.size() - 1;
293  else --aPos;
294  return aPos;
295 }
296 
301 template <typename TInteger>
302 char
304 {
305  ASSERT( aPos < chain.size() );
306  //return chain[ aPos ] - '0';
307  return chain[ aPos ];
308 }
309 
310 
314 template <typename TInteger>
315 inline
318 {
319  return (typename DGtal::FreemanChain<TInteger>::Size)(chain.size());
320 }
321 
322 
323 template <typename TInteger>
324 inline
326  TInteger& min_y, TInteger& max_x, TInteger& max_y ) const
327 {
328  min_x = max_x = x0;
329  min_y = max_y = y0;
330  for ( ConstIterator it = begin();
331  it != end();
332  ++it )
333  {
334  Point p( *it );
335  if ( p.at(0) < min_x )
336  min_x = p.at(0);
337  else
338  if ( p.at(0) > max_x )
339  max_x = p.at(0);
340  if ( p.at(1) < min_y )
341  min_y = p.at(1);
342  else
343  if ( p.at(1) > max_y )
344  max_y = p.at(1);
345  }
346 }
347 
348 
349 template <typename TInteger>
350 inline
353 {
354  ConstIterator it = begin();
355  ConstIterator it_end = end();
356  // find first letters a and b.
357  char code1 = it.getCode();
358  it.next();
359  while ( ( it != it_end ) && ( it.getCode() == code1 ) )
360  it.next();
361  ASSERT( ( it != it_end )
362  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 1-letter freeman chain." );
363  char code2 = it.getCode();
364  // find third letter c.
365  while ( ( it != it_end ) && ( ( it.getCode() == code1 )
366  || ( it.getCode() == code2 ) ) )
367  it.next();
368  ASSERT( ( it != it_end )
369  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 2-letters Freeman chain." );
370  // reorder a and b.
371  it.previous();
372  if ( it.getCode() != code2 )
373  swap( code1, code2 );
374  // find first a.
375  do
376  {
377  it.previous();
378  }
379  while ( it.getCode() == code2 );
380  char a_char = chain[ it.getPosition() ];
381  // the next is the first b.
382  it.next();
383  char b_char = chain[ it.getPosition() ];
384  // Reorder the alphabet to match the quadrant change.
385  while ( A.order( b_char ) != 1 )
386  A.shiftLeft();
387  if ( A.order( a_char ) == 0 )
388  {
389  A.reverse();
390  while ( A.order( b_char ) != 1 )
391  A.shiftLeft();
392  }
393  ASSERT( ( A.order( b_char ) == 1 )
394  && ( A.order( a_char ) == 2 )
395  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] Internal error: invalid Quadrant change found." );
396  return it;
397 }
398 
399 
400 template <typename TInteger>
401 inline
404 {
405  ConstIterator it = begin();
406  ConstIterator it_end = end();
407  // find first letters a and b.
408  uint8_t code1 = it.getCode();
409  it.next();
410  while ( ( it != it_end ) && ( it.getCode() == code1 ) )
411  it.next();
412  ASSERT( ( it != it_end )
413  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 1-letter freeman chain." );
414  uint8_t code2 = it.getCode();
415  // find third letter c.
416  while ( ( it != it_end ) && ( ( it.getCode() == code1 )
417  || ( it.getCode() == code2 ) ) )
418  it.next();
419  ASSERT( ( it != it_end )
420  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 2-letters Freeman chain." );
421  uint8_t code3 = it.getCode();
422  // find fourth letter d.
423  while ( ( it != it_end ) && ( ( it.getCode() == code1 )
424  || ( it.getCode() == code2 )
425  || ( it.getCode() == code3 ) ) )
426  it.next();
427  ASSERT( ( it != it_end )
428  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 3-letters Freeman chain." );
429  // define true c.
430  it.previous();
431  code3 = it.getCode();
432  // find first b.
433  do
434  {
435  it.previous();
436  }
437  while ( it.getCode() == code3 );
438  char a_char = chain[ it.getPosition() ];
439  // the next is the first c.
440  it.next();
441  char b_char = chain[ it.getPosition() ];
442  // Reorder the alphabet to match the quadrant change.
443  while ( A.order( b_char ) != 1 )
444  A.shiftLeft();
445  if ( A.order( a_char ) == 0 )
446  {
447  A.reverse();
448  while ( A.order( b_char ) != 1 )
449  A.shiftLeft();
450  }
451  ASSERT( ( A.order( b_char ) == 1 )
452  && ( A.order( a_char ) == 2 )
453  && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] Internal error: invalid Quadrant change found." );
454  return it;
455 }
456 
457 
458 template <typename TInteger>
459 inline
461 {
462  return (x0 == xn) && (y0 == yn);
463 }
464 
465 
466 template <typename TInteger>
467 inline
469 {
470  ConstIterator it = this->begin();
471  ConstIterator it_end = this->end();
472  --it_end;
473  ConstIterator it_suiv = it;
474  Point spos = *it;
475  int nb_ccw_turns = 0;
476  while ( it != it_end )
477  {
478  int code1 = it.getCode();
479  it_suiv.nextInLoop();
480  int code2 = it_suiv.getCode();
481  char diff = ( code2 - code1 + 4 ) % 4;
482  if ( diff == 1 )
483  ++nb_ccw_turns;
484  else
485  if ( diff == 3 )
486  --nb_ccw_turns;
487  else
488  if ( diff == 2 )
489  return 0;
490  ++it;
491  }
492  if ( spos == *it_suiv )
493  return nb_ccw_turns / 4;
494  else
495  return 0;
496 }
497 
498 
499 template <typename TInteger>
500 inline
503 {
504  Self newChain;
505  Point startPoint = getPoint(pos);
506  Point endPoint = getPoint(pos+n);
507  newChain.chain = chain.substr(pos,n);
508  newChain.x0 = startPoint.at(0);
509  newChain.y0 = startPoint.at(1);
510  newChain.xn = endPoint.at(0);
511  newChain.yn = endPoint.at(1);
512  return newChain;
513 }
514 
515 
516 template <typename TInteger>
517 inline
520 {
521  Self newChain;
522  newChain.chain = chain + aOther.chain;
523  newChain.x0 = x0;
524  newChain.y0 = y0;
525  Point newLastPoint = lastPoint() + ( aOther.lastPoint() - aOther.firstPoint() );
526  newChain.xn = newLastPoint.at(0);
527  newChain.yn = newLastPoint.at(1);
528  return newChain;
529 }
530 
531 
532 template <typename TInteger>
533 inline
536 {
537  chain += aOther.chain;
538  Point newLastPoint = lastPoint() + ( aOther.lastPoint() - aOther.firstPoint() );
539  xn = newLastPoint.at(0);
540  yn = newLastPoint.at(1);
541  return *this;
542 }
543 
544 
545 template <typename TInteger>
546 inline
549 {
550  ConstIterator it;
551  Size n = this->size();
552  if ( aPos < n / 2 ) {
553  it = begin();
554  for (unsigned int i=0; i<aPos; ++i)
555  it++;
556  }
557  else
558  {
559  it = end();
560  it--;
561  n = n-aPos;
562  for (unsigned int i=0; i<n; ++i) {
563  it--;
564  }
565  }
566  return *it;
567 }
568 
569 
570 
571 template <typename TInteger>
572 inline
575 {
576  chain += std::string( &aCode, 1);
577  int dx=0, dy=0;
578  //displacement( dx, dy, aCode - '0' );
579  displacement( dx, dy, aCode );
580  xn += dx;
581  yn += dy;
582  return *this;
583 }
584 
585 
586 
587 
588 
589 template <typename TInteger>
590 inline
593 {
594  ConstIterator it = end();
595  for (unsigned int i=0; i<=n; ++i)
596  it--;
597  xn = (*it).at(0);
598  yn = (*it).at(1);
599  Size mySize = size();
600  ASSERT( (n <= mySize) && "Tried to shorten a FreemanChain by more then its length");
601  chain.resize( mySize - n );
602  return *this;
603 }
604 
605 
606 
607 
608 // ----------------------- Interface --------------------------------------
609 
610 
611 template <typename TInteger>
612 inline
613 void DGtal::FreemanChain<TInteger>::selfDisplay ( std::ostream & out ) const
614 {
615  out << x0 << " " << y0 << " " << chain;
616 }
617 
618 
623 template <typename TInteger>
624 inline
626 {
627  return true;
628 }
629 
630 
631 
632 
633 
634 
635 
636 
637 
639 // Static services
640 
641 
642 template <typename TInteger>
643 inline
644 void DGtal::FreemanChain<TInteger>::read( std::istream & in, FreemanChain & c )
645 {
646  string str;
647  while ( true )
648  {
649  getline( in, str );
650  if ( ! in.good() )
651  return;
652  if ( ( str.size() > 0 ) && ( str[ 0 ] != '#' ) )
653  {
654  istringstream str_in( str );
655  str_in >> c.x0 >> c.y0 >> c.chain;
656  return;
657  }
658  }
659 }
660 
661 template <typename TInteger>
662 template <typename TConstIterator>
663 inline
664 void DGtal::FreemanChain<TInteger>::readFromPointsRange( const TConstIterator& itBegin, const TConstIterator& itEnd, FreemanChain & c )
665 {
666  TConstIterator it( itBegin );
667 
668  if (it != itEnd)
669  { //if the range is not empty
670  Point startingPt( *it );
671  ++it;
672 
673  if (it != itEnd)
674  { //if there is more than one element
675  ostringstream oss;
676  Point pt( startingPt );
677  do
678  {
679 
680  Point ptSuiv( *it );
681  Integer dx = ptSuiv[0] - pt[0];
682  Integer dy = ptSuiv[1] - pt[1];
683  short number = ( dx != 0 ? (1 - dx) : (2 - dy) );
684  if ( (number < 0) || (number > 3) )
685  {
686  std::cerr << "not connected points (method readFromPointsRange of FreemanChain)" << std::endl;
687  throw ConnectivityException();
688  }
689  oss << number;
690  pt = ptSuiv;
691  ++it;
692 
693  } while ( it != itEnd );
694 
695  c.xn=pt[0];
696  c.yn=pt[1];
697  c.chain = oss.str();
698  }
699 
700  c.x0=startingPt[0];
701  c.y0=startingPt[1];
702  }
703 
704 }
705 
706 template <typename TInteger>
707 template <typename TRange>
708 inline
710 {
711  BOOST_CONCEPT_ASSERT(( CConstSinglePassRange<TRange> ));
712  readFromPointsRange( aRange.begin(), aRange.end(), c );
713 }
714 
715 template <typename TInteger>
716 inline
718  const FreemanChain & fc, std::vector<Point> & aVContour)
719 {
720  aVContour.clear();
721  for ( ConstIterator it = fc.begin();
722  it != fc.end();
723  ++it )
724  {
725  aVContour.push_back(*it);
726  }
727 }
728 
729 
730 
731 template <typename TInteger>
732 void
734  switch ( aCode )
735  {
736  case '0': aPoint.at(0)++; break;
737  case '1': aPoint.at(1)++; break;
738  case '2': aPoint.at(0)--; break;
739  case '3': aPoint.at(1)--; break;
740  }
741 }
742 
743 // Depreciated
744 //
745 //template <typename TInteger>
746 //void
747 //DGtal::FreemanChain<TInteger>::alphabet( char & aZero, char & aOne, char aQuadrant )
748 //{
749 // switch ( aQuadrant )
750 // {
751 // case '0':
752 // aZero = '0';
753 // aOne = '1';
754 // break;
755 // case '1':
756 // aZero = '1';
757 // aOne = '2';
758 // break;
759 // case '2':
760 // aZero = '2';
761 // aOne = '3';
762 // break;
763 // case '3':
764 // aZero = '3';
765 // aOne = '0';
766 // break;
767 // }
768 //
769 //};
770 
771 
772 
773 template <typename TInteger>
774 inline
776  char aCode2, bool ccw )
777 {
778  unsigned int cfg = ( ccw ? 0 : 16 ) + ( (aCode1 - '0') << 2 ) + (aCode2 - '0');
779  static const char tbl[ 32 ] =
780  {
781  '2', '1', '0', '3', '3', '2', '1', '0',
782  '0', '3', '2', '1', '1', '0', '3', '2',
783  '2', '3', '0', '1', '1', '2', '3', '0',
784  '0', '1', '2', '3', '3', '0', '1', '2'
785  };
786  return tbl[ cfg ];
787 }
788 
789 
790 
791 template <typename TInteger>
792 inline
794 {
795  return '0' + ( ( (code - '0' ) + n ) & 3 );
796 }
797 
798 
799 
800 
801 
802 template <typename TInteger>
803 inline
804 void
805 DGtal::FreemanChain<TInteger>::displacement( int & dx, int & dy, char aCode )
806 {
807  switch ( aCode )
808  {
809  case '0': dx = 1; dy = 0; break;
810  case '1': dx = 0; dy = 1; break;
811  case '2': dx = -1; dy = 0; break;
812  case '3': dx = 0; dy = -1; break;
813  }
814 }
815 
816 
817 template <typename TInteger>
818 inline
821 {
822 #ifdef CPP11_INITIALIZER_LIST
823  switch ( aCode )
824  {
825  case '0': return Point({1,0});
826  case '1': return Point({0,1});
827  case '2': return Point({-1,0});
828  case '3': return Point({0,-1});
829  }
830  return Point({0,0});
831 #else
832  int t[2] = {0,0};
833 
834  switch ( aCode )
835  {
836  case '0': t[0]++; return Point( t );
837  case '1': t[1]++; return Point( t );
838  case '2': t[0]--; return Point( t );
839  case '3': t[1]--; return Point( t );
840  }
841  return Point( t );
842 #endif //CPP11_INITIALIZER_LIST
843 }
844 
845 
846 
847 template <typename TInteger>
848 inline
849 char
851 {
852  if ( ccw ) return ( aCode == '3' ) ? '0' : ( aCode + 1 );
853  else return ( aCode == '0' ) ? '3' : ( aCode - 1 );
854 }
855 //DGtal::FreemanChain<TInteger>::turnedCode( unsigned int aCode, bool ccw )
856 //{
857 // if ( ccw ) return ( aCode + 1 ) & 0x3;
858 // else return ( aCode - 1 ) & 0x3;
859 //}
860 
861 
862 
863 
864 
865 
866 
867 template <typename TInteger>
869  FreemanChain & aInnerChain,
870  std::vector<unsigned int> & aOuter2inner,
871  std::vector<unsigned int> & aInner2outer,
872  const FreemanChain & aOuterChain,
873  bool ccw )
874 {
875  unsigned int nb = (unsigned int)aOuterChain.chain.size();
876  unsigned int j = 0;
877  aOuter2inner.clear();
878  aOuter2inner.reserve( nb );
879  // aInnerChain.chain.reserve( nb + 4 );
880  aInnerChain.chain = "";
881  aInner2outer.clear();
882  aInner2outer.reserve( nb + ( ccw ? 4 : -4 ) );
883  int dx0=0, dy0=0;
884  int dx1=0, dy1=0;
885  FreemanChain<TInteger>::displacement( dx0, dy0, aOuterChain.code( 0 ) );
886  int turn = ccw ? 1 : 3;
887  //FreemanChain<TInteger>::displacement( dx1, dy1, ( aOuterChain.code( 0 ) + turn ) % 4 );
888  FreemanChain<TInteger>::displacement( dx1, dy1, addToCode( aOuterChain.code( 0 ) , turn ) );
889  dx0 += dx1;
890  dy0 += dy1;
891  aInnerChain.x0 = dx0 > 0 ? aOuterChain.x0 : aOuterChain.x0 - 1;
892  aInnerChain.y0 = dy0 > 0 ? aOuterChain.y0 : aOuterChain.y0 - 1;
893 
894  ConstIterator it_begin = aOuterChain.begin();
895  ConstIterator it = it_begin;
896  it.next();
897  for ( unsigned int i = 0; i < nb; ++i )
898  {
899  // Check if contour is open.
900  // cerr << "i=" << i << " code=" << aOuterChain.code( i ) << endl;
901  switch ( movement( aOuterChain.code( i ), aOuterChain.code( ( i + 1 ) % nb ), ccw ) )
902  {
903  case '0':
904  // contour going in then out.
905  aInnerChain.chain += aOuterChain.chain[ i ];
906  //aInnerChain.chain += ( ( ( (unsigned int) ( aOuterChain.chain[ i ] - '0' )
907  // + ( ccw ? 3 : 1 ) ) )
908  // % 4 ) + '0';
909  aInnerChain.chain += addToCode ( aOuterChain.chain[ i ], (ccw) ? 3 : 1 );
910  aInnerChain.chain += aOuterChain.chain[ ( i + 1 ) % nb ];
911  aOuter2inner.push_back( j );
912  aInner2outer.push_back( i );
913  aInner2outer.push_back( i + 1 );
914  aInner2outer.push_back( i + 1 );
915  j += 3;
916  break;
917 
918  case '1':
919  // contour turning toward its inside.
920  aOuter2inner.push_back( j );
921  break;
922 
923  case '2':
924  // contour going straight ahead
925  aInnerChain.chain += aOuterChain.chain[ i ];
926  aOuter2inner.push_back( j );
927  aInner2outer.push_back( i );
928  ++j;
929  break;
930 
931  case '3':
932  // contour turning toward its outside.
933  aInnerChain.chain += aOuterChain.chain[ i ];
934  aInnerChain.chain += aOuterChain.chain[ ( i + 1 ) % nb ];
935  aOuter2inner.push_back( j );
936  aInner2outer.push_back( i );
937  aInner2outer.push_back( i + 1 );
938  j += 2;
939  break;
940  }
941 
942  // Advances along contour and check if it is a closed contour.
943  it.next();
944  if ( ( i == nb - 1 )
945  && ( *it_begin != *it ) )
946  // freeman chain is *not* a closed loop.
947  {
948  aInnerChain.chain += aOuterChain.chain[ i ];
949  aOuter2inner.push_back( j );
950  aInner2outer.push_back( i );
951  ++i;
952  ++j;
953  break;
954  }
955  }
956 }
957 
958 
959 
960 
961 template <typename TInteger>
963  FreemanChain & aCleanC,
964  std::vector<unsigned int> & aC2clean,
965  std::vector<unsigned int> & aClean2c,
966  const FreemanChain & c,
967  bool ccw )
968 {
969  unsigned int nb = (unsigned int)c.chain.size();
970  if ( nb == 0 )
971  {
972  cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
973  << " cleanOuterSpikes: Empty input chain"
974  << endl;
975  return false;
976  }
977 
981  vector<unsigned int> c2cleanTMP;
982  aCleanC.chain.reserve( nb );
983  aCleanC.chain = "";
984  aC2clean.clear();
985  aClean2c.clear();
986  aC2clean.reserve( nb );
987  aClean2c.reserve( nb );
988  c2cleanTMP.reserve( nb );
989  ConstIterator it = c.begin();
990  ConstIterator itn = c.begin();
991  itn.nextInLoop();
992  // Find a consistent starting point.
993  unsigned int n;
994  unsigned int size_spike = 0;
995  for ( n = 0; n < nb; ++n )
996  {
997  size_spike = 0;
998  while ( movement( it.getCode(), itn.getCode(), ccw ) == '0' )
999  {
1000  it.previousInLoop();
1001  itn.nextInLoop();
1002  mc.increment( i );
1003  size_spike += 2;
1004  if ( size_spike >= nb )
1005  {
1006  cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1007  << " Spike is longer than contour !"
1008  << " size_spike=" << size_spike
1009  << " nb=" << nb
1010  << endl;
1011  return false;
1012  }
1013  }
1014  mc.increment( i );
1015  it = itn;
1016  itn.nextInLoop();
1017  if ( size_spike > 0 )
1018  break;
1019  }
1020  unsigned int start_idx = it.getPosition();
1021  i = start_idx;
1022  // JOL : 2009/07/07, added starting coordinates
1023  // XP : 2011/09/06, added ending coordinates
1024  Point P = *it;
1025  aCleanC.x0 = P.at(0);
1026  aCleanC.y0 = P.at(1);
1027  aCleanC.xn = P.at(0);
1028  aCleanC.yn = P.at(1);
1029 
1030  // cerr << "Starting point is " << i << endl;
1031  ASSERT( ( n < nb ) || ( i == 0 ) );
1032  if ( n == nb )
1033  { // do nothing
1034  aCleanC.chain = c.chain;
1035  for ( unsigned int ni = 0; ni < nb; ++ni )
1036  {
1037  aC2clean.push_back( ni );
1038  aClean2c.push_back( ni );
1039  }
1040  if ( size_spike != 0 )
1041  cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1042  << "No starting point found (only spikes !)" << endl;
1043 
1044  return size_spike == 0;
1045  }
1046  // Loops over all letters.
1047  ConstIterator it_begin = it;
1048  deque<unsigned int> clean_code;
1049  deque<unsigned int> clean_idx;
1050  vector<unsigned int> begin_outer_spike;
1051  vector<unsigned int> end_outer_spike;
1052  // i follows iterator it.
1053  do
1054  {
1055  clean_code.push_back( it.getCode() );
1056  clean_idx.push_back( i );
1057  itn = it;
1058  it.nextInLoop();
1059  mc.increment( i );
1060  // cerr << "- i=" << i << " (" << clean_code.back()
1061  // << it.getCode() << ") ";
1062  size_spike = 0;
1063  unsigned int last_spike_idx = end_outer_spike.empty() ?
1064  start_idx :
1065  end_outer_spike.back();
1066  j = i;
1067  while ( ( ! clean_code.empty() )
1068  && ( j != last_spike_idx )
1069  && ( movement( clean_code.back(), it.getCode(), ccw ) == '0' )
1070  && ( it != it_begin ) )
1071  {
1072  clean_code.pop_back();
1073  clean_idx.pop_back();
1074  mc.increment( i );
1075  mc.decrement( j );
1076  it.nextInLoop();
1077  itn.previousInLoop();
1078  size_spike += 2;
1079  }
1080  // cerr << "i=" << i << " size_spike=" << size_spike
1081  // << " last_spike_idx=" << last_spike_idx
1082  // << endl;
1083  if ( size_spike != 0 )
1084  {
1085  // There is a spike. Is it an outer one ?
1086  unsigned int previous_code = itn.getCode();
1087  unsigned int previous_idx = itn.getPosition();
1088  // JOL : do not
1089  // consider any more "cleaned contour" since we cannot go
1090  // further than the last spike.
1091  // unsigned int previous_code =
1092  // clean_code.empty() ? itn.getCode() : clean_code.back();
1093  // unsigned int previous_idx =
1094  // clean_code.empty() ? itn.getPosition() : clean_idx.back();
1095  itn = it;
1096  itn.previousInLoop();
1097  unsigned int move1 = movement( previous_code, addToCode ( itn.getCode() , 2 ), ccw );
1098  unsigned int move2 = movement( itn.getCode(), it.getCode() , ccw );
1099  bool return_spike = ( move1 == '0' ) || ( move2 == '0' );
1100  bool outer_spike = ( move1 == '3' ) || ( move2 == '3' );
1101  // if ( return_spike )
1102  // cerr << "[DGtal::FreemanChain::cleanOuterSpikes] return spike."
1103  // << endl;
1104  // if ( ! ( ( outer_spike && ( move1 != 1 ) && ( move2 != 1 ) )
1105  // || ( ! outer_spike && ( move1 != 3 ) && ( move2 != 3 ) ) ) )
1106  // cerr << "[DGtal::FreemanChain::cleanOuterSpikes] "
1107  // << "Weird spike. Invalid contour (expected 3 3) ?"
1108  // << " move1=" << move1
1109  // << " move2=" << move2
1110  // << " ccw=" << ccw
1111  // << " start_idx=" << start_idx
1112  // << " size_spike=" << size_spike
1113  // << " it=" << it.getPosition()
1114  // << " itp=" << previous_idx
1115  // << endl
1116  // << c.chain << endl;
1117  // Process waiting steps.
1118  if ( outer_spike || return_spike )
1119  {
1120  begin_outer_spike.push_back( mc.next( previous_idx ) );
1121  end_outer_spike.push_back( i );
1122  // cout << " outer spike [" << begin_outer_spike.back()
1123  // << "," << end_outer_spike.back() << "[ " << endl;
1124  }
1125  }
1126  }
1127  while ( it != it_begin );
1128 
1129  // Once outer spikes are known, we can create the new contour.
1130  aC2clean.resize( nb );
1131  i = start_idx % nb;
1132  j = 0;
1133  unsigned int nb_spikes = (unsigned int)begin_outer_spike.size();
1134  unsigned int k = 0;
1135  n = 0;
1136  while ( n < nb )
1137  {
1138  if ( ( k == nb_spikes ) || ( i != begin_outer_spike[ k ] ) )
1139  {
1140  aCleanC.chain.push_back( c.chain[ i ] );
1141  aC2clean[ i ] = j;
1142  aClean2c.push_back( i );
1143  mc.increment( i );
1144  ++j;
1145  ++n;
1146  }
1147  else
1148  {
1149  while ( i != end_outer_spike[ k ] )
1150  {
1151  aC2clean[ i ] = j;
1152  mc.increment( i );
1153  ++n;
1154  }
1155  ++k;
1156  }
1157  }
1158  for ( unsigned int ii = 0; ii < nb; ++ii )
1159  if ( aC2clean[ ii ] >= aCleanC.chain.size() )
1160  {
1161  if ( aC2clean[ ii ] == aCleanC.chain.size() )
1162  aC2clean[ ii ] = 0;
1163  else
1164  {
1165  cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1166  << "Bad correspondence for aC2clean[" << ii << "]"
1167  << " = " << aC2clean[ ii ] << " >= " << aCleanC.chain.size()
1168  << endl;
1169  aC2clean[ ii ] = aC2clean[ ii ] % aCleanC.chain.size();
1170  }
1171  }
1172 
1173  for ( unsigned int jj = 0; j < aCleanC.chain.size(); ++jj )
1174  if ( aClean2c[ jj ] >= nb )
1175  {
1176  cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1177  << "Bad correspondence for aClean2c[" << jj << "]"
1178  << " = " << aClean2c[ jj ] << " >= " << nb
1179  << endl;
1180  aClean2c[ jj ] = aClean2c[ jj ] % nb;
1181  }
1182  return true;
1183 }
1184 
1185 
1186 
1187 
1188 
1189 
1190 
1191 
1192 
1193 // /**
1194 // * Given a Freeman chain [c] coding a 4-connected pixel loop, computes
1195 // * its subsampling by the transformation:
1196 // * X = ( x - x0 ) div h,
1197 // * Y = ( y - y0 ) div v.
1198 // *
1199 // * @param aSubc (output) the subsampled Freeman chain code (may
1200 // * contain spikes)
1201 // *
1202 // * @param aC2subc (output) the mapping associating an element to
1203 // * its subsampled element.
1204 // *
1205 // * @param aSubc2c (output) the inverse mapping associating a
1206 // * subsampled element to its element. More precisely, subc2c[ j ]
1207 // * is the last pointel to be in j.
1208 // *
1209 // * @param c the input chain code.
1210 // *
1211 // * @param h the subsampling along x
1212 // * @param v the subsampling along y
1213 // * @param x0 the x-origin of the frame (X,Y) in (x,y)
1214 // * @param y0 the y-origin of the frame (X,Y) in (x,y)
1215 // *
1216 // * @return 'false' if initial contour was empty or if [subc] is empty,
1217 // * 'true' otherwise.
1218 // */
1219 // static bool subsample( FreemanChain & aSubc,
1220 // std::vector<unsigned int> & aC2subc,
1221 // std::vector<unsigned int> & aSubc2c,
1222 // const FreemanChain & c,
1223 // unsigned int h, unsigned int v,
1224 // int x0, int y0 ){
1225 // if ( ( h == 0 ) || ( v == 0 ) ) return false;
1226 // FreemanChain<TInteger>::ConstIterator it = c.begin();
1227 // unsigned int j = 0;
1228 // unsigned int nb = c.chain.size();
1229 // if ( nb == 0 ) return false;
1230 // Point fxy( it.get() );
1231 // Point fXY;
1232 // fXY.at(0)= ( fxy.at(0) - x0 ) / h;
1233 // fXY.at(1)= ( fxy.at(1) - y0 ) / v;
1234 // aSubc.x0 = fXY.at(0);
1235 // aSubc.y0 = fXY.at(1);
1236 // aC2subc.clear();
1237 // aC2subc.reserve( nb );
1238 // aSubc2c.clear();
1239 // aSubc2c.reserve( nb );
1240 // for ( unsigned int i = 0; i < nb; ++i )
1241 // {
1242 // aC2subc.push_back( j );
1243 // it.nextInLoop();
1244 // Point nxy( it.get() );
1245 // Point nXY;
1246 // nXY.at(0)= ( nxy.at(0) - x0 ) / h;
1247 // nXY.at(1)= ( nxy.at(1) - y0 ) / v;
1248 // if ( nXY != fXY )
1249 // {
1250 // aSubc2c.push_back( i );
1251 // char code;
1252 // if ( nXY.at(0) > fXY.at(0) ) code = '0';
1253 // else if ( nXY.at(0) < fXY.at(0) ) code = '2';
1254 // else if ( nXY.at(1) > fXY.at(1) ) code = '1';
1255 // else code = '3';
1256 // aSubc.chain += code;
1257 // ++j;
1258 // fXY = nXY;
1259 // }
1260 // }
1261 // // aC2subc.push_back( j );
1262 // // it.nextInLoop();
1263 // // for ( unsigned int i = 1; i <= nb; ++i )
1264 // // {
1265 // // // JOL
1266 // // //aC2subc.push_back( j );
1267 // // Vector2i nxy( it.get() );
1268 // // Vector2i nXY( ( nxy.x() - x0 ) / h, ( nxy.y() - y0 ) / v );
1269 // // if ( nXY != fXY )
1270 // // {
1271 // // char code;
1272 // // if ( nXY.x() > fXY.x() ) code = '0';
1273 // // else if ( nXY.x() < fXY.x() ) code = '2';
1274 // // else if ( nXY.y() > fXY.y() ) code = '1';
1275 // // else code = '3';
1276 // // aSubc.chain += code;
1277 // // aSubc2c.push_back( i - 1 );
1278 // // ++j;
1279 // // fXY = nXY;
1280 // // }
1281 // // if ( i != nb ) aC2subc.push_back( j );
1282 // // it.nextInLoop();
1283 // // }
1284 // // // TODO : enhance this.
1285 // unsigned int nbsub = aSubc.chain.size();
1286 // // Last correspondence may be in fact to 0 instead of nbsub.
1287 // if ( nbsub != 0 )
1288 // for ( unsigned int i = 0; i < nb; ++i )
1289 // if ( aC2subc[ i ] >= nbsub ) aC2subc[ i ] -= nbsub;
1290 // ASSERT( aC2subc.size() == nb );
1291 // return nbsub != 0;
1292 // }
1293 
1294 
1295 
1296 
1297 
1299 // Drawing services
1300 
1301 template <typename TInteger>
1302 inline
1303 std::string
1305 {
1306  return "FreemanChain";
1307 }
1308 
1309 template <typename TInteger>
1310 inline
1311 void
1313 {
1314  ConstIterator it = this->begin();
1315  for (unsigned int i=0; i < chain.size(); ++i)
1316  it++;
1317  xn = (*it).at(0);
1318  yn = (*it).at(1);
1319 }
1320 
1321 
1322 
1323 
1324 
1325 
1327 // Implementation of inline functions and external operators //
1328 
1335 template <typename TInteger>
1336 inline
1337  std::ostream&
1338 DGtal::operator<< ( std::ostream & out,
1339  const FreemanChain<TInteger> & aObject )
1340 {
1341  aObject.selfDisplay ( out );
1342  return out;
1343 }
1344 
1345 // //
1347 
1348