Project

General

Profile

Statistics
| Branch: | Revision:

root / vision / cvblobs8.3 / ComponentLabeling.cpp @ b11b2b30

History | View | Annotate | Download (10.4 KB)

1

    
2
#include "ComponentLabeling.h"
3

    
4
//! Conversion from freeman code to coordinate increments (counterclockwise)
5
static const CvPoint freemanCodeIncrement[8] =
6
    { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
7

    
8

    
9

    
10
/**
11
- FUNCI?: 
12
- FUNCIONALITAT: 
13
- PAR?METRES:
14
        - 
15
- RESULTAT:
16
        - 
17
- RESTRICCIONS:
18
        - 
19
- AUTOR: rborras
20
- DATA DE CREACI?: 2008/04/29
21
- MODIFICACI?: Data. Autor. Descripci?.
22
*/
23
inline unsigned char GET_ABOVE_IMAGEPIXEL( unsigned char *currentPixel, IplImage *image )
24
{
25
        return *(currentPixel - image->widthStep);
26
}
27
inline unsigned char GET_BELOW_IMAGEPIXEL( unsigned char *currentPixel, IplImage *image )
28
{
29
        return *(currentPixel + image->widthStep);
30
}
31

    
32

    
33

    
34
inline unsigned char GET_IMAGE_PIXEL( IplImage *image, CvPoint p )
35
{
36
        return *(image->imageData + p.x + p.y *image->widthStep);
37
}
38

    
39
inline bool GET_IMAGEMASK_PIXEL( IplImage *mask, CvPoint p )
40
{
41
        if( mask != NULL )
42
                return ((unsigned char)*(mask->imageData + p.x + p.y *mask->widthStep)) > 0;
43
        else
44
                return true;
45
}
46
inline bool GET_BELOW_VISITEDPIXEL( bool *currentPixel, int imageWidth )
47
{
48
        return *( currentPixel + imageWidth );
49
}
50

    
51
/**
52
- FUNCI?: ASSIGN_LABEL
53
- FUNCIONALITAT: Assigns label value to label image
54
- PAR?METRES:
55
        - 
56
- RESULTAT:
57
        - 
58
- RESTRICCIONS:
59
        - 
60
- AUTOR: rborras
61
- DATA DE CREACI?: 2008/04/29
62
- MODIFICACI?: Data. Autor. Descripci?.
63
*/
64
inline void ASSIGN_LABEL( CvPoint p, t_labelType *labels, int imageWidth, int newLabel )
65
{
66
        *(labels + p.y * imageWidth + p.x) = newLabel;
67
}
68

    
69

    
70
inline void ASSIGN_VISITED( CvPoint p, bool *visitedPoints, int imageWidth  )
71
{
72
        *(visitedPoints + p.y * imageWidth + p.x) = true;
73
}
74

    
75
/**
76
- FUNCI?: ComponentLabeling
77
- FUNCIONALITAT: Calcula els components binaris (blobs) d'una imatge amb connectivitat a 8
78
- PAR?METRES:
79
        - inputImage: image to segment (pixel values different than blobColor are treated as background)
80
        - maskImage: if not NULL, all the pixels equal to 0 in mask are skipped in input image
81
        - backgroundColor: color of background (ignored pixels)
82
        - blobs: blob vector destination
83
- RESULTAT:
84
        - 
85
- RESTRICCIONS:
86
        - 
87
- AUTOR: rborras
88
- DATA DE CREACI?: 2008/04/21
89
- MODIFICACI?: Data. Autor. Descripci?.
90
- NOTA: Algorithm based on "A linear-time component labeling algorithm using contour tracing technique", 
91
                F.Chang et al
92
*/
93
bool ComponentLabeling(        IplImage* inputImage,
94
                                                IplImage* maskImage,
95
                                                unsigned char backgroundColor,
96
                                                Blob_vector &blobs )
97
{
98
        int i,j;
99
        // row major vector with visited points 
100
        bool *visitedPoints, *pVisitedPoints, internalContour, externalContour;
101
        unsigned char *pInputImage, *pMask, *pAboveInputImage, *pBelowInputImage,
102
                                  *pAboveMask, *pBelowMask;
103
        int imageWidth, imageHeight, currentLabel, contourLabel;
104
        // row major vector with labelled image 
105
        t_labelType *labelledImage, *pLabels;
106
        //! current blob pointer
107
        CBlob *currentBlob;
108
        CvSize imageSizes;
109
        CvPoint currentPoint;
110

    
111
        // verify input image
112
        if( !CV_IS_IMAGE( inputImage ) )
113
                return false;
114

    
115
        // verify that input image and mask image has same size
116
        if( maskImage )
117
        {
118
                if( !CV_IS_IMAGE(maskImage) || 
119
                        maskImage->width != inputImage->width || 
120
                        maskImage->height != inputImage->height )
121
                return false;
122
        }
123
        else
124
        {
125
                pMask = NULL;
126
                pAboveMask = NULL;
127
                pBelowMask = NULL;
128
        }
129

    
130
        imageSizes = cvSize(inputImage->width,inputImage->height);
131
        
132
        imageWidth = inputImage->width;
133
        imageHeight = inputImage->height;
134

    
135
        // create auxiliary buffers
136
        labelledImage = (t_labelType*) malloc( inputImage->width * inputImage->height * sizeof(t_labelType) );
137
        visitedPoints = (bool*) malloc( inputImage->width * inputImage->height * sizeof(bool) );
138

    
139
        // initialize it to 0
140
        memset(labelledImage, 0, inputImage->width * inputImage->height * sizeof(t_labelType) ) ;
141
        memset(visitedPoints, false, inputImage->width * inputImage->height * sizeof(bool) ) ;
142

    
143
        // initialize pointers and label counter
144
        pLabels = labelledImage;
145
        pVisitedPoints = visitedPoints;
146
        currentLabel = 1;
147

    
148
        for (j = 0; j < imageHeight; j++ )
149
        {
150
                // don't verify if we area on first or last row, it will verified on pointer access
151
                pAboveInputImage = (unsigned char*) inputImage->imageData + (j-1) * inputImage->widthStep;
152
                pBelowInputImage = (unsigned char*) inputImage->imageData + (j+1) * inputImage->widthStep;
153
        
154
                pInputImage = (unsigned char*) inputImage->imageData + j * inputImage->widthStep;
155

    
156
                if( maskImage )
157
                {
158
                        pMask = (unsigned char*) maskImage->imageData + j * maskImage->widthStep;
159
                        // don't verify if we area on first or last row, it will verified on pointer access
160
                        pAboveMask = (unsigned char*) maskImage->imageData + (j-1) * maskImage->widthStep;
161
                        pBelowMask = (unsigned char*) maskImage->imageData + (j+1) * maskImage->widthStep;
162

    
163
                }
164
                
165
                for (i = 0; i < imageWidth; i++, pInputImage++, pMask++, pAboveInputImage++, pBelowInputImage++,
166
                                                                                 pAboveMask++, pBelowMask++ )
167
                {
168
                        // ignore background pixels or 0 pixels in mask
169
                        if ( (*pInputImage == backgroundColor) || (maskImage && *pMask == 0 ))
170
                        {
171
                                pLabels++;
172
                                pVisitedPoints++;
173
                                continue;
174
                        }
175
                        
176
                        // new external contour: current label == 0 and above pixel is background
177
                        if( j > 0 )
178
                        {
179
                                externalContour = ((*pAboveInputImage == backgroundColor) || 
180
                                                                  (maskImage && *pAboveMask == 0)) && 
181
                                                                  (*pLabels == 0);
182
                        }
183
                        else
184
                                externalContour = (*pLabels == 0);
185

    
186
                        // new internal contour: below pixel is background and not visited
187
                        if( !externalContour && j < imageHeight - 1 )
188
                        {
189
                                internalContour = *pBelowInputImage == backgroundColor &&
190
                                                                  !GET_BELOW_VISITEDPIXEL( pVisitedPoints, imageWidth);
191
                        }
192
                        else
193
                        {
194
                                internalContour = false;
195
                        }
196
                        
197
                        
198
                        if( externalContour )
199
                        {
200
                                currentPoint = cvPoint(i,j);
201
                                // assign label to labelled image
202
                                *pLabels = currentLabel;
203
                                
204
                                // create new blob
205
                                currentBlob = new CBlob(currentLabel, currentPoint, imageSizes );
206

    
207
                                // contour tracing with currentLabel
208
                                contourTracing( inputImage, maskImage, currentPoint, 
209
                                                                labelledImage, visitedPoints, 
210
                                                                currentLabel, false, backgroundColor, currentBlob->GetExternalContour() );
211

    
212
                                // add new created blob
213
                                blobs.push_back(currentBlob);
214

    
215
                                currentLabel++;
216
                        }
217
                        else 
218
                        {
219
                                if( internalContour )
220
                                {
221
                                        currentPoint = cvPoint(i,j);
222

    
223
                                        if( *pLabels == 0 )
224
                                        {
225
                                                // take left neightbour value as current
226
                                                if( i > 0 )
227
                                                        contourLabel = *(pLabels - 1);
228
                                        }
229
                                        else
230
                                        {
231
                                                contourLabel = *pLabels;
232
                                        }
233

    
234
                                        if(contourLabel>0)
235
                                        {
236
                                                currentBlob = blobs[contourLabel-1];
237
                                                CBlobContour newContour(currentPoint, currentBlob->GetStorage());
238
                                                
239

    
240
                                                // contour tracing with contourLabel
241
                                                contourTracing( inputImage, maskImage, currentPoint, labelledImage, visitedPoints,
242
                                                                                contourLabel, true, backgroundColor, &newContour ); 
243

    
244
                                                currentBlob->AddInternalContour( newContour );
245
                                        }
246
                                }
247
                                // neither internal nor external contour
248
                                else
249
                                {
250
                                        // take left neightbour value as current if it is not labelled
251
                                        if( i > 0 && *pLabels == 0 )
252
                                                *pLabels = *(pLabels - 1);
253
                                }
254

    
255
                        }
256
                        
257
                        pLabels++;
258
                        pVisitedPoints++;
259

    
260
                }
261
        }
262

    
263

    
264
        // free auxiliary buffers
265
        free( labelledImage );
266
        free( visitedPoints );
267

    
268
        return true;
269
}
270

    
271

    
272

    
273
/**
274
- FUNCI?: 
275
- FUNCIONALITAT: 
276
- PAR?METRES:
277
        - 
278
- RESULTAT:
279
        - 
280
- RESTRICCIONS:
281
        - 
282
- AUTOR: rborras
283
- DATA DE CREACI?: 2008/04/29
284
- MODIFICACI?: Data. Autor. Descripci?.
285
*/
286
void contourTracing( IplImage *image, 
287
                                         IplImage *maskImage,
288
                                         CvPoint contourStart, t_labelType *labels, bool *visitedPoints, t_labelType label,
289
                                         bool internalContour, unsigned char backgroundColor, CBlobContour *currentBlobcontour )
290
{
291
        CvPoint t, tnext, tsecond;
292
        short initialMovement, movement;
293

    
294
        if( internalContour )
295
        {
296
                initialMovement = 7;//3;
297
        }
298
        else
299
        {
300
                initialMovement = 3;//7;
301
        }
302

    
303
        tsecond = tracer( image, maskImage, contourStart, visitedPoints, initialMovement, 
304
                                        backgroundColor, movement );
305
        
306
        // assign current label to tnext
307
        ASSIGN_LABEL( contourStart, labels, image->width, label );
308
        
309

    
310
        // contour corresponds to isolated pixel? 
311
        if( tsecond.x == contourStart.x && tsecond.y == contourStart.y )
312
        {
313
                // we are finished with the contour
314
                return;
315
        }
316

    
317
        // add chain code to current contour
318
        currentBlobcontour->AddChainCode(movement);
319
        
320
        // assign label to next point 
321
        ASSIGN_LABEL( tsecond, labels, image->width, label );
322
        
323
        tnext.x = tsecond.x;
324
        tnext.y = tsecond.y;
325
        t.x = tnext.x;
326
        t.y = tnext.y;
327
        
328
        // while T is different than contourStart and Tnext is different than T
329
        // follow contour until start point is reached again
330
        while ( t.x != contourStart.x || t.y != contourStart.y || 
331
                        tsecond.x != tnext.x || tsecond.y != tnext.y )
332
        {
333
                
334
                t.x = tnext.x;
335
                t.y = tnext.y;
336
                initialMovement = (movement + 5) % 8;
337
                
338
                // search for next contour point
339
                tnext = tracer( image, maskImage, t, visitedPoints, initialMovement, 
340
                                                backgroundColor, movement );
341
                
342
                // assign label to contour point
343
                ASSIGN_LABEL( tnext, labels, image->width, label );
344

    
345
                // add chain code to current contour
346
                currentBlobcontour->AddChainCode(movement);
347
        }
348

    
349
}
350

    
351
/**
352
- FUNCI?: tracer
353
- FUNCIONALITAT: Searches for next point of a contour
354
- PAR?METRES:
355
        - 
356
- RESULTAT:
357
        - 
358
- RESTRICCIONS:
359
        - 
360
- AUTOR: rborras
361
- DATA DE CREACI?: 2008/04/30
362
- MODIFICACI?: Data. Autor. Descripci?.
363
*/
364
CvPoint tracer( IplImage *image, IplImage *maskImage, CvPoint P, bool *visitedPoints,
365
                                short initialMovement,
366
                                unsigned char backgroundColor, short &movement )
367
{
368
        int d;
369
        CvPoint pNext;
370
        
371
        for (d = 0; d <= 7; d++ )
372
        {
373
                movement = (initialMovement + d) % 8;
374
                
375
                pNext.x = P.x + freemanCodeIncrement[movement].x;
376
                pNext.y = P.y + freemanCodeIncrement[movement].y;
377

    
378
                // the point is inside image ?
379
                if( pNext.x < 0 || pNext.x >= image->width || 
380
                        pNext.y < 0 || pNext.y >= image->height )
381
                {
382
                        // try other movement
383
                        continue;
384
                }
385
                
386
                // image has blobColor value in the new point?
387
                if( (GET_IMAGE_PIXEL( image, pNext ) != backgroundColor ) && GET_IMAGEMASK_PIXEL(maskImage, pNext ) )
388
                {
389
                        return pNext;
390
                }
391
                else
392
                {
393
                        // mark point as visited
394
                        ASSIGN_VISITED( pNext, visitedPoints, image->width );
395
                }
396
        }
397

    
398
        // no possible movement was found
399
        movement = -1;
400
        pNext.x = P.x;
401
        pNext.y = P.y;
402

    
403
        return pNext;
404
}
405

    
406