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
00100 bool *visitedPoints, *pVisitedPoints, internalContour, externalContour;
00101 unsigned char *pInputImage, *pMask;
00102 int imageWidth, imageHeight, currentLabel, contourLabel;
00103
00104 t_labelType *labelledImage, *pLabels;
00106 CBlob *currentBlob;
00107 CvSize imageSizes;
00108 CvPoint currentPoint;
00109
00110
00111 if( !CV_IS_IMAGE( inputImage ) )
00112 return false;
00113
00114
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
00129 labelledImage = (t_labelType*) malloc( inputImage->width * inputImage->height * sizeof(t_labelType) );
00130 visitedPoints = (bool*) malloc( inputImage->width * inputImage->height * sizeof(bool) );
00131
00132
00133 memset(labelledImage, 0, inputImage->width * inputImage->height * sizeof(t_labelType) ) ;
00134 memset(visitedPoints, false, inputImage->width * inputImage->height * sizeof(bool) ) ;
00135
00136
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
00151 if ( (*pInputImage == backgroundColor) || (maskImage && *pMask == 0 ))
00152 {
00153 pLabels++;
00154 pVisitedPoints++;
00155 continue;
00156 }
00157
00158
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
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
00183 *pLabels = currentLabel;
00184
00185
00186 currentBlob = new CBlob(currentLabel, currentPoint, imageSizes );
00187
00188
00189 contourTracing( inputImage, maskImage, currentPoint,
00190 labelledImage, visitedPoints,
00191 currentLabel, false, backgroundColor, currentBlob->GetExternalContour() );
00192
00193
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
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
00222 contourTracing( inputImage, maskImage, currentPoint, labelledImage, visitedPoints,
00223 contourLabel, true, backgroundColor, &newContour );
00224
00225 currentBlob->AddInternalContour( newContour );
00226 }
00227 }
00228
00229 else
00230 {
00231
00232 if( i > 0 && *pLabels == 0 )
00233 *pLabels = *(pLabels - 1);
00234 }
00235
00236 }
00237
00238 pLabels++;
00239 pVisitedPoints++;
00240
00241 }
00242 }
00243
00244
00245
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;
00278 }
00279 else
00280 {
00281 initialMovement = 3;
00282 }
00283
00284 tsecond = tracer( image, maskImage, contourStart, visitedPoints, initialMovement,
00285 backgroundColor, movement );
00286
00287
00288 ASSIGN_LABEL( contourStart, labels, image->width, label );
00289
00290
00291
00292 if( tsecond.x == contourStart.x && tsecond.y == contourStart.y )
00293 {
00294
00295 return;
00296 }
00297
00298
00299 currentBlobcontour->AddChainCode(movement);
00300
00301
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
00310
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
00320 tnext = tracer( image, maskImage, t, visitedPoints, initialMovement,
00321 backgroundColor, movement );
00322
00323
00324 ASSIGN_LABEL( tnext, labels, image->width, label );
00325
00326
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
00360 if( pNext.x < 0 || pNext.x >= image->width ||
00361 pNext.y < 0 || pNext.y >= image->height )
00362 {
00363
00364 continue;
00365 }
00366
00367
00368 if( (GET_IMAGE_PIXEL( image, pNext ) != backgroundColor ) && GET_IMAGEMASK_PIXEL(maskImage, pNext ) )
00369 {
00370 return pNext;
00371 }
00372 else
00373 {
00374
00375 ASSIGN_VISITED( pNext, visitedPoints, image->width );
00376 }
00377 }
00378
00379
00380 movement = -1;
00381 pNext.x = P.x;
00382 pNext.y = P.y;
00383
00384 return pNext;
00385 }
00386
00387