root / branches / tbeta / Windows-PS3EyeMuticam / addons / ofxNCore / src / Tracking / ContourFinder.cpp @ 198

View | Annotate | Download (5.9 KB)

1
/*
2
*  ContourFinder.cpp
3
*  
4
*
5
*  Created on 2/2/09.
6
*  Adapted from openframeworks ofxCvContourFinder
7
*
8
*/
9
10
#include "ContourFinder.h"
11
12
//--------------------------------------------------------------------------------
13
static int qsort_carea_compare( const void* _a, const void* _b) 
14
{
15
        int out = 0;
16
        // pointers, ugh.... sorry about this
17
        CvSeq* a = *((CvSeq **)_a);
18
        CvSeq* b = *((CvSeq **)_b);
19
        // use opencv to calc size, then sort based on size
20
        float areaa = fabs(cvContourArea(a, CV_WHOLE_SEQ));
21
        float areab = fabs(cvContourArea(b, CV_WHOLE_SEQ));
22
        // note, based on the -1 / 1 flip
23
        // we sort biggest to smallest, not smallest to biggest
24
        if( areaa > areab )                out = -1;
25
        else                                        out =  1;
26
        return out;
27
}
28
29
//--------------------------------------------------------------------------------
30
ContourFinder::ContourFinder()
31
{
32
        myMoments = (CvMoments*)malloc( sizeof(CvMoments) );
33
        reset();
34
}
35
36
//--------------------------------------------------------------------------------
37
ContourFinder::~ContourFinder() 
38
{
39
        free( myMoments );
40
}
41
42
//--------------------------------------------------------------------------------
43
void ContourFinder::reset() 
44
{
45
    blobs.clear();
46
    nBlobs = 0;
47
}
48
49
//--------------------------------------------------------------------------------
50
int ContourFinder::findContours( ofxCvGrayscaleImage&  input,
51
                                                                          int minArea,
52
                                                                          int maxArea,
53
                                                                          int nConsidered,
54
                                                                          bool bFindHoles,
55
                                      bool bUseApproximation) 
