1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                        Intel License Agreement
11//
12// Copyright (C) 2000, Intel Corporation, all rights reserved.
13// Third party copyrights are property of their respective owners.
14//
15// Redistribution and use in source and binary forms, with or without modification,
16// are permitted provided that the following conditions are met:
17//
18//   * Redistribution's of source code must retain the above copyright notice,
19//     this list of conditions and the following disclaimer.
20//
21//   * Redistribution's in binary form must reproduce the above copyright notice,
22//     this list of conditions and the following disclaimer in the documentation
23//     and/or other materials provided with the distribution.
24//
25//   * The name of Intel Corporation may not be used to endorse or promote products
26//     derived from this software without specific prior written permission.
27//
28// This software is provided by the copyright holders and contributors "as is" and
29// any express or implied warranties, including, but not limited to, the implied
30// warranties of merchantability and fitness for a particular purpose are disclaimed.
31// In no event shall the Intel Corporation or contributors be liable for any direct,
32// indirect, incidental, special, exemplary, or consequential damages
33// (including, but not limited to, procurement of substitute goods or services;
34// loss of use, data, or profits; or business interruption) however caused
35// and on any theory of liability, whether in contract, strict liability,
36// or tort (including negligence or otherwise) arising in any way out of
37// the use of this software, even if advised of the possibility of such damage.
38//
39//M*/
40
41#include "_cvaux.h"
42
43CvBGCodeBookModel* cvCreateBGCodeBookModel()
44{
45    CvBGCodeBookModel* model = (CvBGCodeBookModel*)cvAlloc( sizeof(*model) );
46    memset( model, 0, sizeof(*model) );
47    model->cbBounds[0] = model->cbBounds[1] = model->cbBounds[2] = 10;
48    model->modMin[0] = 3;
49    model->modMax[0] = 10;
50    model->modMin[1] = model->modMin[2] = 1;
51    model->modMax[1] = model->modMax[2] = 1;
52    model->storage = cvCreateMemStorage();
53
54    return model;
55}
56
57void cvReleaseBGCodeBookModel( CvBGCodeBookModel** model )
58{
59    if( model && *model )
60    {
61        cvReleaseMemStorage( &(*model)->storage );
62        memset( *model, 0, sizeof(**model) );
63        cvFree( model );
64    }
65}
66
67static uchar satTab8u[768];
68#undef SAT_8U
69#define SAT_8U(x) satTab8u[(x) + 255]
70
71static void icvInitSatTab()
72{
73    static int initialized = 0;
74    if( !initialized )
75    {
76        for( int i = 0; i < 768; i++ )
77        {
78            int v = i - 255;
79            satTab8u[i] = (uchar)(v < 0 ? 0 : v > 255 ? 255 : v);
80        }
81        initialized = 1;
82    }
83}
84
85
86void cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* _image,
87                         CvRect roi, const CvArr* _mask )
88{
89    CV_FUNCNAME( "cvBGCodeBookUpdate" );
90
91    __BEGIN__;
92
93    CvMat stub, *image = cvGetMat( _image, &stub );
94    CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
95    int i, x, y, T;
96    int nblocks;
97    uchar cb0, cb1, cb2;
98    CvBGCodeBookElem* freeList;
99
100    CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
101        (!mask || CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask)) );
102
103    if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
104    {
105        roi.width = image->cols;
106        roi.height = image->rows;
107    }
108    else
109        CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols &&
110                   (unsigned)roi.y < (unsigned)image->rows &&
111                   roi.width >= 0 && roi.height >= 0 &&
112                   roi.x + roi.width <= image->cols &&
113                   roi.y + roi.height <= image->rows );
114
115    if( image->cols != model->size.width || image->rows != model->size.height )
116    {
117        cvClearMemStorage( model->storage );
118        model->freeList = 0;
119        cvFree( &model->cbmap );
120        int bufSz = image->cols*image->rows*sizeof(model->cbmap[0]);
121        model->cbmap = (CvBGCodeBookElem**)cvAlloc(bufSz);
122        memset( model->cbmap, 0, bufSz );
123        model->size = cvSize(image->cols, image->rows);
124    }
125
126    icvInitSatTab();
127
128    cb0 = model->cbBounds[0];
129    cb1 = model->cbBounds[1];
130    cb2 = model->cbBounds[2];
131
132    T = ++model->t;
133    freeList = model->freeList;
134    nblocks = (int)((model->storage->block_size - sizeof(CvMemBlock))/sizeof(*freeList));
135    nblocks = MIN( nblocks, 1024 );
136    CV_ASSERT( nblocks > 0 );
137
138    for( y = 0; y < roi.height; y++ )
139    {
140        const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3;
141        const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0;
142        CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x;
143
144        for( x = 0; x < roi.width; x++, p += 3, cb++ )
145        {
146            CvBGCodeBookElem *e, *found = 0;
147            uchar p0, p1, p2, l0, l1, l2, h0, h1, h2;
148            int negRun;
149
150            if( m && m[x] == 0 )
151                continue;
152
153            p0 = p[0]; p1 = p[1]; p2 = p[2];
154            l0 = SAT_8U(p0 - cb0); l1 = SAT_8U(p1 - cb1); l2 = SAT_8U(p2 - cb2);
155            h0 = SAT_8U(p0 + cb0); h1 = SAT_8U(p1 + cb1); h2 = SAT_8U(p2 + cb2);
156
157            for( e = *cb; e != 0; e = e->next )
158            {
159                if( e->learnMin[0] <= p0 && p0 <= e->learnMax[0] &&
160                    e->learnMin[1] <= p1 && p1 <= e->learnMax[1] &&
161                    e->learnMin[2] <= p2 && p2 <= e->learnMax[2] )
162                {
163                    e->tLastUpdate = T;
164                    e->boxMin[0] = MIN(e->boxMin[0], p0);
165                    e->boxMax[0] = MAX(e->boxMax[0], p0);
166                    e->boxMin[1] = MIN(e->boxMin[1], p1);
167                    e->boxMax[1] = MAX(e->boxMax[1], p1);
168                    e->boxMin[2] = MIN(e->boxMin[2], p2);
169                    e->boxMax[2] = MAX(e->boxMax[2], p2);
170
171                    // no need to use SAT_8U for updated learnMin[i] & learnMax[i] here,
172                    // as the bounding li & hi are already within 0..255.
173                    if( e->learnMin[0] > l0 ) e->learnMin[0]--;
174                    if( e->learnMax[0] < h0 ) e->learnMax[0]++;
175                    if( e->learnMin[1] > l1 ) e->learnMin[1]--;
176                    if( e->learnMax[1] < h1 ) e->learnMax[1]++;
177                    if( e->learnMin[2] > l2 ) e->learnMin[2]--;
178                    if( e->learnMax[2] < h2 ) e->learnMax[2]++;
179
180                    found = e;
181                    break;
182                }
183                negRun = T - e->tLastUpdate;
184                e->stale = MAX( e->stale, negRun );
185            }
186
187            for( ; e != 0; e = e->next )
188            {
189                negRun = T - e->tLastUpdate;
190                e->stale = MAX( e->stale, negRun );
191            }
192
193            if( !found )
194            {
195                if( !freeList )
196                {
197                    freeList = (CvBGCodeBookElem*)cvMemStorageAlloc(model->storage,
198                        nblocks*sizeof(*freeList));
199                    for( i = 0; i < nblocks-1; i++ )
200                        freeList[i].next = &freeList[i+1];
201                    freeList[nblocks-1].next = 0;
202                }
203                e = freeList;
204                freeList = freeList->next;
205
206                e->learnMin[0] = l0; e->learnMax[0] = h0;
207                e->learnMin[1] = l1; e->learnMax[1] = h1;
208                e->learnMin[2] = l2; e->learnMax[2] = h2;
209                e->boxMin[0] = e->boxMax[0] = p0;
210                e->boxMin[1] = e->boxMax[1] = p1;
211                e->boxMin[2] = e->boxMax[2] = p2;
212                e->tLastUpdate = T;
213                e->stale = 0;
214                e->next = *cb;
215                *cb = e;
216            }
217        }
218    }
219
220    model->freeList = freeList;
221
222    __END__;
223}
224
225
226int cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* _image,
227                      CvArr* _fgmask, CvRect roi )
228{
229    int maskCount = -1;
230
231    CV_FUNCNAME( "cvBGCodeBookDiff" );
232
233    __BEGIN__;
234
235    CvMat stub, *image = cvGetMat( _image, &stub );
236    CvMat mstub, *mask = cvGetMat( _fgmask, &mstub );
237    int x, y;
238    uchar m0, m1, m2, M0, M1, M2;
239
240    CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
241        image->cols == model->size.width && image->rows == model->size.height &&
242        CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask) );
243
244    if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
245    {
246        roi.width = image->cols;
247        roi.height = image->rows;
248    }
249    else
250        CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols &&
251                   (unsigned)roi.y < (unsigned)image->rows &&
252                   roi.width >= 0 && roi.height >= 0 &&
253                   roi.x + roi.width <= image->cols &&
254                   roi.y + roi.height <= image->rows );
255
256    m0 = model->modMin[0]; M0 = model->modMax[0];
257    m1 = model->modMin[1]; M1 = model->modMax[1];
258    m2 = model->modMin[2]; M2 = model->modMax[2];
259
260    maskCount = roi.height*roi.width;
261    for( y = 0; y < roi.height; y++ )
262    {
263        const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3;
264        uchar* m = mask->data.ptr + mask->step*(y + roi.y) + roi.x;
265        CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x;
266
267        for( x = 0; x < roi.width; x++, p += 3, cb++ )
268        {
269            CvBGCodeBookElem *e;
270            uchar p0 = p[0], p1 = p[1], p2 = p[2];
271            int l0 = p0 + m0, l1 = p1 + m1, l2 = p2 + m2;
272            int h0 = p0 - M0, h1 = p1 - M1, h2 = p2 - M2;
273            m[x] = (uchar)255;
274
275            for( e = *cb; e != 0; e = e->next )
276            {
277                if( e->boxMin[0] <= l0 && h0 <= e->boxMax[0] &&
278                    e->boxMin[1] <= l1 && h1 <= e->boxMax[1] &&
279                    e->boxMin[2] <= l2 && h2 <= e->boxMax[2] )
280                {
281                    m[x] = 0;
282                    maskCount--;
283                    break;
284                }
285            }
286        }
287    }
288
289    __END__;
290
291    return maskCount;
292}
293
294void cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh,
295                             CvRect roi, const CvArr* _mask )
296{
297    CV_FUNCNAME( "cvBGCodeBookClearStale" );
298
299    __BEGIN__;
300
301    CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
302    int x, y, T;
303    CvBGCodeBookElem* freeList;
304
305    CV_ASSERT( model && (!mask || CV_IS_MASK_ARR(mask) &&
306        mask->cols == model->size.width && mask->rows == model->size.height) );
307
308    if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
309    {
310        roi.width = model->size.width;
311        roi.height = model->size.height;
312    }
313    else
314        CV_ASSERT( (unsigned)roi.x < (unsigned)mask->cols &&
315                   (unsigned)roi.y < (unsigned)mask->rows &&
316                   roi.width >= 0 && roi.height >= 0 &&
317                   roi.x + roi.width <= mask->cols &&
318                   roi.y + roi.height <= mask->rows );
319
320    icvInitSatTab();
321    freeList = model->freeList;
322    T = model->t;
323
324    for( y = 0; y < roi.height; y++ )
325    {
326        const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0;
327        CvBGCodeBookElem** cb = model->cbmap + model->size.width*(y + roi.y) + roi.x;
328
329        for( x = 0; x < roi.width; x++, cb++ )
330        {
331            CvBGCodeBookElem *e, first, *prev = &first;
332
333            if( m && m[x] == 0 )
334                continue;
335
336            for( first.next = e = *cb; e != 0; e = prev->next )
337            {
338                if( e->stale > staleThresh )
339                {
340                    prev->next = e->next;
341                    e->next = freeList;
342                    freeList = e;
343                }
344                else
345                {
346                    e->stale = 0;
347                    e->tLastUpdate = T;
348                    prev = e;
349                }
350            }
351
352            *cb = first.next;
353        }
354    }
355
356    model->freeList = freeList;
357
358    __END__;
359}
360
361/* End of file. */
362
363