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;
782template <typename TInteger>
784char DGtal::FreemanChain<TInteger>::movement( char aCode1,
785 char aCode2, bool ccw )
787 unsigned int cfg = ( ccw ? 0 : 16 ) + ( (aCode1 - '0') << 2 ) + (aCode2 - '0');
788 static const char tbl[ 32 ] =
790 '2', '1', '0', '3', '3', '2', '1', '0',
791 '0', '3', '2', '1', '1', '0', '3', '2',
792 '2', '3', '0', '1', '1', '2', '3', '0',
793 '0', '1', '2', '3', '3', '0', '1', '2'
800template <typename TInteger>
802char DGtal::FreemanChain<TInteger>::addToCode( char code, int n)
804 return '0' + ( ( (code - '0' ) + n ) & 3 );
809template <typename TInteger>
811short DGtal::FreemanChain<TInteger>::freemanCode4C(int dx, int dy)
813 short number = static_cast<short>(( dx != 0 ? (1 - dx) : (2 - dy) ));
814 if ( (number < 0) || (number > 3) )
823template <typename TInteger>
826DGtal::FreemanChain<TInteger>::displacement( int & dx, int & dy, char aCode )
830 case '0': dx = 1; dy = 0; break;
831 case '1': dx = 0; dy = 1; break;
832 case '2': dx = -1; dy = 0; break;
833 case '3': dx = 0; dy = -1; break;
838template <typename TInteger>
840typename DGtal::PointVector<2,TInteger>
841DGtal::FreemanChain<TInteger>::displacement( char aCode )
845 case '0': return Point({1,0});
846 case '1': return Point({0,1});
847 case '2': return Point({-1,0});
848 case '3': return Point({0,-1});
855template <typename TInteger>
858DGtal::FreemanChain<TInteger>::turnedCode( char aCode, bool ccw )
860 if ( ccw ) return ( aCode == '3' ) ? '0' : ( aCode + 1 );
861 else return ( aCode == '0' ) ? '3' : ( aCode - 1 );
863//DGtal::FreemanChain<TInteger>::turnedCode( unsigned int aCode, bool ccw )
865// if ( ccw ) return ( aCode + 1 ) & 0x3;
866// else return ( aCode - 1 ) & 0x3;
875template <typename TInteger>
876void DGtal::FreemanChain<TInteger>::innerContour(
877 FreemanChain & aInnerChain,
878 std::vector<unsigned int> & aOuter2inner,
879 std::vector<unsigned int> & aInner2outer,
880 const FreemanChain & aOuterChain,
883 unsigned int nb = (unsigned int)aOuterChain.chain.size();
885 aOuter2inner.clear();
886 aOuter2inner.reserve( nb );
887 // aInnerChain.chain.reserve( nb + 4 );
888 aInnerChain.chain = "";
889 aInner2outer.clear();
890 aInner2outer.reserve( nb + ( ccw ? 4 : -4 ) );
893 FreemanChain<TInteger>::displacement( dx0, dy0, aOuterChain.code( 0 ) );
894 int turn = ccw ? 1 : 3;
895 //FreemanChain<TInteger>::displacement( dx1, dy1, ( aOuterChain.code( 0 ) + turn ) % 4 );
896 FreemanChain<TInteger>::displacement( dx1, dy1, addToCode( aOuterChain.code( 0 ) , turn ) );
899 aInnerChain.x0 = dx0 > 0 ? aOuterChain.x0 : aOuterChain.x0 - 1;
900 aInnerChain.y0 = dy0 > 0 ? aOuterChain.y0 : aOuterChain.y0 - 1;
902 ConstIterator it_begin = aOuterChain.begin();
903 ConstIterator it = it_begin;
905 for ( unsigned int i = 0; i < nb; ++i )
907 // Check if contour is open.
908 // cerr << "i=" << i << " code=" << aOuterChain.code( i ) << endl;
909 switch ( movement( aOuterChain.code( i ), aOuterChain.code( ( i + 1 ) % nb ), ccw ) )
912 // contour going in then out.
913 aInnerChain.chain += aOuterChain.chain[ i ];
914 //aInnerChain.chain += ( ( ( (unsigned int) ( aOuterChain.chain[ i ] - '0' )
915 // + ( ccw ? 3 : 1 ) ) )
917 aInnerChain.chain += addToCode ( aOuterChain.chain[ i ], (ccw) ? 3 : 1 );
918 aInnerChain.chain += aOuterChain.chain[ ( i + 1 ) % nb ];
919 aOuter2inner.push_back( j );
920 aInner2outer.push_back( i );
921 aInner2outer.push_back( i + 1 );
922 aInner2outer.push_back( i + 1 );
927 // contour turning toward its inside.
928 aOuter2inner.push_back( j );
932 // contour going straight ahead
933 aInnerChain.chain += aOuterChain.chain[ i ];
934 aOuter2inner.push_back( j );
935 aInner2outer.push_back( i );
940 // contour turning toward its outside.
941 aInnerChain.chain += aOuterChain.chain[ i ];
942 aInnerChain.chain += aOuterChain.chain[ ( i + 1 ) % nb ];
943 aOuter2inner.push_back( j );
944 aInner2outer.push_back( i );
945 aInner2outer.push_back( i + 1 );
950 // Advances along contour and check if it is a closed contour.
953 && ( *it_begin != *it ) )
954 // freeman chain is *not* a closed loop.
956 aInnerChain.chain += aOuterChain.chain[ i ];
957 aOuter2inner.push_back( j );
958 aInner2outer.push_back( i );
969template <typename TInteger>
970bool DGtal::FreemanChain<TInteger>::cleanOuterSpikes(
971 FreemanChain & aCleanC,
972 std::vector<unsigned int> & aC2clean,
973 std::vector<unsigned int> & aClean2c,
974 const FreemanChain & c,
977 unsigned int nb = (unsigned int)c.chain.size();
980 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
981 << " cleanOuterSpikes: Empty input chain"
986 ModuloComputer< DGtal::int32_t > mc( nb );
987 ModuloComputer< DGtal::int32_t >::UnsignedInteger i = 0;
988 ModuloComputer< DGtal::int32_t >::UnsignedInteger j = 0;
989 std::vector<unsigned int> c2cleanTMP;
990 aCleanC.chain.reserve( nb );
994 aC2clean.reserve( nb );
995 aClean2c.reserve( nb );
996 c2cleanTMP.reserve( nb );
997 ConstIterator it = c.begin();
998 ConstIterator itn = c.begin();
1000 // Find a consistent starting point.
1002 unsigned int size_spike = 0;
1003 for ( n = 0; n < nb; ++n )
1006 while ( movement( it.getCode(), itn.getCode(), ccw ) == '0' )
1008 it.previousInLoop();
1012 if ( size_spike >= nb )
1014 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1015 << " Spike is longer than contour !"
1016 << " size_spike=" << size_spike
1025 if ( size_spike > 0 )
1028 unsigned int start_idx = it.position();
1030 // JOL : 2009/07/07, added starting coordinates
1031 // XP : 2011/09/06, added ending coordinates
1038 // cerr << "Starting point is " << i << endl;
1039 ASSERT( ( n < nb ) || ( i == 0 ) );
1042 aCleanC.chain = c.chain;
1043 for ( unsigned int ni = 0; ni < nb; ++ni )
1045 aC2clean.push_back( ni );
1046 aClean2c.push_back( ni );
1048 if ( size_spike != 0 )
1049 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1050 << "No starting point found (only spikes !)" << std::endl;
1052 return size_spike == 0;
1054 // Loops over all letters.
1055 ConstIterator it_begin = it;
1056 std::deque<unsigned int> clean_code;
1057 std::deque<unsigned int> clean_idx;
1058 std::vector<unsigned int> begin_outer_spike;
1059 std::vector<unsigned int> end_outer_spike;
1060 // i follows iterator it.
1063 clean_code.push_back( it.getCode() );
1064 clean_idx.push_back( i );
1068 // cerr << "- i=" << i << " (" << clean_code.back()
1069 // << it.getCode() << ") ";
1071 unsigned int last_spike_idx = end_outer_spike.empty() ?
1073 end_outer_spike.back();
1075 while ( ( ! clean_code.empty() )
1076 && ( j != last_spike_idx )
1077 && ( movement( clean_code.back(), it.getCode(), ccw ) == '0' )
1078 && ( it != it_begin ) )
1080 clean_code.pop_back();
1081 clean_idx.pop_back();
1085 itn.previousInLoop();
1088 // cerr << "i=" << i << " size_spike=" << size_spike
1089 // << " last_spike_idx=" << last_spike_idx
1091 if ( size_spike != 0 )
1093 // There is a spike. Is it an outer one ?
1094 unsigned int previous_code = itn.getCode();
1095 unsigned int previous_idx = itn.position();
1097 // consider any more "cleaned contour" since we cannot go
1098 // further than the last spike.
1099 // unsigned int previous_code =
1100 // clean_code.empty() ? itn.getCode() : clean_code.back();
1101 // unsigned int previous_idx =
1102 // clean_code.empty() ? itn.position() : clean_idx.back();
1104 itn.previousInLoop();
1105 unsigned int move1 = movement( previous_code, addToCode ( itn.getCode() , 2 ), ccw );
1106 unsigned int move2 = movement( itn.getCode(), it.getCode() , ccw );
1107 bool return_spike = ( move1 == '0' ) || ( move2 == '0' );
1108 bool outer_spike = ( move1 == '3' ) || ( move2 == '3' );
1109 // if ( return_spike )
1110 // cerr << "[DGtal::FreemanChain::cleanOuterSpikes] return spike."
1112 // if ( ! ( ( outer_spike && ( move1 != 1 ) && ( move2 != 1 ) )
1113 // || ( ! outer_spike && ( move1 != 3 ) && ( move2 != 3 ) ) ) )
1114 // cerr << "[DGtal::FreemanChain::cleanOuterSpikes] "
1115 // << "Weird spike. Invalid contour (expected 3 3) ?"
1116 // << " move1=" << move1
1117 // << " move2=" << move2
1118 // << " ccw=" << ccw
1119 // << " start_idx=" << start_idx
1120 // << " size_spike=" << size_spike
1121 // << " it=" << it.position()
1122 // << " itp=" << previous_idx
1124 // << c.chain << endl;
1125 // Process waiting steps.
1126 if ( outer_spike || return_spike )
1128 begin_outer_spike.push_back( mc.next( previous_idx ) );
1129 end_outer_spike.push_back( i );
1130 // cout << " outer spike [" << begin_outer_spike.back()
1131 // << "," << end_outer_spike.back() << "[ " << endl;
1135 while ( it != it_begin );
1137 // Once outer spikes are known, we can create the new contour.
1138 aC2clean.resize( nb );
1141 unsigned int nb_spikes = (unsigned int)begin_outer_spike.size();
1146 if ( ( k == nb_spikes ) || ( i != begin_outer_spike[ k ] ) )
1148 aCleanC.chain.push_back( c.chain[ i ] );
1150 aClean2c.push_back( i );
1157 while ( i != end_outer_spike[ k ] )
1166 for ( unsigned int ii = 0; ii < nb; ++ii )
1167 if ( aC2clean[ ii ] >= aCleanC.chain.size() )
1169 if ( aC2clean[ ii ] == aCleanC.chain.size() )
1173 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1174 << "Bad correspondence for aC2clean[" << ii << "]"
1175 << " = " << aC2clean[ ii ] << " >= " << aCleanC.chain.size()
1177 aC2clean[ ii ] = aC2clean[ ii ] % aCleanC.chain.size();
1181 for ( unsigned int jj = 0; j < aCleanC.chain.size(); ++jj )
1182 if ( aClean2c[ jj ] >= nb )
1184 std::cerr << "[DGtal::FreemanChain::cleanOuterSpikes]"
1185 << "Bad correspondence for aClean2c[" << jj << "]"
1186 << " = " << aClean2c[ jj ] << " >= " << nb
1188 aClean2c[ jj ] = aClean2c[ jj ] % nb;
1193///////////////////////////////////////////////////////////////////////////////
1196template <typename TInteger>
1199DGtal::FreemanChain<TInteger>::className() const
1201 return "FreemanChain";
1204template <typename TInteger>
1207DGtal::FreemanChain<TInteger>::computeLastPoint()
1209 ConstIterator it = this->begin();
1210 for (unsigned int i=0; i < chain.size(); ++i)
1221///////////////////////////////////////////////////////////////////////////////
1222// Implementation of inline functions and external operators //
1225 * Overloads 'operator<<' for displaying objects of class 'FreemanChain'.
1226 * @param out the output stream where the object is written.
1227 * @param aObject the object of class 'FreemanChain' to write.
1228 * @return the output stream after the writing.
1230template <typename TInteger>
1233DGtal::operator<< ( std::ostream & out,
1234 const FreemanChain<TInteger> & aObject )
1236 aObject.selfDisplay ( out );
1241///////////////////////////////////////////////////////////////////////////////