📄 backgroundsubtraction.c
字号:
/**
* @file BackgroundSubtraction.cpp
* @author Gengyu Ma
* @brief
* Background subtraction related functions are implemented here.
*/
#include "backgroundSubtraction.h"
#include "blobDetection_CC.h"
#include <stdlib.h> // for malloc/ free
//////////////////////////////////////////////////////////////////////////
// parameters for shadow detection
//////////////////////////////////////////////////////////////////////////
/** edge with smaller gradient than this is not evaluated */
BYTE SHADOW_MAXGRAD = 24;
/** sharpness bigger than this is considered as object border */
BYTE SHADOW_MAXSHARP = 36;
/** if difference is bigger than this, it can not be shadow */
BYTE SHADOW_MAXDIFF = 128;
/** scene type */
BYTE g_ABSSceneType = GENERAL_SCN;
//////////////////////////////////////////////////////////////////////////
// parameters for blob detection
//////////////////////////////////////////////////////////////////////////
/** minimum reported blob size */
USHORT MIN_BLOB_SIZE = 70;
/** blobs smaller than this is considered as noise */
USHORT MAX_NOISE_SIZE = 16;
//////////////////////////////////////////////////////////////////////
// Global viables for saving models
//////////////////////////////////////////////////////////////////////////
/** number of pixels in one image */
INT g_iABSPixelNum = 0;
/** address of scene model */
INT* g_iaABSPixels = NULL;
/** the sorted scene model, stored by the pointer of each model */
INT** g_lpaABSModel = NULL;
/** the address that point to the total weight of each pixel */
USHORT* g_iaABSTotalWeight = NULL;
//////////////////////////////////////////////////////////////////////////
// General Image information
//////////////////////////////////////////////////////////////////////////
/** image information
* image width, image height, and number of byte at each line */
USHORT g_iImageWidth, g_iImageHeight, g_iImageWStep;
/** index of current frame in a video */
USHORT g_iFrameNum = 0;
//////////////////////////////////////////////////////////////////////////
// parameters at pixel level
//////////////////////////////////////////////////////////////////////////
/** the learning rate for weights (0.0 -> 1.0)
* 1/1024 = 2^-10 */
USHORT alpha = 1024;
/** minimum portion of data accounted for by background (0.0 -> 1.0)
* 11 / 16 */
USHORT bgT = 11;
/** initial weight should be pretty low
* 32 << 10 */
USHORT InitialWeight = 32;
/** initial variance, should be rather high */
USHORT InitialVariance = 12;
/** a vector within <SigmaFactor> standard deviations of a model
* Sigma = 15 / 8 */
INT SigmaM8 = 15;
/** after how long, the foreground is merged into background */
USHORT THEFT_DURARION = 100;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @param input input image
* @param output output image
* @return void
* @author Gengyu Ma
*/
void smoothByMedian(BYTE* input, BYTE *output)
{
USHORT x,y;
USHORT r1,r2,r3;
USHORT w = g_iImageWidth;
USHORT h = g_iImageHeight;
USHORT wstep = g_iImageWStep;
BYTE* srcadd = input;
BYTE* dstadd = output;
BYTE p0,p1,p2,p3,p4,p5,p6,p7,p8;
BYTE *src0,*src1,*src2;
BYTE *dst;
BYTE t;
for (y=0; y<h; y++)
{
src0 = srcadd + wstep*(y-1);
src1 = src0 + wstep;
src2 = src1 + wstep;
if (y==0) src0 = src1;
else if (y==h-1) src2 = src1;
dst = dstadd + wstep*y;
for (x=0; x<w; x++)
{
if (src1[x]<16)
{
dst[x] = src1[x];
continue;
}
r1 = x==0 ? 0:x-1;
r2 = x;
r3 = x==w-1 ? x:x+1;
p0 = src0[r1]; p1 = src0[r2]; p2 = src0[r3];
p3 = src1[r1]; p4 = src1[r2]; p5 = src1[r3];
p6 = src2[r1]; p7 = src2[r2]; p8 = src2[r3];
MINMAXSWAP(p1, p2); MINMAXSWAP(p4, p5);
MINMAXSWAP(p7, p8); MINMAXSWAP(p0, p1);
MINMAXSWAP(p3, p4); MINMAXSWAP(p6, p7);
MINMAXSWAP(p1, p2); MINMAXSWAP(p4, p5);
MINMAXSWAP(p7, p8); MINMAXSWAP(p0, p3);
MINMAXSWAP(p5, p8); MINMAXSWAP(p4, p7);
MINMAXSWAP(p3, p6); MINMAXSWAP(p1, p4);
MINMAXSWAP(p2, p5); MINMAXSWAP(p4, p7);
MINMAXSWAP(p4, p2); MINMAXSWAP(p6, p4);
MINMAXSWAP(p4, p2);
dst[x] = p4;
}
}
}
/**
* @param input input image
* @param output output image
* @return void
* @author Gengyu Ma
*/
void smoothByMedian_Binary(BYTE* input, BYTE *output)
{
LONG pi;
BYTE v1;
BYTE *src0,*src1,*src2;
BYTE *dst;
memset(output, 0, g_iABSPixelNum);
src0 = input;
src1 = src0 + g_iImageWStep;
src2 = src1 + g_iImageWStep;
dst = output + g_iImageWStep;
for (pi=g_iImageWStep; pi<g_iABSPixelNum-g_iImageWStep; pi++)
{
if (src1[0]!=BACKGROUND)
{
v1 = 0;
if (src0[-1]) ++ v1;
if (src0[0]) ++ v1;
if (src0[1]) ++ v1;
if (src1[-1]) ++ v1;
if (src1[0]) ++ v1;
if (src1[1]) ++ v1;
if (src2[-1]) ++ v1;
if (src2[0]) ++ v1;
if (src2[1]) ++ v1;
if (v1>=6) *dst = *src1;
}
++ src0; ++ src1; ++ src2;
++ dst;
}
}
/**
* @param input input image
* @param output output image
* @return void
* @author Gengyu Ma
*/
void smoothUp(BYTE* input, BYTE *output)
{
USHORT x,y;
USHORT w = g_iImageWidth;
USHORT h = g_iImageHeight;
USHORT wstep = g_iImageWStep;
BYTE* srcadd = input;
BYTE* dstadd = output;
USHORT sum = 0;
BYTE *src0,*src1,*src2;
BYTE *dst;
USHORT r1,r2,r3;
for (y=0; y<h; y++)
{
src0 = srcadd + wstep*(y-1);
src1 = src0 + wstep;
src2 = src1 + wstep;
if (y==0) src0 = src1;
else if (y==h-1) src2 = src1;
dst = dstadd + wstep*y;
for (x=0; x<w; x++)
{
if (src1[x]>150)
{
dst[x] = src1[x];
continue;
}
r1 = x==0 ? 0:x-1;
r2 = x;
r3 = x==w-1 ? x:x+1;
sum = src0[r1]; sum += src0[r2]; sum += src0[r3];
sum += src1[r1]; sum += src1[r2]; sum += src1[r3];
sum += src2[r1]; sum += src2[r2]; sum += src2[r3];
dst[x] = (BYTE)((sum+5)/9);
}
}
}
/**
* @param input input image
* @param output output image
* @return void
* @author Gengyu Ma
*/
void smoothDown(BYTE* input, BYTE *output)
{
USHORT x,y;
USHORT w = g_iImageWidth;
USHORT h = g_iImageHeight;
USHORT wstep = g_iImageWStep;
USHORT sum = 0;
BYTE* srcadd = input;
BYTE* dstadd = output;
BYTE *src0,*src1,*src2;
BYTE *dst;
USHORT r1,r2,r3;
for (y=0; y<h; y++)
{
src0 = srcadd + wstep*(y-1);
src1 = src0 + wstep;
src2 = src1 + wstep;
if (y==0) src0 = src1;
else if (y==h-1) src2 = src1;
dst = dstadd + wstep*y;
for (x=0; x<w; x++)
{
if (src1[x]<16)
{
dst[x] = src1[x];
continue;
}
r1 = x==0 ? 0:x-1;
r2 = x;
r3 = x==w-1 ? x:x+1;
sum = src0[r1]; sum += src0[r2]; sum += src0[r3];
sum += src1[r1]; sum += src1[r2]; sum += src1[r3];
sum += src2[r1]; sum += src2[r2]; sum += src2[r3];
dst[x] = (BYTE)((sum+5)/9);
}
}
}
/** Allocate memory for ABS
* @param w width of input image
* @param h height of input image
* @return void
* @author Gengyu Ma
*/
void ABS_Create(USHORT w, USHORT h)
{
INT p;
g_iImageHeight = h;
g_iImageWidth = w;
g_iImageWStep = (w-1)/4 * 4 + 4;
ABS_Release();
g_iABSPixelNum = w * h;
g_iaABSPixels = (INT*)malloc(g_iABSPixelNum*K_MODELS*PMSIZE*4);
g_lpaABSModel = (INT**)malloc(g_iABSPixelNum*K_MODELS*4);
g_iaABSTotalWeight = (USHORT*)malloc(g_iABSPixelNum*sizeof(USHORT));
for (p=0; p<g_iABSPixelNum*K_MODELS; p++)
g_lpaABSModel[p] = g_iaABSPixels + p*PMSIZE;
// set parameters
ABS_SetParameters(SCENE_DEFAULT, 0);
}
/** Set system parameters according to scene type
* @param para scene parameter
* @param value the value of specified parameter
* @return void
* @author Gengyu Ma
*/
void ABS_SetParameters(Scene_Parameter para, INT value)
{
// when scene was set to different type, the duration is reduced.
// thus can smooth the change of scene type
static INT duration_dark = 16;
static INT duration_near = 16;
INT oldvalue;
switch(para) {
case SCENE_BRIGHT_OR_DARK:
oldvalue = (g_ABSSceneType & 1) > 0;
if (value==oldvalue) { duration_dark = 16; return; }
else if (duration_dark-- > 0) return;
g_ABSSceneType = g_ABSSceneType ^ 1;
duration_dark = 16;
break;
case SCENE_FAR_OR_NEAR:
oldvalue = (g_ABSSceneType & 2) > 0;
if (value==oldvalue) { duration_near = 16; return; }
else if (duration_near-- > 0) return;
g_ABSSceneType = g_ABSSceneType ^ 2;
duration_near = 16;
break;
case SCENE_BLOB_SIZE:
if (value>400 && MIN_BLOB_SIZE<90)
MIN_BLOB_SIZE++;
else if (value<32 && MIN_BLOB_SIZE>60)
MIN_BLOB_SIZE-=2;
return;
case SCENE_DEFAULT:
g_ABSSceneType = GENERAL_SCN;
}
if (g_ABSSceneType==GENERAL_SCN)
{
SHADOW_MAXDIFF = 128;
SHADOW_MAXGRAD = 16;
SHADOW_MAXSHARP= 32;
SigmaM8 = 18;
}
if (g_ABSSceneType & CLOSE_SCN)
{
SHADOW_MAXDIFF = 136;
SHADOW_MAXGRAD = 20;
SHADOW_MAXSHARP= 36;
SigmaM8 = 20;
}
if (g_ABSSceneType & DARK_SCN)
{
SHADOW_MAXDIFF = 8;
SHADOW_MAXGRAD = 12;
SHADOW_MAXSHARP= 4;
SigmaM8 = 12;
}
}
/** Set system parameters according to scene type
* @param void
* @return void
* @author Gengyu Ma
*/
void ABS_Release()
{
if (g_iaABSPixels) free(g_iaABSPixels);
g_iaABSPixels = NULL;
if (g_lpaABSModel) free(g_lpaABSModel);
g_lpaABSModel = NULL;
if (g_iaABSTotalWeight) free(g_iaABSTotalWeight);
g_iaABSTotalWeight = NULL;
}
/** Update the background model from an image
* @param lpimg the address of image data buffer
* @param updatefactor control the speed of update, bigger value means faster speed
* @return void
* @author Gengyu Ma
*/
void ABS_BackgroundModeling(BYTE *lpimg, BYTE updatefactor)
{
BYTE *p = lpimg;
INT **pmd = g_lpaABSModel;
USHORT *ptw = g_iaABSTotalWeight;
INT i;
for (i=0; i<g_iABSPixelNum; i++)
{
Pixel_ModelUpdate(*p, pmd, ptw, updatefactor);
p ++;
pmd += K_MODELS;
ptw ++;
}
}
/** Evaluate the gradient at every pixel in the background model
* @param edgeimg The gradient of each pixel in the background model
* @return void
* @author Gengyu Ma
*/
void ABS_SceneAnalyze(BYTE* edgeimg)
{
USHORT x,y;
BYTE* edgeadd;
INT** pmd, **pmdadj;
USHORT v1,v2, grad, ming, maxg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -