ComponentLabeling.cpp
Go to the documentation of this file.
00001 
00002 #include "hrl_cvblobslib/ComponentLabeling.h"
00003 
00005 static const CvPoint freemanCodeIncrement[8] =
00006     { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
00007 
00008 
00009 
00023 inline unsigned char GET_ABOVE_IMAGEPIXEL( unsigned char *currentPixel, IplImage *image )
00024 {
00025         return *(currentPixel - image->widthStep);
00026 }
00027 inline unsigned char GET_BELOW_IMAGEPIXEL( unsigned char *currentPixel, IplImage *image )
00028 {
00029         return *(currentPixel + image->widthStep);
00030 }
00031 
00032 
00033 
00034 inline unsigned char GET_IMAGE_PIXEL( IplImage *image, CvPoint p )
00035 {
00036         return *(image->imageData + p.x + p.y *image->widthStep);
00037 }
00038 
00039 inline bool GET_IMAGEMASK_PIXEL( IplImage *mask, CvPoint p )
00040 {
00041         if( mask != NULL )
00042                 return ((unsigned char)*(mask->imageData + p.x + p.y *mask->widthStep)) > 0;
00043         else
00044                 return true;
00045 }
00046 inline bool GET_BELOW_VISITEDPIXEL( bool *currentPixel, int imageWidth )
00047 {
00048         return *( currentPixel + imageWidth );
00049 }
00050 
00064 inline void ASSIGN_LABEL( CvPoint p, t_labelType *labels, int imageWidth, int newLabel )
00065 {
00066         *(labels + p.y * imageWidth + p.x) = newLabel;
00067 }
00068 
00069 
00070 inline void ASSIGN_VISITED( CvPoint p, bool *visitedPoints, int imageWidth  )
00071 {
00072         *(visitedPoints + p.y * imageWidth + p.x) = true;
00073 }
00074 
00093 bool ComponentLabeling( IplImage* inputImage,
00094                                                 IplImage* maskImage,
00095                                                 unsigned char backgroundColor,
00096                                                 Blob_vector &blobs )
00097 {
00098         int i,j;
00099         // row major vector with visited points 
00100         bool *visitedPoints, *pVisitedPoints, internalContour, externalContour;
00101         unsigned char *pInputImage, *pMask;
00102         int imageWidth, imageHeight, currentLabel, contourLabel;
00103         // row major vector with labelled image 
00104         t_labelType *labelledImage, *pLabels;
00106         CBlob *currentBlob;
00107         CvSize imageSizes;
00108         CvPoint currentPoint;
00109 
00110         // verify input image
00111         if( !CV_IS_IMAGE( inputImage ) )
00112                 return false;
00113 
00114         // verify that input image and mask image has same size
00115         if( maskImage )
00116         {
00117                 if( !CV_IS_IMAGE(maskImage) || 
00118                         maskImage->width != inputImage->width || 
00119                         maskImage->height != inputImage->height )
00120                 return false;
00121         }
00122 
00123         imageSizes = cvSize(inputImage->width,inputImage->height);
00124         
00125         imageWidth = inputImage->width;
00126         imageHeight = inputImage->height;
00127 
00128         // create auxiliary buffers
00129         labelledImage = (t_labelType*) malloc( inputImage->width * inputImage->height * sizeof(t_labelType) );
00130         visitedPoints = (bool*) malloc( inputImage->width * inputImage->height * sizeof(bool) );
00131 
00132         // initialize it to 0
00133         memset(labelledImage, 0, inputImage->width * inputImage->height * sizeof(t_labelType) ) ;
00134         memset(visitedPoints, false, inputImage->width * inputImage->height * sizeof(bool) ) ;
00135 
00136         // initialize pointers and label counter
00137         pLabels = labelledImage;
00138         pVisitedPoints = visitedPoints;
00139         currentLabel = 1;
00140 
00141         for (j = 0; j < imageHeight; j++ )
00142         {
00143                 pInputImage = (unsigned char*) inputImage->imageData + j * inputImage->widthStep;
00144 
00145                 if( maskImage )
00146                         pMask = (unsigned char*) maskImage->imageData + j * maskImage->widthStep;
00147                 
00148                 for (i = 0; i < imageWidth; i++, pInputImage++, pMask++ )
00149                 {
00150                         // ignore background pixels or 0 pixels in mask
00151                         if ( (*pInputImage == backgroundColor) || (maskImage && *pMask == 0 ))
00152                         {
00153                                 pLabels++;
00154                                 pVisitedPoints++;
00155                                 continue;
00156                         }
00157                         
00158                         // new external contour: current label == 0 and above pixel is background
00159                         if( j > 0 )
00160                                 externalContour = ((GET_ABOVE_IMAGEPIXEL( pInputImage, inputImage ) == backgroundColor) || 
00161                                                                   (maskImage && GET_ABOVE_IMAGEPIXEL( pMask, maskImage ) == 0)) && 
00162                                                                   (*pLabels == 0);
00163                         else
00164                                 externalContour = (*pLabels == 0);
00165 
00166                         // new internal contour: below pixel is background and not visited
00167                         if( !externalContour && j < imageHeight - 1 )
00168                         {
00169                                 internalContour = GET_BELOW_IMAGEPIXEL( pInputImage, inputImage ) == backgroundColor &&
00170                                                                   !GET_BELOW_VISITEDPIXEL( pVisitedPoints, imageWidth);
00171 
00172                         }
00173                         else
00174                         {
00175                                 internalContour = false;
00176                         }
00177                         
00178                         
00179                         if( externalContour )
00180                         {
00181                                 currentPoint = cvPoint(i,j);
00182                                 // assign label to labelled image
00183                                 *pLabels = currentLabel;
00184                                 
00185                                 // create new blob
00186                                 currentBlob = new CBlob(currentLabel, currentPoint, imageSizes );
00187 
00188                                 // contour tracing with currentLabel
00189                                 contourTracing( inputImage, maskImage, currentPoint, 
00190                                                                 labelledImage, visitedPoints, 
00191                                                                 currentLabel, false, backgroundColor, currentBlob->GetExternalContour() );
00192 
00193                                 // add new created blob
00194                                 blobs.push_back(currentBlob);
00195 
00196                                 currentLabel++;
00197                         }
00198                         else 
00199                         {
00200                                 if( internalContour )
00201                                 {
00202                                         currentPoint = cvPoint(i,j);
00203 
00204                                         if( *pLabels == 0 )
00205                                         {
00206                                                 // take left neightbour value as current
00207                                                 if( i > 0 )
00208                                                         contourLabel = *(pLabels - 1);
00209                                         }
00210                                         else
00211                                         {
00212                                                 contourLabel = *pLabels;
00213                                         }
00214 
00215                                         if(contourLabel>0)
00216                                         {
00217                                                 currentBlob = blobs[contourLabel-1];
00218                                                 CBlobContour newContour(currentPoint, currentBlob->GetStorage());
00219                                                 
00220 
00221                                                 // contour tracing with contourLabel
00222                                                 contourTracing( inputImage, maskImage, currentPoint, labelledImage, visitedPoints,
00223                                                                                 contourLabel, true, backgroundColor, &newContour ); 
00224 
00225                                                 currentBlob->AddInternalContour( newContour );
00226                                         }
00227                                 }
00228                                 // neither internal nor external contour
00229                                 else
00230                                 {
00231                                         // take left neightbour value as current if it is not labelled
00232                                         if( i > 0 && *pLabels == 0 )
00233                                                 *pLabels = *(pLabels - 1);
00234                                 }
00235 
00236                         }
00237                         
00238                         pLabels++;
00239                         pVisitedPoints++;
00240 
00241                 }
00242         }
00243 
00244 
00245         // free auxiliary buffers
00246         free( labelledImage );
00247         free( visitedPoints );
00248 
00249         return true;
00250 }
00251 
00252 
00253 
00267 void contourTracing( IplImage *image, 
00268                                          IplImage *maskImage,
00269                                          CvPoint contourStart, t_labelType *labels, bool *visitedPoints, t_labelType label,
00270                                          bool internalContour, unsigned char backgroundColor, CBlobContour *currentBlobcontour )
00271 {
00272         CvPoint t, tnext, tsecond;
00273         short initialMovement, movement;
00274 
00275         if( internalContour )
00276         {
00277                 initialMovement = 7;//3;
00278         }
00279         else
00280         {
00281                 initialMovement = 3;//7;
00282         }
00283 
00284         tsecond = tracer( image, maskImage, contourStart, visitedPoints, initialMovement, 
00285                                         backgroundColor, movement );
00286         
00287         // assign current label to tnext
00288         ASSIGN_LABEL( contourStart, labels, image->width, label );
00289         
00290 
00291         // contour corresponds to isolated pixel? 
00292         if( tsecond.x == contourStart.x && tsecond.y == contourStart.y )
00293         {
00294                 // we are finished with the contour
00295                 return;
00296         }
00297 
00298         // add chain code to current contour
00299         currentBlobcontour->AddChainCode(movement);
00300         
00301         // assign label to next point 
00302         ASSIGN_LABEL( tsecond, labels, image->width, label );
00303         
00304         tnext.x = tsecond.x;
00305         tnext.y = tsecond.y;
00306         t.x = tnext.x;
00307         t.y = tnext.y;
00308         
00309         // while T is different than contourStart and Tnext is different than T
00310         // follow contour until start point is reached again
00311         while ( t.x != contourStart.x || t.y != contourStart.y || 
00312                         tsecond.x != tnext.x || tsecond.y != tnext.y )
00313         {
00314                 
00315                 t.x = tnext.x;
00316                 t.y = tnext.y;
00317                 initialMovement = (movement + 5) % 8;
00318                 
00319                 // search for next contour point
00320                 tnext = tracer( image, maskImage, t, visitedPoints, initialMovement, 
00321                                                 backgroundColor, movement );
00322                 
00323                 // assign label to contour point
00324                 ASSIGN_LABEL( tnext, labels, image->width, label );
00325 
00326                 // add chain code to current contour
00327                 currentBlobcontour->AddChainCode(movement);
00328         }
00329 
00330 }
00331 
00345 CvPoint tracer( IplImage *image, IplImage *maskImage, CvPoint P, bool *visitedPoints,
00346                                 short initialMovement,
00347                                 unsigned char backgroundColor, short &movement )
00348 {
00349         int d;
00350         CvPoint pNext;
00351         
00352         for (d = 0; d <= 7; d++ )
00353         {
00354                 movement = (initialMovement + d) % 8;
00355                 
00356                 pNext.x = P.x + freemanCodeIncrement[movement].x;
00357                 pNext.y = P.y + freemanCodeIncrement[movement].y;
00358 
00359                 // the point is inside image ?
00360                 if( pNext.x < 0 || pNext.x >= image->width || 
00361                         pNext.y < 0 || pNext.y >= image->height )
00362                 {
00363                         // try other movement
00364                         continue;
00365                 }
00366                 
00367                 // image has blobColor value in the new point?
00368                 if( (GET_IMAGE_PIXEL( image, pNext ) != backgroundColor ) && GET_IMAGEMASK_PIXEL(maskImage, pNext ) )
00369                 {
00370                         return pNext;
00371                 }
00372                 else
00373                 {
00374                         // mark point as visited
00375                         ASSIGN_VISITED( pNext, visitedPoints, image->width );
00376                 }
00377         }
00378 
00379         // no possible movement was found
00380         movement = -1;
00381         pNext.x = P.x;
00382         pNext.y = P.y;
00383 
00384         return pNext;
00385 }
00386 
00387 


hrl_cvblobslib
Author(s): kelsey
autogenerated on Wed Nov 27 2013 11:32:58