2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file FreemanChain.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5807), University of Savoie, France
21 * @author Bertrand Kerautret (\c kerautre@loria.fr )
22 * LORIA (CNRS, UMR 7503), University of Nancy, France
23 * @author Xavier Provençal (\c xavier.provencal@univ-savoie.fr )
24 * Laboratory of Mathematics (CNRS, UMR 5807), University of Savoie, France
25 * @author Tristan Roussillon (\c
26 * tristan.roussillon@liris.cnrs.fr ) Laboratoire d'InfoRmatique en
27 * Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS,
32 * @brief Implementation of inline methods defined in FreemanChain.h
34 * This file is part of the DGtal library.
37 ///////////////////////////////////////////////////////////////////////////////
38 // IMPLEMENTATION of inline methods.
39 ///////////////////////////////////////////////////////////////////////////////
44 ///////////////////////////////////////////////////////////////////////////////
48 template <typename TInteger>
50 DGtal::FreemanChain<TInteger>::ConstIterator::ConstIterator(
51 ConstAlias<FreemanChain> aChain, unsigned int n)
52 : myFc( &aChain ), myPos( 0 )
54 if ( n < myFc->chain.size() )
58 while ( myPos < n ) this->next();
64 myPos = (typename DGtal::FreemanChain<TInteger>::Index)(myFc->chain.size()+1);
70 * @param other the iterator to copy.
71 * @return a reference on 'this'.
73 template <typename TInteger>
75 typename DGtal::FreemanChain<TInteger>::ConstIterator &
76 DGtal::FreemanChain<TInteger>::ConstIterator::operator= ( const ConstIterator & other )
88 template <typename TInteger>
90 void DGtal::FreemanChain<TInteger>::ConstIterator::next()
92 if ( myPos < myFc->chain.size() )
94 switch ( myFc->code( myPos ) )
96 case '0': (myXY[0])++; break;
97 case '1': (myXY[1])++; break;
98 case '2': (myXY[0])--; break;
99 case '3': (myXY[1])--; break;
108 template <typename TInteger>
110 void DGtal::FreemanChain<TInteger>::ConstIterator::nextInLoop()
112 if ( myPos < myFc->chain.size() )
114 switch ( myFc->code( myPos ) )
116 case '0': (myXY[0])++; break;
117 case '1': (myXY[1])++; break;
118 case '2': (myXY[0])--; break;
119 case '3': (myXY[1])--; break;
121 myPos = ( myPos + 1 ) % myFc->chain.size();
126 template <typename TInteger>
128 void DGtal::FreemanChain<TInteger>::ConstIterator::previous()
130 if ( myPos == myFc->chain.size() + 1 )
132 myXY = myFc->lastPoint();
139 if ( myPos < myFc->chain.size() )
141 switch ( myFc->code( myPos ) )
143 case '0': (myXY[0])--; break;
144 case '1': (myXY[1])--; break;
145 case '2': (myXY[0])++; break;
146 case '3': (myXY[1])++; break;
153 template <typename TInteger>
155 void DGtal::FreemanChain<TInteger>::ConstIterator::previousInLoop()
157 if ( myPos == 0 ) myPos = (typename DGtal::FreemanChain<TInteger>::Index)(myFc->chain.size() - 1);
159 switch ( myFc->code( myPos ) )
161 case '0': (myXY[0])--; break;
162 case '1': (myXY[1])--; break;
163 case '2': (myXY[0])++; break;
164 case '3': (myXY[1])++; break;
170 ///////////////////////////////////////////////////////////////////////////////
171 // ----------------------- Standard services ------------------------------
177 * @param s the chain code.
178 * @param x the x-coordinate of the first point.
179 * @param y the y-coordinate of the first point.
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 )
185 DGtal::FreemanChain<TInteger>::computeLastPoint();
192 template <typename TInteger>
193 DGtal::FreemanChain<TInteger>::
194 FreemanChain( const std::vector<Point>& vectPoints )
196 readFromPointsRange(vectPoints.begin(), vectPoints.end(), *this);
203 * @param in any input stream,
205 template <typename TInteger>
206 DGtal::FreemanChain<TInteger>::FreemanChain(std::istream & in ){
214 * @param aOther the object to clone.
216 template <typename TInteger>
217 DGtal::FreemanChain<TInteger>::FreemanChain( const FreemanChain<TInteger> & aOther )
218 : chain( aOther.chain ), x0( aOther.x0 ), y0( aOther.y0 ),
219 xn( aOther.xn), yn( aOther.yn)
227 * @param aOther the object to copy.
228 * @return a reference on 'this'.
230 template <typename TInteger>
231 typename DGtal::FreemanChain<TInteger> &
232 DGtal::FreemanChain<TInteger>::operator=( const FreemanChain<TInteger> & aOther )
234 if ( this != &aOther )
236 chain = aOther.chain;
249 ///////////////////////////////////////////////////////////////////////////////
250 // Iterators services
253 template <typename TInteger>
254 typename DGtal::FreemanChain<TInteger>::ConstIterator
255 DGtal::FreemanChain<TInteger>::begin() const
257 return ConstIterator( *this, 0 );
261 template <typename TInteger>
262 typename DGtal::FreemanChain<TInteger>::ConstIterator
263 DGtal::FreemanChain<TInteger>::end() const
265 Point p(0,0); // *(end()) is invalid
266 return ConstIterator( *this, (typename DGtal::FreemanChain<TInteger>::Index)(chain.size() + 1), p );
271 * @param aPos a position in the chain code.
272 * @return the next position.
274 template <typename TInteger>
275 typename DGtal::FreemanChain<TInteger>::Index
276 DGtal::FreemanChain<TInteger>::next( Index aPos ) const
279 if ( aPos >= chain.size() )
285 * @param aPos a position in the chain code.
286 * @return the previous position.
288 template <typename TInteger>
289 typename DGtal::FreemanChain<TInteger>::Index
290 DGtal::FreemanChain<TInteger>::previous( Index aPos ) const
292 if ( aPos == 0 ) aPos = chain.size() - 1;
298 * @param aPos a position in the chain code.
299 * @return the code at position [aPos].
301 template <typename TInteger>
303 DGtal::FreemanChain<TInteger>::code( Index aPos ) const
305 ASSERT( aPos < chain.size() );
306 //return chain[ aPos ] - '0';
307 return chain[ aPos ];
312 * @return the length of the Freeman chain code.
314 template <typename TInteger>
316 typename DGtal::FreemanChain<TInteger>::Index
317 DGtal::FreemanChain<TInteger>::size() const
319 return (typename DGtal::FreemanChain<TInteger>::Size)(chain.size());
323 template <typename TInteger>
325 void DGtal::FreemanChain<TInteger>::computeBoundingBox( TInteger & min_x,
326 TInteger& min_y, TInteger& max_x, TInteger& max_y ) const
330 for ( ConstIterator it = begin();
349 template <typename TInteger>
351 typename DGtal::FreemanChain<TInteger>::ConstIterator
352 DGtal::FreemanChain<TInteger>::findQuadrantChange( OrderedAlphabet & A ) const
354 ConstIterator it = begin();
355 ConstIterator it_end = end();
356 // find first letters a and b.
357 char code1 = it.getCode();
359 while ( ( it != it_end ) && ( it.getCode() == code1 ) )
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 ) ) )
368 ASSERT( ( it != it_end )
369 && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 2-letters Freeman chain." );
372 if ( it.getCode() != code2 )
373 std::swap( code1, code2 );
379 while ( it.getCode() == code2 );
380 char a_char = chain[ it.position() ];
381 // the next is the first b.
383 char b_char = chain[ it.position() ];
384 // Reorder the alphabet to match the quadrant change.
385 while ( A.order( b_char ) != 1 )
387 if ( A.order( a_char ) == 0 )
390 while ( A.order( b_char ) != 1 )
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." );
400 template <typename TInteger>
402 typename DGtal::FreemanChain<TInteger>::ConstIterator
403 DGtal::FreemanChain<TInteger>::findQuadrantChange4( OrderedAlphabet & A ) const
405 ConstIterator it = begin();
406 ConstIterator it_end = end();
407 // find first letters a and b.
408 uint8_t code1 = it.getCode();
410 while ( ( it != it_end ) && ( it.getCode() == code1 ) )
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 ) ) )
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 ) ) )
427 ASSERT( ( it != it_end )
428 && "[DGtal::FreemanChain::findQuadrantChange( OrderedAlphabet & A ) const] 3-letters Freeman chain." );
431 code3 = it.getCode();
437 while ( it.getCode() == code3 );
438 char a_char = chain[ it.position() ];
439 // the next is the first c.
441 char b_char = chain[ it.position() ];
442 // Reorder the alphabet to match the quadrant change.
443 while ( A.order( b_char ) != 1 )
445 if ( A.order( a_char ) == 0 )
448 while ( A.order( b_char ) != 1 )
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." );
458 template <typename TInteger>
460 int DGtal::FreemanChain<TInteger>::isClosed() const
462 return (x0 == xn) && (y0 == yn);
466 template <typename TInteger>
468 int DGtal::FreemanChain<TInteger>::ccwLoops() const
470 ConstIterator it = this->begin();
471 ConstIterator it_end = this->end();
473 ConstIterator it_suiv = it;
475 int nb_ccw_turns = 0;
476 while ( it != it_end )
478 int code1 = it.getCode();
479 it_suiv.nextInLoop();
480 int code2 = it_suiv.getCode();
481 char diff = ( code2 - code1 + 4 ) % 4;
492 if ( spos == *it_suiv )
493 return nb_ccw_turns / 4;
499 template <typename TInteger>
501 typename DGtal::FreemanChain<TInteger>
502 DGtal::FreemanChain<TInteger>::subChain(Index pos, Size n) const
505 Point startPoint = getPoint(pos);
506 Point endPoint = getPoint(pos+n);
507 newChain.chain = chain.substr(pos,n);
508 newChain.x0 = startPoint[0];
509 newChain.y0 = startPoint[1];
510 newChain.xn = endPoint[0];
511 newChain.yn = endPoint[1];
516 template <typename TInteger>
518 typename DGtal::FreemanChain<TInteger>
519 DGtal::FreemanChain<TInteger>::operator+(const Self& aOther) const
522 newChain.chain = chain + aOther.chain;
525 Point newLastPoint = lastPoint() + ( aOther.lastPoint() - aOther.firstPoint() );
526 newChain.xn = newLastPoint[0];
527 newChain.yn = newLastPoint[1];
532 template <typename TInteger>
534 typename DGtal::FreemanChain<TInteger>&
535 DGtal::FreemanChain<TInteger>::operator+=(const Self& aOther)
537 chain += aOther.chain;
538 Point newLastPoint = lastPoint() + ( aOther.lastPoint() - aOther.firstPoint() );
539 xn = newLastPoint[0];
540 yn = newLastPoint[1];
545 template <typename TInteger>
547 typename DGtal::FreemanChain<TInteger>::Point
548 DGtal::FreemanChain<TInteger>::getPoint(Index aPos) const
551 Size n = this->size();
552 if ( aPos < n / 2 ) {
554 for (unsigned int i=0; i<aPos; ++i)
562 for (unsigned int i=0; i<n; ++i) {
571 template <typename TInteger>
573 typename DGtal::FreemanChain<TInteger> &
574 DGtal::FreemanChain<TInteger>::extend(char aCode)
576 chain += std::string( &aCode, 1);
578 //displacement( dx, dy, aCode - '0' );
579 displacement( dx, dy, aCode );
589 template <typename TInteger>
591 typename DGtal::FreemanChain<TInteger> &
592 DGtal::FreemanChain<TInteger>::retract(Size n)
594 ConstIterator it = end();
595 for (unsigned int i=0; i<=n; ++i)
599 Size mySize = size();
600 ASSERT( (n <= mySize) && "Tried to shorten a FreemanChain by more then its length");
601 chain.resize( mySize - n );
608 // ----------------------- Interface --------------------------------------
611 template <typename TInteger>
613 void DGtal::FreemanChain<TInteger>::selfDisplay ( std::ostream & out ) const
615 out << x0 << " " << y0 << " " << chain;
620 * Checks the validity/consistency of the object.
621 * @return 'true' if the object is valid, 'false' otherwise.
623 template <typename TInteger>
625 bool DGtal::FreemanChain<TInteger>::isValid () const
638 ///////////////////////////////////////////////////////////////////////////////
642 template <typename TInteger>
644 void DGtal::FreemanChain<TInteger>::read( std::istream & in, FreemanChain & c )
652 if ( ( str.size() > 0 ) && ( str[ 0 ] != '#' ) )
654 std::istringstream str_in( str );
655 str_in >> c.x0 >> c.y0 >> c.chain;
661 template <typename TInteger>
662 template <typename TConstIterator>
664 void DGtal::FreemanChain<TInteger>::readFromPointsRange( const TConstIterator& itBegin, const TConstIterator& itEnd, FreemanChain & c )
666 TConstIterator it( itBegin );
669 { //if the range is not empty
670 Point startingPt( *it );
674 { //if there is more than one element
675 std::ostringstream oss;
676 Point pt( startingPt );
681 Integer dx = ptSuiv[0] - pt[0];
682 Integer dy = ptSuiv[1] - pt[1];
683 short number = freemanCode4C(dx, dy);
684 if ( (number < 0) || (number > 3) )
686 std::cerr << "not connected points (method readFromPointsRange of FreemanChain)" << std::endl;
687 throw ConnectivityException();
693 } while ( it != itEnd );
706 template <typename TInteger>
707 template <typename TRange>
709 void DGtal::FreemanChain<TInteger>::readFromPointsRange( const TRange& aRange, FreemanChain & c )
711 BOOST_CONCEPT_ASSERT(( concepts::CConstSinglePassRange<TRange> ));
712 readFromPointsRange( aRange.begin(), aRange.end(), c );
715 template <typename TInteger>
717 void DGtal::FreemanChain<TInteger>::getContourPoints(
718 const FreemanChain & fc, std::vector<Point> & aVContour)
721 for ( ConstIterator it = fc.begin();
725 aVContour.push_back(*it);
729 template <typename TInteger>
731 void DGtal::FreemanChain<TInteger>::getInterPixelLinels(const KhalimskySpaceND<2, TInteger> &aKSpace,
732 const FreemanChain & fc,
733 typename KhalimskySpaceND<2, TInteger>::SCellSet &aSCellContour,
734 bool aFlagForAppend){
736 aSCellContour.clear();
739 for ( ConstIterator it = fc.begin();
743 // By convention the FreemanChain in InterGrid mode is shifted by a (-0.5, 0.5) vector.
744 Point pt ((*it)[0]*2, ((*it)[1]+1)*2);
745 KhalimskySpaceND<2, int>::SCell linel;
746 switch ( fc.code(pos%fc.size()) )
749 linel = aKSpace.sCell(pt+Point(1,0), false);
752 linel = aKSpace.sCell(pt+Point(0,1), false);
755 linel = aKSpace.sCell(pt+Point(-1,0), true);
758 linel = aKSpace.sCell(pt+Point(0,-1), true);
762 aSCellContour.insert(linel);
770 template <typename TInteger>
772 DGtal::FreemanChain<TInteger>::movePointFromFC(Point & aPoint, char aCode ){
775 case '0': aPoint[0]++; break;
776 case '1': aPoint[1]++; break;
777 case '2': aPoint[0]--; break;
778 case '3': aPoint[1]--; break;
784 //template <typename TInteger>
786 //DGtal::FreemanChain<TInteger>::alphabet( char & aZero, char & aOne, char aQuadrant )
788 // switch ( aQuadrant )
812 template <typename TInteger>
814 char DGtal::FreemanChain<TInteger>::movement( char aCode1,
815 char aCode2, bool ccw )
817 unsigned int cfg = ( ccw ? 0 : 16 ) + ( (aCode1 - '0') << 2 ) + (aCode2 - '0');
818 static const char tbl[ 32 ] =
820 '2', '1', '0', '3', '3', '2', '1', '0',
821 '0', '3', '2', '1', '1', '0', '3', '2',
822 '2', '3', '0', '1', '1', '2', '3', '0',
823 '0', '1', '2', '3', '3', '0', '1', '2'
830 template <typename TInteger>
832 char DGtal::FreemanChain<TInteger>::addToCode( char code, int n)
834 return '0' + ( ( (code - '0' ) + n ) & 3 );
839 template <typename TInteger>
841 short DGtal::FreemanChain<TInteger>::freemanCode4C(int dx, int dy)
843 short number = static_cast<short>(( dx != 0 ? (1 - dx) : (2 - dy) ));
844 if ( (number < 0) || (number > 3) )
853 template <typename TInteger>
856 DGtal::FreemanChain<TInteger>::displacement( int & dx, int & dy, char aCode )
860 case '0': dx = 1; dy = 0; break;
861 case '1': dx = 0; dy = 1; break;
862 case '2': dx = -1; dy = 0; break;
863 case '3': dx = 0; dy = -1; break;
868 template <typename TInteger>
870 typename DGtal::PointVector<2,TInteger>
871 DGtal::FreemanChain<TInteger>::displacement( char aCode )
875 case '0': return Point({1,0});
876 case '1': return Point({0,1});
877 case '2': return Point({-1,0});
878 case '3': return Point({0,-1});
885 template <typename TInteger>
888 DGtal::FreemanChain<TInteger>::turnedCode( char aCode, bool ccw )
890 if ( ccw ) return ( aCode == '3' ) ? '0' : ( aCode + 1 );
891 else return ( aCode == '0' ) ? '3' : ( aCode - 1 );
893 //DGtal::FreemanChain<TInteger>::turnedCode( unsigned int aCode, bool ccw )
895 // if ( ccw ) return ( aCode + 1 ) & 0x3;
896 // else return ( aCode - 1 ) & 0x3;
905 template <typename TInteger>
906 void DGtal::FreemanChain<TInteger>::innerContour(
907 FreemanChain & aInnerChain,
908 std::vector<unsigned int> & aOuter2inner,
909 std::vector<unsigned int> & aInner2outer,
910 const FreemanChain & aOuterChain,
913 unsigned int nb = (unsigned int)aOuterChain.chain.size();
915 aOuter2inner.clear();
916 aOuter2inner.reserve( nb );
917 // aInnerChain.chain.reserve( nb + 4 );
918 aInnerChain.chain = "";
919 aInner2outer.clear();
920 aInner2outer.reserve( nb + ( ccw ? 4 : -4 ) );
923 FreemanChain<TInteger>::displacement( dx0, dy0, aOuterChain.code( 0 ) );
924 int turn = ccw ? 1 : 3;
925 //FreemanChain<TInteger>::displacement( dx1, dy1, ( aOuterChain.code( 0 ) + turn ) % 4 );
926 FreemanChain<TInteger>::displacement( dx1, dy1, addToCode( aOuterChain.code( 0 ) , turn ) );
929 aInnerChain.x0 = dx0 > 0 ? aOuterChain.x0 : aOuterChain.x0 - 1;
930 aInnerChain.y0 = dy0 > 0 ? aOuterChain.y0 : aOuterChain.y0 - 1;
932 ConstIterator it_begin = aOuterChain.begin();
933 ConstIterator it = it_begin;
935 for ( unsigned int i = 0; i < nb; ++i )
937 // Check if contour is open.
938 // cerr << "i=" << i << " code=" << aOuterChain.code( i ) << endl;
939 switch ( movement( aOuterChain.code( i ), aOuterChain.code( ( i + 1 ) % nb ), ccw ) )
942 // contour going in then out.
943 aInnerChain.chain += aOuterChain.chain[ i ];
944 //aInnerChain.chain += ( ( ( (unsigned int) ( aOuterChain.chain[ i ] - '0' )
945 // + ( ccw ? 3 : 1 ) ) )
947 aInnerChain.chain += addToCode ( aOuterChain.chain[ i ], (ccw) ? 3 : 1 );
948 aInnerChain.chain += aOuterChain.chain[ ( i + 1 ) % nb ];
949 aOuter2inner.push_back( j );
950 aInner2outer.push_back( i );
951 aInner2outer.push_back( i + 1 );
952 aInner2outer.push_back( i + 1 );
957 // contour turning toward its inside.
958 aOuter2inner.push_back( j );
962 // contour going straight ahead
963 aInnerChain.chain += aOuterChain.chain[ i ];
964 aOuter2inner.push_back( j );
965 aInner2outer.push_back( i );
970 // contour turning toward its outside.
971 aInnerChain.chain += aOuterChain.chain[ i ];
972 aInnerChain.chain += aOuterChain.chain[ ( i + 1 ) % nb ];
973 aOuter2inner.push_back( j );
974 aInner2outer.push_back( i );
975 aInner2outer.push_back( i + 1 );
980 // Advances along contour and check if it is a closed contour.
983 && ( *it_begin != *it ) )
984 // freeman chain is *not* a closed loop.
986 aInnerChain.chain += aOuterChain.chain[ i ];
987 aOuter2inner.push_back( j );
988 aInner2outer.push_back( i );
999 template <typename TInteger>
1000 bool DGtal::FreemanChain<TInteger>::cleanOuterSpikes(
1001 FreemanChain & aCleanC,
1002 std::vector<unsigned int> & aC2clean,
1003 std::vector<unsigned int> & aClean2c,
1004 const FreemanChain & c,
1007 unsigned int nb = (unsigned int)c.chain.size();
1010 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1011 << " cleanOuterSpikes: Empty input chain"
1016 ModuloComputer< DGtal::int32_t > mc( nb );
1017 ModuloComputer< DGtal::int32_t >::UnsignedInteger i = 0;
1018 ModuloComputer< DGtal::int32_t >::UnsignedInteger j = 0;
1019 std::vector<unsigned int> c2cleanTMP;
1020 aCleanC.chain.reserve( nb );
1024 aC2clean.reserve( nb );
1025 aClean2c.reserve( nb );
1026 c2cleanTMP.reserve( nb );
1027 ConstIterator it = c.begin();
1028 ConstIterator itn = c.begin();
1030 // Find a consistent starting point.
1032 unsigned int size_spike = 0;
1033 for ( n = 0; n < nb; ++n )
1036 while ( movement( it.getCode(), itn.getCode(), ccw ) == '0' )
1038 it.previousInLoop();
1042 if ( size_spike >= nb )
1044 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1045 << " Spike is longer than contour !"
1046 << " size_spike=" << size_spike
1055 if ( size_spike > 0 )
1058 unsigned int start_idx = it.position();
1060 // JOL : 2009/07/07, added starting coordinates
1061 // XP : 2011/09/06, added ending coordinates
1068 // cerr << "Starting point is " << i << endl;
1069 ASSERT( ( n < nb ) || ( i == 0 ) );
1072 aCleanC.chain = c.chain;
1073 for ( unsigned int ni = 0; ni < nb; ++ni )
1075 aC2clean.push_back( ni );
1076 aClean2c.push_back( ni );
1078 if ( size_spike != 0 )
1079 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1080 << "No starting point found (only spikes !)" << std::endl;
1082 return size_spike == 0;
1084 // Loops over all letters.
1085 ConstIterator it_begin = it;
1086 std::deque<unsigned int> clean_code;
1087 std::deque<unsigned int> clean_idx;
1088 std::vector<unsigned int> begin_outer_spike;
1089 std::vector<unsigned int> end_outer_spike;
1090 // i follows iterator it.
1093 clean_code.push_back( it.getCode() );
1094 clean_idx.push_back( i );
1098 // cerr << "- i=" << i << " (" << clean_code.back()
1099 // << it.getCode() << ") ";
1101 unsigned int last_spike_idx = end_outer_spike.empty() ?
1103 end_outer_spike.back();
1105 while ( ( ! clean_code.empty() )
1106 && ( j != last_spike_idx )
1107 && ( movement( clean_code.back(), it.getCode(), ccw ) == '0' )
1108 && ( it != it_begin ) )
1110 clean_code.pop_back();
1111 clean_idx.pop_back();
1115 itn.previousInLoop();
1118 // cerr << "i=" << i << " size_spike=" << size_spike
1119 // << " last_spike_idx=" << last_spike_idx
1121 if ( size_spike != 0 )
1123 // There is a spike. Is it an outer one ?
1124 unsigned int previous_code = itn.getCode();
1125 unsigned int previous_idx = itn.position();
1127 // consider any more "cleaned contour" since we cannot go
1128 // further than the last spike.
1129 // unsigned int previous_code =
1130 // clean_code.empty() ? itn.getCode() : clean_code.back();
1131 // unsigned int previous_idx =
1132 // clean_code.empty() ? itn.position() : clean_idx.back();
1134 itn.previousInLoop();
1135 unsigned int move1 = movement( previous_code, addToCode ( itn.getCode() , 2 ), ccw );
1136 unsigned int move2 = movement( itn.getCode(), it.getCode() , ccw );
1137 bool return_spike = ( move1 == '0' ) || ( move2 == '0' );
1138 bool outer_spike = ( move1 == '3' ) || ( move2 == '3' );
1139 // if ( return_spike )
1140 // cerr << "[DGtal::FreemanChain::cleanOuterSpikes] return spike."
1142 // if ( ! ( ( outer_spike && ( move1 != 1 ) && ( move2 != 1 ) )
1143 // || ( ! outer_spike && ( move1 != 3 ) && ( move2 != 3 ) ) ) )
1144 // cerr << "[DGtal::FreemanChain::cleanOuterSpikes] "
1145 // << "Weird spike. Invalid contour (expected 3 3) ?"
1146 // << " move1=" << move1
1147 // << " move2=" << move2
1148 // << " ccw=" << ccw
1149 // << " start_idx=" << start_idx
1150 // << " size_spike=" << size_spike
1151 // << " it=" << it.position()
1152 // << " itp=" << previous_idx
1154 // << c.chain << endl;
1155 // Process waiting steps.
1156 if ( outer_spike || return_spike )
1158 begin_outer_spike.push_back( mc.next( previous_idx ) );
1159 end_outer_spike.push_back( i );
1160 // cout << " outer spike [" << begin_outer_spike.back()
1161 // << "," << end_outer_spike.back() << "[ " << endl;
1165 while ( it != it_begin );
1167 // Once outer spikes are known, we can create the new contour.
1168 aC2clean.resize( nb );
1171 unsigned int nb_spikes = (unsigned int)begin_outer_spike.size();
1176 if ( ( k == nb_spikes ) || ( i != begin_outer_spike[ k ] ) )
1178 aCleanC.chain.push_back( c.chain[ i ] );
1180 aClean2c.push_back( i );
1187 while ( i != end_outer_spike[ k ] )
1196 for ( unsigned int ii = 0; ii < nb; ++ii )
1197 if ( aC2clean[ ii ] >= aCleanC.chain.size() )
1199 if ( aC2clean[ ii ] == aCleanC.chain.size() )
1203 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1204 << "Bad correspondence for aC2clean[" << ii << "]"
1205 << " = " << aC2clean[ ii ] << " >= " << aCleanC.chain.size()
1207 aC2clean[ ii ] = aC2clean[ ii ] % aCleanC.chain.size();
1211 for ( unsigned int jj = 0; j < aCleanC.chain.size(); ++jj )
1212 if ( aClean2c[ jj ] >= nb )
1214 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1215 << "Bad correspondence for aClean2c[" << jj << "]"
1216 << " = " << aClean2c[ jj ] << " >= " << nb
1218 aClean2c[ jj ] = aClean2c[ jj ] % nb;
1223 ///////////////////////////////////////////////////////////////////////////////
1226 template <typename TInteger>
1229 DGtal::FreemanChain<TInteger>::className() const
1231 return "FreemanChain";
1234 template <typename TInteger>
1237 DGtal::FreemanChain<TInteger>::computeLastPoint()
1239 ConstIterator it = this->begin();
1240 for (unsigned int i=0; i < chain.size(); ++i)
1251 ///////////////////////////////////////////////////////////////////////////////
1252 // Implementation of inline functions and external operators //
1255 * Overloads 'operator<<' for displaying objects of class 'FreemanChain'.
1256 * @param out the output stream where the object is written.
1257 * @param aObject the object of class 'FreemanChain' to write.
1258 * @return the output stream after the writing.
1260 template <typename TInteger>
1263 DGtal::operator<< ( std::ostream & out,
1264 const FreemanChain<TInteger> & aObject )
1266 aObject.selfDisplay ( out );
1271 ///////////////////////////////////////////////////////////////////////////////