| /*M/////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
| // |
| // By downloading, copying, installing or using the software you agree to this license. |
| // If you do not agree to this license, do not download, install, |
| // copy or use the software. |
| // |
| // |
| // Intel License Agreement |
| // |
| // Copyright (C) 2000, Intel Corporation, all rights reserved. |
| // Third party copyrights are property of their respective owners. |
| // |
| // Redistribution and use in source and binary forms, with or without modification, |
| // are permitted provided that the following conditions are met: |
| // |
| // * Redistribution's of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // * Redistribution's in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // * The name of Intel Corporation may not be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // This software is provided by the copyright holders and contributors "as is" and |
| // any express or implied warranties, including, but not limited to, the implied |
| // warranties of merchantability and fitness for a particular purpose are disclaimed. |
| // In no event shall the Intel Corporation or contributors be liable for any direct, |
| // indirect, incidental, special, exemplary, or consequential damages |
| // (including, but not limited to, procurement of substitute goods or services; |
| // loss of use, data, or profits; or business interruption) however caused |
| // and on any theory of liability, whether in contract, strict liability, |
| // or tort (including negligence or otherwise) arising in any way out of |
| // the use of this software, even if advised of the possibility of such damage. |
| // |
| //M*/ |
| |
| #include "_cvaux.h" |
| |
| CvBGCodeBookModel* cvCreateBGCodeBookModel() |
| { |
| CvBGCodeBookModel* model = (CvBGCodeBookModel*)cvAlloc( sizeof(*model) ); |
| memset( model, 0, sizeof(*model) ); |
| model->cbBounds[0] = model->cbBounds[1] = model->cbBounds[2] = 10; |
| model->modMin[0] = 3; |
| model->modMax[0] = 10; |
| model->modMin[1] = model->modMin[2] = 1; |
| model->modMax[1] = model->modMax[2] = 1; |
| model->storage = cvCreateMemStorage(); |
| |
| return model; |
| } |
| |
| void cvReleaseBGCodeBookModel( CvBGCodeBookModel** model ) |
| { |
| if( model && *model ) |
| { |
| cvReleaseMemStorage( &(*model)->storage ); |
| memset( *model, 0, sizeof(**model) ); |
| cvFree( model ); |
| } |
| } |
| |
| static uchar satTab8u[768]; |
| #undef SAT_8U |
| #define SAT_8U(x) satTab8u[(x) + 255] |
| |
| static void icvInitSatTab() |
| { |
| static int initialized = 0; |
| if( !initialized ) |
| { |
| for( int i = 0; i < 768; i++ ) |
| { |
| int v = i - 255; |
| satTab8u[i] = (uchar)(v < 0 ? 0 : v > 255 ? 255 : v); |
| } |
| initialized = 1; |
| } |
| } |
| |
| |
| void cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* _image, |
| CvRect roi, const CvArr* _mask ) |
| { |
| CV_FUNCNAME( "cvBGCodeBookUpdate" ); |
| |
| __BEGIN__; |
| |
| CvMat stub, *image = cvGetMat( _image, &stub ); |
| CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0; |
| int i, x, y, T; |
| int nblocks; |
| uchar cb0, cb1, cb2; |
| CvBGCodeBookElem* freeList; |
| |
| CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 && |
| (!mask || CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask)) ); |
| |
| if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 ) |
| { |
| roi.width = image->cols; |
| roi.height = image->rows; |
| } |
| else |
| CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols && |
| (unsigned)roi.y < (unsigned)image->rows && |
| roi.width >= 0 && roi.height >= 0 && |
| roi.x + roi.width <= image->cols && |
| roi.y + roi.height <= image->rows ); |
| |
| if( image->cols != model->size.width || image->rows != model->size.height ) |
| { |
| cvClearMemStorage( model->storage ); |
| model->freeList = 0; |
| cvFree( &model->cbmap ); |
| int bufSz = image->cols*image->rows*sizeof(model->cbmap[0]); |
| model->cbmap = (CvBGCodeBookElem**)cvAlloc(bufSz); |
| memset( model->cbmap, 0, bufSz ); |
| model->size = cvSize(image->cols, image->rows); |
| } |
| |
| icvInitSatTab(); |
| |
| cb0 = model->cbBounds[0]; |
| cb1 = model->cbBounds[1]; |
| cb2 = model->cbBounds[2]; |
| |
| T = ++model->t; |
| freeList = model->freeList; |
| nblocks = (int)((model->storage->block_size - sizeof(CvMemBlock))/sizeof(*freeList)); |
| nblocks = MIN( nblocks, 1024 ); |
| CV_ASSERT( nblocks > 0 ); |
| |
| for( y = 0; y < roi.height; y++ ) |
| { |
| const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3; |
| const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0; |
| CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x; |
| |
| for( x = 0; x < roi.width; x++, p += 3, cb++ ) |
| { |
| CvBGCodeBookElem *e, *found = 0; |
| uchar p0, p1, p2, l0, l1, l2, h0, h1, h2; |
| int negRun; |
| |
| if( m && m[x] == 0 ) |
| continue; |
| |
| p0 = p[0]; p1 = p[1]; p2 = p[2]; |
| l0 = SAT_8U(p0 - cb0); l1 = SAT_8U(p1 - cb1); l2 = SAT_8U(p2 - cb2); |
| h0 = SAT_8U(p0 + cb0); h1 = SAT_8U(p1 + cb1); h2 = SAT_8U(p2 + cb2); |
| |
| for( e = *cb; e != 0; e = e->next ) |
| { |
| if( e->learnMin[0] <= p0 && p0 <= e->learnMax[0] && |
| e->learnMin[1] <= p1 && p1 <= e->learnMax[1] && |
| e->learnMin[2] <= p2 && p2 <= e->learnMax[2] ) |
| { |
| e->tLastUpdate = T; |
| e->boxMin[0] = MIN(e->boxMin[0], p0); |
| e->boxMax[0] = MAX(e->boxMax[0], p0); |
| e->boxMin[1] = MIN(e->boxMin[1], p1); |
| e->boxMax[1] = MAX(e->boxMax[1], p1); |
| e->boxMin[2] = MIN(e->boxMin[2], p2); |
| e->boxMax[2] = MAX(e->boxMax[2], p2); |
| |
| // no need to use SAT_8U for updated learnMin[i] & learnMax[i] here, |
| // as the bounding li & hi are already within 0..255. |
| if( e->learnMin[0] > l0 ) e->learnMin[0]--; |
| if( e->learnMax[0] < h0 ) e->learnMax[0]++; |
| if( e->learnMin[1] > l1 ) e->learnMin[1]--; |
| if( e->learnMax[1] < h1 ) e->learnMax[1]++; |
| if( e->learnMin[2] > l2 ) e->learnMin[2]--; |
| if( e->learnMax[2] < h2 ) e->learnMax[2]++; |
| |
| found = e; |
| break; |
| } |
| negRun = T - e->tLastUpdate; |
| e->stale = MAX( e->stale, negRun ); |
| } |
| |
| for( ; e != 0; e = e->next ) |
| { |
| negRun = T - e->tLastUpdate; |
| e->stale = MAX( e->stale, negRun ); |
| } |
| |
| if( !found ) |
| { |
| if( !freeList ) |
| { |
| freeList = (CvBGCodeBookElem*)cvMemStorageAlloc(model->storage, |
| nblocks*sizeof(*freeList)); |
| for( i = 0; i < nblocks-1; i++ ) |
| freeList[i].next = &freeList[i+1]; |
| freeList[nblocks-1].next = 0; |
| } |
| e = freeList; |
| freeList = freeList->next; |
| |
| e->learnMin[0] = l0; e->learnMax[0] = h0; |
| e->learnMin[1] = l1; e->learnMax[1] = h1; |
| e->learnMin[2] = l2; e->learnMax[2] = h2; |
| e->boxMin[0] = e->boxMax[0] = p0; |
| e->boxMin[1] = e->boxMax[1] = p1; |
| e->boxMin[2] = e->boxMax[2] = p2; |
| e->tLastUpdate = T; |
| e->stale = 0; |
| e->next = *cb; |
| *cb = e; |
| } |
| } |
| } |
| |
| model->freeList = freeList; |
| |
| __END__; |
| } |
| |
| |
| int cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* _image, |
| CvArr* _fgmask, CvRect roi ) |
| { |
| int maskCount = -1; |
| |
| CV_FUNCNAME( "cvBGCodeBookDiff" ); |
| |
| __BEGIN__; |
| |
| CvMat stub, *image = cvGetMat( _image, &stub ); |
| CvMat mstub, *mask = cvGetMat( _fgmask, &mstub ); |
| int x, y; |
| uchar m0, m1, m2, M0, M1, M2; |
| |
| CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 && |
| image->cols == model->size.width && image->rows == model->size.height && |
| CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask) ); |
| |
| if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 ) |
| { |
| roi.width = image->cols; |
| roi.height = image->rows; |
| } |
| else |
| CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols && |
| (unsigned)roi.y < (unsigned)image->rows && |
| roi.width >= 0 && roi.height >= 0 && |
| roi.x + roi.width <= image->cols && |
| roi.y + roi.height <= image->rows ); |
| |
| m0 = model->modMin[0]; M0 = model->modMax[0]; |
| m1 = model->modMin[1]; M1 = model->modMax[1]; |
| m2 = model->modMin[2]; M2 = model->modMax[2]; |
| |
| maskCount = roi.height*roi.width; |
| for( y = 0; y < roi.height; y++ ) |
| { |
| const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3; |
| uchar* m = mask->data.ptr + mask->step*(y + roi.y) + roi.x; |
| CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x; |
| |
| for( x = 0; x < roi.width; x++, p += 3, cb++ ) |
| { |
| CvBGCodeBookElem *e; |
| uchar p0 = p[0], p1 = p[1], p2 = p[2]; |
| int l0 = p0 + m0, l1 = p1 + m1, l2 = p2 + m2; |
| int h0 = p0 - M0, h1 = p1 - M1, h2 = p2 - M2; |
| m[x] = (uchar)255; |
| |
| for( e = *cb; e != 0; e = e->next ) |
| { |
| if( e->boxMin[0] <= l0 && h0 <= e->boxMax[0] && |
| e->boxMin[1] <= l1 && h1 <= e->boxMax[1] && |
| e->boxMin[2] <= l2 && h2 <= e->boxMax[2] ) |
| { |
| m[x] = 0; |
| maskCount--; |
| break; |
| } |
| } |
| } |
| } |
| |
| __END__; |
| |
| return maskCount; |
| } |
| |
| void cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh, |
| CvRect roi, const CvArr* _mask ) |
| { |
| CV_FUNCNAME( "cvBGCodeBookClearStale" ); |
| |
| __BEGIN__; |
| |
| CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0; |
| int x, y, T; |
| CvBGCodeBookElem* freeList; |
| |
| CV_ASSERT( model && (!mask || CV_IS_MASK_ARR(mask) && |
| mask->cols == model->size.width && mask->rows == model->size.height) ); |
| |
| if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 ) |
| { |
| roi.width = model->size.width; |
| roi.height = model->size.height; |
| } |
| else |
| CV_ASSERT( (unsigned)roi.x < (unsigned)mask->cols && |
| (unsigned)roi.y < (unsigned)mask->rows && |
| roi.width >= 0 && roi.height >= 0 && |
| roi.x + roi.width <= mask->cols && |
| roi.y + roi.height <= mask->rows ); |
| |
| icvInitSatTab(); |
| freeList = model->freeList; |
| T = model->t; |
| |
| for( y = 0; y < roi.height; y++ ) |
| { |
| const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0; |
| CvBGCodeBookElem** cb = model->cbmap + model->size.width*(y + roi.y) + roi.x; |
| |
| for( x = 0; x < roi.width; x++, cb++ ) |
| { |
| CvBGCodeBookElem *e, first, *prev = &first; |
| |
| if( m && m[x] == 0 ) |
| continue; |
| |
| for( first.next = e = *cb; e != 0; e = prev->next ) |
| { |
| if( e->stale > staleThresh ) |
| { |
| prev->next = e->next; |
| e->next = freeList; |
| freeList = e; |
| } |
| else |
| { |
| e->stale = 0; |
| e->tLastUpdate = T; |
| prev = e; |
| } |
| } |
| |
| *cb = first.next; |
| } |
| } |
| |
| model->freeList = freeList; |
| |
| __END__; |
| } |
| |
| /* End of file. */ |
| |