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///////////////////////////////////////////////////////////////////////////////
48template <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'.
73template <typename TInteger>
75typename DGtal::FreemanChain<TInteger>::ConstIterator &
76DGtal::FreemanChain<TInteger>::ConstIterator::operator= ( const ConstIterator & other )
88template <typename TInteger>
90void 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;
108template <typename TInteger>
110void 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();
126template <typename TInteger>
128void 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;
153template <typename TInteger>
155void 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.
181template <typename TInteger>
182DGtal::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();
192template <typename TInteger>
193DGtal::FreemanChain<TInteger>::
194FreemanChain( const std::vector<Point>& vectPoints )
196 readFromPointsRange(vectPoints.begin(), vectPoints.end(), *this);
203 * @param in any input stream,
205template <typename TInteger>
206DGtal::FreemanChain<TInteger>::FreemanChain(std::istream & in ){
214 * @param aOther the object to clone.
216template <typename TInteger>
217DGtal::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'.
230template <typename TInteger>
231typename DGtal::FreemanChain<TInteger> &
232DGtal::FreemanChain<TInteger>::operator=( const FreemanChain<TInteger> & aOther )
234 if ( this != &aOther )
236 chain = aOther.chain;
249///////////////////////////////////////////////////////////////////////////////
253template <typename TInteger>
254typename DGtal::FreemanChain<TInteger>::ConstIterator
255DGtal::FreemanChain<TInteger>::begin() const
257 return ConstIterator( *this, 0 );
261template <typename TInteger>
262typename DGtal::FreemanChain<TInteger>::ConstIterator
263DGtal::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.
274template <typename TInteger>
275typename DGtal::FreemanChain<TInteger>::Index
276DGtal::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.
288template <typename TInteger>
289typename DGtal::FreemanChain<TInteger>::Index
290DGtal::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].
301template <typename TInteger>
303DGtal::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.
314template <typename TInteger>
316typename DGtal::FreemanChain<TInteger>::Index
317DGtal::FreemanChain<TInteger>::size() const
319 return (typename DGtal::FreemanChain<TInteger>::Size)(chain.size());
323template <typename TInteger>
325void DGtal::FreemanChain<TInteger>::computeBoundingBox( TInteger & min_x,
326 TInteger& min_y, TInteger& max_x, TInteger& max_y ) const
330 for ( ConstIterator it = begin();
349template <typename TInteger>
351typename DGtal::FreemanChain<TInteger>::ConstIterator
352DGtal::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." );
400template <typename TInteger>
402typename DGtal::FreemanChain<TInteger>::ConstIterator
403DGtal::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." );
458template <typename TInteger>
460int DGtal::FreemanChain<TInteger>::isClosed() const
462 return (x0 == xn) && (y0 == yn);
466template <typename TInteger>
468int 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;
499template <typename TInteger>
501typename DGtal::FreemanChain<TInteger>
502DGtal::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];
516template <typename TInteger>
518typename DGtal::FreemanChain<TInteger>
519DGtal::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];
532template <typename TInteger>
534typename DGtal::FreemanChain<TInteger>&
535DGtal::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];
545template <typename TInteger>
547typename DGtal::FreemanChain<TInteger>::Point
548DGtal::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) {
571template <typename TInteger>
573typename DGtal::FreemanChain<TInteger> &
574DGtal::FreemanChain<TInteger>::extend(char aCode)
576 chain += std::string( &aCode, 1);
578 //displacement( dx, dy, aCode - '0' );
579 displacement( dx, dy, aCode );
589template <typename TInteger>
591typename DGtal::FreemanChain<TInteger> &
592DGtal::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 --------------------------------------
611template <typename TInteger>
613void 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.
623template <typename TInteger>
625bool DGtal::FreemanChain<TInteger>::isValid () const
638///////////////////////////////////////////////////////////////////////////////
642template <typename TInteger>
644void 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;
661template <typename TInteger>
662template <typename TConstIterator>
664void 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 );
706template <typename TInteger>
707template <typename TRange>
709void DGtal::FreemanChain<TInteger>::readFromPointsRange( const TRange& aRange, FreemanChain & c )
711 BOOST_CONCEPT_ASSERT(( concepts::CConstSinglePassRange<TRange> ));
712 readFromPointsRange( aRange.begin(), aRange.end(), c );
715template <typename TInteger>
717void DGtal::FreemanChain<TInteger>::getContourPoints(
718 const FreemanChain & fc, std::vector<Point> & aVContour)
721 for ( ConstIterator it = fc.begin();
725 aVContour.push_back(*it);
729template <typename TInteger>
731void 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);
770template <typename TInteger>
772DGtal::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 )
812template <typename TInteger>
814char 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'
830template <typename TInteger>
832char DGtal::FreemanChain<TInteger>::addToCode( char code, int n)
834 return '0' + ( ( (code - '0' ) + n ) & 3 );
839template <typename TInteger>
841short 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) )
853template <typename TInteger>
856DGtal::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;
868template <typename TInteger>
870typename DGtal::PointVector<2,TInteger>
871DGtal::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});
885template <typename TInteger>
888DGtal::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;
905template <typename TInteger>
906void 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 );
999template <typename TInteger>
1000bool 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///////////////////////////////////////////////////////////////////////////////
1226template <typename TInteger>
1229DGtal::FreemanChain<TInteger>::className() const
1231 return "FreemanChain";
1234template <typename TInteger>
1237DGtal::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.
1260template <typename TInteger>
1263DGtal::operator<< ( std::ostream & out,
1264 const FreemanChain<TInteger> & aObject )
1266 aObject.selfDisplay ( out );
1271///////////////////////////////////////////////////////////////////////////////