56
{
57
        reset();
58
59
        // opencv will clober the image it detects contours on, so we want to
60
    // copy it into a copy before we detect contours.  That copy is allocated
61
    // if necessary (necessary = (a) not allocated or (b) wrong size)
62
        // so be careful if you pass in different sized images to "findContours"
63
        // there is a performance penalty, but we think there is not a memory leak
64
    // to worry about better to create mutiple contour finders for different
65
    // sizes, ie, if you are finding contours in a 640x480 image but also a
66
    // 320x240 image better to make two ContourFinder objects then to use
67
    // one, because you will get penalized less.
68
69
        if( inputCopy.width == 0 ) 
70
        {
71
                inputCopy.allocate( input.width, input.height );
72
                inputCopy = input;
73
        } 
74
        else 
75
        {
76
                if( inputCopy.width == input.width && inputCopy.height == input.height ) 
77
                        inputCopy = input;
78
                else 
79
                {
80
                        // we are allocated, but to the wrong size --
81
                        // been checked for memory leaks, but a warning:
82
                        // be careful if you call this function with alot of different
83
                        // sized "input" images!, it does allocation every time
84
                        // a new size is passed in....
85
                        //inputCopy.clear();
86
                        inputCopy.allocate( input.width, input.height );
87
                        inputCopy = input;
88
                }
89
        }
90
91
        CvSeq* contour_list = NULL;
92
        contour_storage = cvCreateMemStorage( 1000 );
93
        storage        = cvCreateMemStorage( 1000 );
94
95
        CvContourRetrievalMode  retrieve_mode
96
        = (bFindHoles) ? CV_RETR_LIST : CV_RETR_EXTERNAL;
97
        cvFindContours( inputCopy.getCvImage(), contour_storage, &contour_list,
98
                    sizeof(CvContour), retrieve_mode, bUseApproximation ? CV_CHAIN_APPROX_SIMPLE : CV_CHAIN_APPROX_NONE );
99
        CvSeq* contour_ptr = contour_list;
100
101
        nCvSeqsFound = 0;
102
103
        // put the contours from the linked list, into an array for sorting
104
        while( (contour_ptr != NULL) ) 
105
        {
106
                float area = fabs( cvContourArea(contour_ptr, CV_WHOLE_SEQ) );
107
                if( (area > minArea) && (area < maxArea) ) 
108
                {
109
                if (nCvSeqsFound < TOUCH_MAX_CONTOUR_LENGTH)
110
                                {
111
                                cvSeqBlobs[nCvSeqsFound] = contour_ptr;         // copy the pointer
112
                nCvSeqsFound++;
113
                                }
114
                }
115
                contour_ptr = contour_ptr->h_next;
116
        }
117
118
        // sort the pointers based on size
119
        if( nCvSeqsFound > 0 ) 
120
        {
121
                qsort( cvSeqBlobs, nCvSeqsFound, sizeof(CvSeq*), qsort_carea_compare);
122
        }
123
124
        // now, we have nCvSeqsFound contours, sorted by size in the array
125
    // cvSeqBlobs let's get the data out and into our structures that we like
126
        for( int i = 0; i < MIN(nConsidered, nCvSeqsFound); i++ ) 
127
        {
128
                blobs.push_back( Blob() );
129
                float area = cvContourArea( cvSeqBlobs[i], CV_WHOLE_SEQ );
130
131
                cvMoments( cvSeqBlobs[i], myMoments );
132
                
133
                // this is if using non-angle bounding box
134
                CvRect rect        = cvBoundingRect( cvSeqBlobs[i], 0 );
135
                blobs[i].boundingRect.x      = rect.x;
136
                blobs[i].boundingRect.y      = rect.y;
137
                blobs[i].boundingRect.width  = rect.width;
138
                blobs[i].boundingRect.height = rect.height;
139
140
                // this is for using angle bounding box
141
                CvBox2D32f box;
142
                box = cvMinAreaRect2( cvSeqBlobs[i] );
143
144
                blobs[i].angleBoundingRect.x          = box.center.x;
145
                blobs[i].angleBoundingRect.y          = box.center.y;
146
                blobs[i].angleBoundingRect.width  = box.size.height;
147
                blobs[i].angleBoundingRect.height = box.size.width;
148
                blobs[i].angle = box.angle;
149
150
                // assign other parameters
151
                blobs[i].area                = fabs(area);
152
                blobs[i].hole                = area < 0 ? true : false;
153
                blobs[i].length                          = cvArcLength(cvSeqBlobs[i]);
154
                // AlexP
155
                // The cast to int causes errors in tracking since centroids are calculated in
156
                // floats and they migh land between integer pixel values (which is what we really want)
157
                // This not only makes tracking more accurate but also more fluid
158
                blobs[i].centroid.x                         = (myMoments->m10 / myMoments->m00);
159
                blobs[i].centroid.y                  = (myMoments->m01 / myMoments->m00);
160
                blobs[i].lastCentroid.x          = 0;
161
                blobs[i].lastCentroid.y          = 0;
162
163
                // get the points for the blob:
164
                CvPoint           pt;
165
                CvSeqReader       reader;
166
                cvStartReadSeq( cvSeqBlobs[i], &reader, 0 );
167
168
            for( int j=0; j < min(TOUCH_MAX_CONTOUR_LENGTH, cvSeqBlobs[i]->total); j++ ) 
169
                {
170
                        CV_READ_SEQ_ELEM( pt, reader );
171
            blobs[i].pts.push_back( ofPoint((float)pt.x, (float)pt.y) );
172
                }
173
                blobs[i].nPts = blobs[i].pts.size();
174
        }
175
176
    nBlobs = blobs.size();
177
178
        // Free the storage memory.
179
        // Warning: do this inside this function otherwise a strange memory leak
180
        if( contour_storage != NULL ) { cvReleaseMemStorage(&contour_storage); }
181
        if( storage != NULL ) { cvReleaseMemStorage(&storage); }
182
183
        return nBlobs;
184
}
185