00001 
00010 #include "v4r_utils/contour.h"
00011 #include <iostream>
00012 #include <stack>
00013 #include <cstdio>
00014 #include "opencv/highgui.h"
00015 
00016 namespace V4R {
00017 
00018 const int Contour::ANGLE_8U = 8;
00019 const int Contour::ANGLE_32F = 32;
00020 const int Contour::ANGLE_64F = 64;
00021 
00022 
00023 const int Contour::MODE_SIMPLE = 1;
00024 const int Contour::MODE_CONTOUR = 2;
00025 const int Contour::MODE_GRAIDENT = 3;
00026 const int Contour::MODE_COMPLEX = 4;
00027 
00028 const float Contour::fPi  = 3.1415926535897932384626433832795;
00029 const double Contour::dPi = 3.1415926535897932384626433832795;
00030 
00031 const int Contour::pppDirectionWeightsField[4][3][3] = {
00032     {   {2,1,2}, 
00033         {4,0,4}, 
00034         {2,1,2}  
00035     },
00036     {   {1,2,4}, 
00037         {2,0,2}, 
00038         {4,2,1}  
00039     },
00040     {   {2,4,2}, 
00041         {1,0,1}, 
00042         {2,4,4}  
00043     },
00044     {   {4,2,1}, 
00045         {2,0,2}, 
00046         {1,2,4}  
00047     }
00048 };
00049 
00050 const int Contour::ppGradientWeightsField[4][9] = {
00051     {3, 5, 6, 8, 2, 0, 7, 1, 4},
00052     {2, 6, 1, 3, 7, 5, 0, 8, 4},
00053     {1, 7, 0, 6, 8, 2, 3, 5, 4},
00054     {0, 8, 1, 7, 5, 3, 2, 6, 4}
00055 };
00056 
00057 const int Contour::pppCommingFromEdgeWeightsField[9][3][3] = {
00058     {   {0,1,2}, 
00059         {1,0,3}, 
00060         {2,3,4}  
00061     },
00062     {   {1,0,1}, 
00063         {2,0,2}, 
00064         {3,4,3}  
00065     },
00066     {   {2,1,0}, 
00067         {3,0,1}, 
00068         {4,3,2}  
00069     },
00070     {   {1,2,3}, 
00071         {0,0,4}, 
00072         {1,2,3}  
00073     },
00074     {   {0,0,0}, 
00075         {0,0,0}, 
00076         {0,0,0}  
00077     },
00078     {   {3,2,1}, 
00079         {4,0,0}, 
00080         {3,2,1}  
00081     },
00082     {   {2,3,4}, 
00083         {1,0,3}, 
00084         {0,1,2}  
00085     },
00086     {   {3,4,3}, 
00087         {2,0,2}, 
00088         {1,0,1}  
00089     },
00090     {   {4,3,2}, 
00091         {3,0,1}, 
00092         {2,1,0}  
00093     }
00094 };
00095 
00096 const int Contour::ppContourWeightsField[9][9] = {
00097     {8, 7, 5, 6, 2, 3, 1, 0, 4},
00098     {7, 6, 8, 3, 5, 0, 2, 1, 4},
00099     {6, 7, 3, 8, 0, 5, 1, 2, 4},
00100     {5, 2, 8, 1, 7, 0, 6, 3, 4},
00101     {0, 0, 0, 0, 0, 0, 0, 0, 0},
00102     {3, 6, 0, 7, 1, 8, 2, 5, 4},
00103     {2, 1, 5, 0, 8, 3, 7, 6, 4},
00104     {1, 2, 0, 3, 5, 6, 8, 7, 4},
00105     {0, 1, 3, 2, 6, 5, 7, 8, 4}
00106 };
00107 
00108 Contour::Contour() :
00109     mpImgEdge ( NULL ),
00110     mpImgEdgeDirection ( NULL ),
00111     mdImgEdgeDirectionType ( 0 ),
00112     mdefEdgeLinkMode ( 0 ),
00113     mImgWidth ( 0 ),
00114     mImgHeight ( 0 ),
00115     mbAllowToModifyTheSources ( false ),
00116 
00117     mNrOfEdges ( 0 ) {}
00118 
00119 Contour::~Contour() {
00120     Contour::RelaseMemory();
00121 }
00122 
00123 void Contour::AllocateMemory() {
00124     RelaseMemory();
00125     if ( mbAllowToModifyTheSources == false ) {
00126         mpImgEdge = ( unsigned char* ) malloc ( sizeof ( unsigned char ) * mImgWidth * mImgHeight );
00127     }
00128     
00129     mEdges.resize ( mImgWidth * mImgHeight );
00130     mAngle8Bit.resize ( mImgWidth * mImgHeight );
00131 }
00132 
00133 void Contour::RelaseMemory() {
00134     if ( mbAllowToModifyTheSources ) {
00135         if ( mpImgEdge != NULL ) {
00136             free ( mpImgEdge );
00137             mpImgEdge = NULL;
00138         }
00139         
00140 
00141 
00142 
00143 
00144 
00145     }
00146 }
00147 
00148 int Contour::getContours( std::vector<std::vector<cv::Point> > &contours, unsigned int min_length) {
00149     contours.clear();
00150     std::vector<cv::Range> idx = getSegmentIndexes () ;
00151     for ( unsigned int i = 0; i < idx.size(); i++ ) {
00152         int length = idx[i].end - idx[i].start;
00153         if (length > min_length) {
00154             contours.push_back(std::vector<cv::Point>());
00155             for ( int index = idx[i].start; index < idx[i].end; index++ ) {
00156               CvPoint &edge = (mEdges)[index];
00157                 contours.back().push_back( edge);
00158             }
00159         }
00160     }
00161     return contours.size();
00162 }
00163 
00164 void Contour::Draw( unsigned char* pImgRGB ) {
00165     unsigned char *pDes;
00166     std::vector<cv::Range> idx = getSegmentIndexes () ;
00167     for ( unsigned int i = 0; i < idx.size(); i++ ) {
00168         unsigned char pColor[] = {rand() / ( RAND_MAX/0xFF ), rand() / ( RAND_MAX/0xFF ), rand() / ( RAND_MAX/0xFF ) };
00169         for ( int index = idx[i].start; index < idx[i].end; index++ ) {
00170             CvPoint edge = (mEdges)[index];
00171             pDes = pImgRGB + ( 3 * ( mImgWidth * edge.y + edge.x ) );
00172             for ( int j  = 0; j < 3; j++ ) {
00173                 pDes[j] = pColor[j];
00174             }
00175         }
00176     }
00177 }
00178 
00179 void Contour::Init ( unsigned int iImgWidth, unsigned int iImgHeight, bool bAllowToModifyTheSources, unsigned char iEdgeToProcess, unsigned char iEdgeInProcess, unsigned char iEdgeProcessed, unsigned char iEdgeStrengthRemoved ) {
00180     if((iImgWidth != mImgWidth) || (mImgHeight != iImgHeight)  ||
00181             (mbAllowToModifyTheSources != bAllowToModifyTheSources) || (mEdgeToProcess != iEdgeToProcess) ||
00182             (mEdgeInProcess != iEdgeInProcess) || (mEdgeProcessed != iEdgeProcessed)) {
00183         RelaseMemory();
00184         mImgWidth = iImgWidth;
00185         mImgHeight = iImgHeight;
00186         mbAllowToModifyTheSources = bAllowToModifyTheSources;
00187         mEdgeToProcess = iEdgeToProcess;
00188         mEdgeInProcess = iEdgeInProcess;
00189         mEdgeProcessed = iEdgeProcessed;
00190         AllocateMemory();
00191     }
00192 }
00193 
00194 int Contour::GetImgDirectionIndex ( CvPoint tPoint ) {
00195     
00196 
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204     int iIndex = 0;
00205     unsigned char i8BitAngle;
00206     float fAngle;
00207     double dAngle;
00208     switch ( mdImgEdgeDirectionType ) {
00209     case ANGLE_8U:
00210         i8BitAngle = ( ( unsigned char* ) mpImgEdgeDirection ) [tPoint.y*mImgWidth + tPoint.x];
00211         if ( i8BitAngle > 128 ) {
00212             i8BitAngle -= 128;
00213         }
00214         i8BitAngle = i8BitAngle + 16;
00215         iIndex = i8BitAngle / 32;
00216         break;
00217     case ANGLE_32F:
00218         fAngle = ( ( float* ) mpImgEdgeDirection ) [tPoint.y*mImgWidth + tPoint.x];
00219         if ( fAngle < 0 ) {
00220             fAngle += fPi;
00221         }
00222         iIndex = ( int ) ( ( fAngle + fPi/8 ) * 3/fPi );
00223         break;
00224     case ANGLE_64F:
00225         dAngle = ( ( double* ) mpImgEdgeDirection ) [tPoint.y*mImgWidth + tPoint.x];
00226 
00227         if ( dAngle < 0 ) {
00228             dAngle += dPi;
00229         }
00230         iIndex = ( int ) ( ( dAngle + dPi/8 ) * 3/dPi );
00231         break;
00232     }
00233     return iIndex;
00234 }
00235 
00236 void Contour::Perform ( unsigned char* pImgEdgeStrength, int defEdgeLinkMode, void* pImgEdgeDirection, int dImgEdgeDirectionType ) {
00237     mNrOfEdges = 0;
00238     mSegments.clear();
00239     mSegments.reserve ( 100 );
00240     mdefEdgeLinkMode = defEdgeLinkMode;
00241     mpImgEdgeDirection = pImgEdgeDirection;
00242     mdImgEdgeDirectionType = dImgEdgeDirectionType;
00243     if ( mbAllowToModifyTheSources ) {
00244         mpImgEdge = pImgEdgeStrength;
00245     } else {
00246         memcpy ( mpImgEdge, pImgEdgeStrength, mImgWidth * mImgHeight );
00247     }
00248 
00249     switch ( mdefEdgeLinkMode ) {
00250     case MODE_SIMPLE:
00251         Linking_Simple();
00252         break;
00253     case MODE_CONTOUR:
00254         Linking_Contour();
00255         break;
00256     case MODE_GRAIDENT:
00257         if ( pImgEdgeDirection == NULL ) {
00258             printf ( "The linker mode requires an edge direction image!\n" );
00259         }
00260         Linking_Gradient();
00261         break;
00262     case MODE_COMPLEX:
00263         if ( pImgEdgeDirection == NULL ) {
00264             printf ( "The linker mode requires an edge direction image!\n" );
00265         }
00266         Linking_Complex();
00267         break;
00268     }
00269 }
00270 
00271 
00272 void Contour::Linking_Simple() {
00273     CvPoint tPoint = {0,0};
00274     cv::Range range(0,0);
00275     for ( tPoint.y = 1; tPoint.y < mImgHeight-1; tPoint.y++ ) {
00276         tPoint.x = 1;
00277         unsigned char *pCurrent = getImgEdge ( tPoint );
00278         for ( ; tPoint.x < mImgWidth-1; tPoint.x++ ) {
00279             if ( *pCurrent >= mEdgeToProcess ) {
00280                 range.start = mNrOfEdges;
00281                 Trace_Simple ( tPoint, &range.end );
00282                 mSegments.push_back ( range );
00283                 
00284             }
00285             pCurrent++;
00286         }
00287     }
00288 }
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00300 
00301 
00302 
00303 
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 void Contour::Trace_Simple ( CvPoint tPoint, int *pEnd ) {
00325     
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335     if (isInImage(tPoint)) {
00336         unsigned char *pPix = getImgEdge ( tPoint );
00337         CvPoint tCurrent = tPoint;
00338         bool bEnd = false;
00339         bool bStart = false;
00340         std::stack<CvPoint> trace_to_start;
00341         std::stack<CvPoint> trace_to_end;
00342         std::stack<CvPoint> *pEdgeStack = &trace_to_start;
00343         while (bEnd == false) {
00344             
00345 
00346 
00347 
00348 
00349 
00350             *pPix = mEdgeProcessed;
00351             pEdgeStack->push(tCurrent);
00352             if (pPix[-mImgWidth-1] >= mEdgeToProcess) {
00353                 pPix = pPix-mImgWidth-1;
00354                 tCurrent.x--, tCurrent.y--;
00355             } else if (pPix[-mImgWidth] >= mEdgeToProcess) {
00356                 pPix = pPix-mImgWidth;
00357                 tCurrent.y--;
00358             } else if ( pPix[-mImgWidth+1] >= mEdgeToProcess) {
00359                 pPix = pPix-mImgWidth+1;
00360                 tCurrent.x++, tCurrent.y--;
00361             } else if (pPix[-1] >= mEdgeToProcess) {
00362                 pPix = pPix-1;
00363                 tCurrent.x--;
00364             } else if (pPix[+1] >= mEdgeToProcess) {
00365                 pPix = pPix+1;
00366                 tCurrent.x++;
00367             } else if (pPix[mImgWidth-1] >= mEdgeToProcess) {
00368                 pPix = pPix + mImgWidth-1;
00369                 tCurrent.x--, tCurrent.y++;
00370             } else if (pPix[mImgWidth] >= mEdgeToProcess) {
00371                 pPix = pPix + mImgWidth;
00372                 tCurrent.y++;
00373             } else if (pPix[mImgWidth+1] >= mEdgeToProcess) {
00374                 pPix = pPix + mImgWidth + 1;
00375                 tCurrent.x++, tCurrent.y++;
00376             } else {
00377                 if (bStart == false) {
00378                     bStart = true;
00379                     while (!trace_to_start.empty()) {
00380                         trace_to_end.push(trace_to_start.top());
00381                         trace_to_start.pop();
00382                     }
00383                     pEdgeStack = &trace_to_end;
00384                     tCurrent = pEdgeStack->top();
00385                     pEdgeStack->pop();
00386                     pPix = getImgEdge ( tCurrent );
00387                 } else {
00388                     bEnd = true;
00389                 }
00390             }
00391         }
00392         while (!pEdgeStack->empty()) {
00393             CvPoint p = pEdgeStack->top();
00394             mEdges[mNrOfEdges++] = p;
00395             pEdgeStack->pop();
00396         }
00397 
00398         *pEnd = (mNrOfEdges-1);
00399     }
00400 }
00401 
00402 void Contour::Linking_Contour() {
00403     CvPoint tPoint = {0,0};
00404     cv::Range range(0,0);
00405     for ( tPoint.y = 1; tPoint.y < ( int ) mImgHeight-1; tPoint.y++ ) {
00406         tPoint.x = 1;
00407         unsigned char *pCurrent = getImgEdge ( tPoint );
00408         for ( ; tPoint.x < ( int ) mImgWidth-1; tPoint.x++ ) {
00409             if ( *pCurrent >= mEdgeToProcess ) {
00410                 range.start = mNrOfEdges;
00411                 Trace_Contour ( tPoint, &range.end, 0 );
00412                 mSegments.push_back ( range );
00413                 
00414             }
00415             pCurrent++;
00416         }
00417     }
00418 }
00419 
00420 void Contour::Trace_Contour ( CvPoint tPoint, int *pEnd, unsigned int iCommingFromEdge ) {
00421     
00422 
00423 
00424 
00425 
00426 
00427 
00428 
00429     if (isInImage(tPoint)) {
00430         unsigned char *pPix = getImgEdge ( tPoint );
00431         CvPoint tCurrent = tPoint;
00432         bool bEnd = false;
00433         bool bStart = false;
00434         std::stack<CvPoint> trace_to_start;
00435         std::stack<CvPoint> trace_to_end;
00436         std::stack<CvPoint> *pEdgeStack = &trace_to_start;
00437         while (bEnd == false) {
00438             *pPix = mEdgeProcessed;
00439             pEdgeStack->push(tCurrent);
00440             if (pPix[-mImgWidth-1] >= mEdgeToProcess) {
00441                 pPix = pPix-mImgWidth-1;
00442                 tCurrent.x--, tCurrent.y--;
00443             } else if (pPix[-mImgWidth] >= mEdgeToProcess) {
00444                 pPix = pPix-mImgWidth;
00445                 tCurrent.y--;
00446             } else if ( pPix[-mImgWidth+1] >= mEdgeToProcess) {
00447                 pPix = pPix-mImgWidth+1;
00448                 tCurrent.x++, tCurrent.y--;
00449             } else if (pPix[-1] >= mEdgeToProcess) {
00450                 pPix = pPix-1;
00451                 tCurrent.x--;
00452             } else if (pPix[+1] >= mEdgeToProcess) {
00453                 pPix = pPix+1;
00454                 tCurrent.x++;
00455             } else if (pPix[mImgWidth-1] >= mEdgeToProcess) {
00456                 pPix = pPix + mImgWidth-1;
00457                 tCurrent.x--, tCurrent.y++;
00458             } else if (pPix[mImgWidth] >= mEdgeToProcess) {
00459                 pPix = pPix + mImgWidth;
00460                 tCurrent.y++;
00461             } else if (pPix[mImgWidth+1] >= mEdgeToProcess) {
00462                 pPix = pPix + mImgWidth + 1;
00463                 tCurrent.x++, tCurrent.y++;
00464             } else {
00465                 if (bStart == false) {
00466                     bStart = true;
00467                     while (!trace_to_start.empty()) {
00468                         trace_to_end.push(trace_to_start.top());
00469                         trace_to_start.pop();
00470                     }
00471                     pEdgeStack = &trace_to_end;
00472                     tCurrent = pEdgeStack->top();
00473                     pPix = getImgEdge ( tCurrent );
00474                 } else {
00475                     bEnd = true;
00476                 }
00477             }
00478         }
00479         while (!pEdgeStack->empty()) {
00480             mEdges[mNrOfEdges++] = pEdgeStack->top();
00481             pEdgeStack->pop();
00482         }
00483         *pEnd = mNrOfEdges;
00484     }
00485 }
00486 
00487 
00488 void Contour::Linking_Gradient() {
00489     CvPoint tPoint = {0,0};
00490     cv::Range range(0,0);
00491     for ( tPoint.y = 1; tPoint.y < ( int ) mImgHeight-1; tPoint.y++ ) {
00492         tPoint.x = 1;
00493         unsigned char *pCurrent = getImgEdge ( tPoint );
00494         for ( ; tPoint.x < ( int ) mImgWidth-1; tPoint.x++ ) {
00495             if ( *pCurrent >= mEdgeToProcess ) {
00496                 range.start = mNrOfEdges;
00497                 Trace_Gradient ( tPoint, &range.end );
00498                 mSegments.push_back ( range );
00499                 
00500             }
00501             pCurrent++;
00502         }
00503     }
00504 }
00505 
00506 void Contour::Trace_Gradient ( CvPoint tPoint, int *pEnd ) {
00507     if (isInImage(tPoint)) {
00508         CvPoint tCurrent = {0,0};
00509         CvPoint tNext = {0,0};
00510         bool bRemove = false;
00511         unsigned char *pNeighbor;
00512         int iEdgeDirection;
00513         if ( mdImgEdgeDirectionType == ANGLE_8U) {
00514             mAngle8Bit[mNrOfEdges] = ( ( unsigned char* ) mpImgEdgeDirection ) [tPoint.y*mImgWidth + tPoint.x];
00515         }
00516         iEdgeDirection = GetImgDirectionIndex ( tPoint );
00517         int *pIndex = ( int* ) ppGradientWeightsField[iEdgeDirection];
00518         for ( int i = 0; i < 9; i++ ) {
00519             tCurrent = GetNeighborPoint ( tPoint, pIndex[i] );
00520             pNeighbor = getImgEdge ( tCurrent );
00521             if ( *pNeighbor >= mEdgeToProcess ) {
00522                 if ( pIndex[i] == 4 ) {
00523                     
00524                     *pNeighbor = mEdgeProcessed;
00525                     mEdges[mNrOfEdges] = tPoint;
00526                     *pEnd = mNrOfEdges;
00527                     mNrOfEdges++;
00528                 } else {
00529                     if ( bRemove ) {
00530                         *pNeighbor = mEdgeProcessed;
00531                     } else {
00532                         bRemove = true;
00533                         tNext = tCurrent;
00534                     }
00535                 }
00536             }
00537         }
00538         if ( bRemove ) {
00539             Trace_Gradient ( tNext, pEnd );
00540         }
00541     }
00542 }
00543 
00544 
00545 void Contour::Linking_Complex() {
00546     CvPoint tPoint = {0,0};
00547     cv::Range range(0,0);
00548     for ( tPoint.y = 1; tPoint.y < ( int ) mImgHeight-1; tPoint.y++ ) {
00549         tPoint.x = 1;
00550         unsigned char *pCurrent = getImgEdge ( tPoint );
00551         for ( ; tPoint.x < ( int ) mImgWidth-1; tPoint.x++ ) {
00552             if ( *pCurrent >= mEdgeToProcess ) {
00553                 range.start = mNrOfEdges;
00554                 Trace_Complex ( tPoint, &range.end, 0 );
00555                 mSegments.push_back ( range );
00556                 
00557             }
00558             pCurrent++;
00559         }
00560     }
00561 }
00562 
00563 void Contour::Trace_Complex ( CvPoint tPoint, int *pEnd, unsigned int iCommingFromEdge ) {
00564     if (isInImage(tPoint)) {
00565         CvPoint tCurrent;
00566         CvPoint tNext = {0,0};;
00567         bool bRemove = false;
00568         unsigned char *pNeighbor = NULL;
00569         unsigned int iGointToEdge = 0;
00570         int pSum[9];
00571         int pIndex[9];
00572         int iEdgeDirection;
00573         if ( mdImgEdgeDirectionType == ANGLE_8U) {
00574             mAngle8Bit[mNrOfEdges] = ( ( unsigned char* ) mpImgEdgeDirection ) [tPoint.y*mImgWidth + tPoint.x];
00575         }
00576         iEdgeDirection = GetImgDirectionIndex ( tPoint );
00577         SumArrayMatrix (  ( int * ) pppDirectionWeightsField[iEdgeDirection],
00578                           ( int * ) pppCommingFromEdgeWeightsField[iCommingFromEdge],
00579                           ( int * ) pSum, 9 );
00580         SortArrayIndexes ( pSum, pIndex, 9 );
00581         for ( int i = 0; i < 9; i++ ) {
00582             tCurrent = GetNeighborPoint ( tPoint, pIndex[i] );
00583             pNeighbor = getImgEdge ( tCurrent );
00584             if ( *pNeighbor >= mEdgeToProcess ) {
00585                 if ( pIndex[i] == 4 ) {
00586                     
00587                     *pNeighbor = mEdgeProcessed;
00588                     mEdges[mNrOfEdges] = tPoint;
00589                     *pEnd = mNrOfEdges;
00590                     mNrOfEdges++;
00591                 } else {
00592                     if ( bRemove ) {
00593                         *pNeighbor = mEdgeProcessed;
00594                     } else {
00595                         bRemove = true;
00596                         tNext = tCurrent;
00597                         iGointToEdge = 8-pIndex[i];
00598                     }
00599                 }
00600             }
00601         }
00602         if ( bRemove ) {
00603             Trace_Complex ( tNext, pEnd, iGointToEdge );
00604         }
00605     }
00606 }
00607 
00608 const CvPoint Contour::GetNeighborPoint ( CvPoint tPoint, int iNeighborIndex ) {
00609     switch ( iNeighborIndex ) {
00610     case 0:
00611         tPoint.x += -1;
00612         tPoint.y += -1;
00613         break;
00614     case 1:
00615         tPoint.x +=  0;
00616         tPoint.y += -1;
00617         break;
00618     case 2:
00619         tPoint.x += +1;
00620         tPoint.y += -1;
00621         break;
00622     case 3:
00623         tPoint.x += -1;
00624         tPoint.y +=  0;
00625         break;
00626     case 4:
00627         tPoint.x +=  0;
00628         tPoint.y +=  0;
00629         break;
00630     case 5:
00631         tPoint.x += +1;
00632         tPoint.y +=  0;
00633         break;
00634     case 6:
00635         tPoint.x += -1;
00636         tPoint.y += +1;
00637         break;
00638     case 7:
00639         tPoint.x +=  0;
00640         tPoint.y += +1;
00641         break;
00642     case 8:
00643         tPoint.x += +1;
00644         tPoint.y += +1;
00645         break;
00646     }
00647     return tPoint;
00648 }
00649 int Contour::GetEdgeListSplittedXY (std::vector<cv::Point_<int> > &rEdges, std::vector<unsigned char> **ppAngle8Bit) {
00650 
00651     rEdges.resize ( mEdges.size() );
00652     for (unsigned int i = 0; i < mEdges.size(); i++) {
00653         rEdges[i] = mEdges[i];
00654     }
00655     if (ppAngle8Bit != NULL) {
00656         *ppAngle8Bit = &mAngle8Bit;
00657     }
00658     return mEdges.size();
00659 }
00660 
00661 const void Contour::SortArrayIndexes ( int *pArray, int *pIndexes, const int iSize ) {
00662     int iMax = -1;
00663     int iMin = iMax;
00664     int iMaxIndex = 0;
00665     for ( int j = 0; j < iSize; j++ ) {
00666         for ( int i = 0; i < iSize; i++ ) {
00667             if ( pArray[i] > iMax ) {
00668                 iMax = pArray[i];
00669                 iMaxIndex = i;
00670             }
00671             if ( pArray[i] < iMin ) {
00672                 iMin = pArray[i];
00673             }
00674         }
00675         pIndexes[j] = iMaxIndex;
00676         pArray[iMaxIndex] = iMin;
00677         iMax = iMin;
00678     }
00679 }
00680 
00681 void  Contour::GetAbnormitiesInEdgesImage ( IplImage *ptImgEdge, std::vector<CvPoint> *pAbnormities, uchar iEdgeStrength ) {
00682     pAbnormities->clear();
00683     bool bAbnormities;
00684     CvPoint tPoint;
00685     for ( tPoint.y = 1; tPoint.y < ptImgEdge->height-1; tPoint.y++ ) {
00686         unsigned char *pRow0 = ( unsigned char * ) ptImgEdge->imageData + ptImgEdge->width* ( tPoint.y-1 );
00687         unsigned char *pRow1 = pRow0 + ptImgEdge->width;
00688         unsigned char *pRow2 = pRow1 + ptImgEdge->width;
00689         for ( tPoint.x = 1; tPoint.x < ptImgEdge->width-1; tPoint.x++ ) {
00690             bAbnormities = false;
00691             if ( pRow1[1] > iEdgeStrength ) {
00692                 int iNoOfNeighbors = 0;
00693                 if ( pRow0[0] > iEdgeStrength ) {
00694                     iNoOfNeighbors++;
00695                     if ( ( pRow0[1] > iEdgeStrength ) || ( pRow1[0] > iEdgeStrength ) ) {
00696                         bAbnormities = true;
00697                     }
00698                 }
00699                 if ( pRow0[1] > iEdgeStrength ) {
00700                     iNoOfNeighbors++;
00701                     if ( ( pRow0[0] > iEdgeStrength ) || ( pRow0[2] > iEdgeStrength ) ) {
00702                         bAbnormities = true;
00703                     }
00704                 }
00705                 if ( pRow0[2] > iEdgeStrength ) {
00706                     iNoOfNeighbors++;
00707                     if ( ( pRow0[1] > iEdgeStrength ) || ( pRow1[2] > iEdgeStrength ) ) {
00708                         bAbnormities = true;
00709                     }
00710                 }
00711                 if ( pRow1[0] > iEdgeStrength ) {
00712                     iNoOfNeighbors++;
00713                     if ( ( pRow0[0] > iEdgeStrength ) || ( pRow2[0] > iEdgeStrength ) ) {
00714                         bAbnormities = true;
00715                     }
00716                 }
00717                 if ( pRow1[2] > iEdgeStrength ) {
00718                     iNoOfNeighbors++;
00719                     if ( ( pRow0[2] > iEdgeStrength ) || ( pRow2[2] > iEdgeStrength ) ) {
00720                         bAbnormities = true;
00721                     }
00722                 }
00723                 if ( pRow2[0] > iEdgeStrength ) {
00724                     iNoOfNeighbors++;
00725                     if ( ( pRow1[0] > iEdgeStrength ) || ( pRow2[1] > iEdgeStrength ) ) {
00726                         bAbnormities = true;
00727                     }
00728                 }
00729                 if ( pRow2[1] > iEdgeStrength ) {
00730                     iNoOfNeighbors++;
00731                     if ( ( pRow2[0] > iEdgeStrength ) || ( pRow2[2] > iEdgeStrength ) ) {
00732                         bAbnormities = true;
00733                     }
00734                 }
00735                 if ( pRow2[2] > iEdgeStrength ) {
00736                     iNoOfNeighbors++;
00737                     if ( ( pRow2[1] > iEdgeStrength ) || ( pRow1[2] > iEdgeStrength ) ) {
00738                         bAbnormities = true;
00739                     }
00740                 }
00741                 if ( bAbnormities ) {
00742                     pAbnormities->push_back ( tPoint );
00743                 }
00744             }
00745             pRow0++;
00746             pRow1++;
00747             pRow2++;
00748         }
00749     }
00750 
00751 }
00752 
00753 std::vector<cv::Range> Contour::getSegmentIndexes() {
00754     return mSegments;
00755 }
00756 
00757 }