📄 blobdetection_cc.c
字号:
/**
@file blobDetection_CC.c
@brief implementation of blob detection algorithm for background subtraction (called by abs.c)
@author Magengyu
*/
#include "blobDetection_CC.h"
#include "backgroundSubtraction.h"
#include "../include/ema.h"
#include <stdlib.h> // for malloc, free
extern USHORT g_iImageWidth, g_iImageHeight, g_iImageWStep;
extern BYTE g_ABSSceneType;
extern USHORT MIN_BLOB_SIZE, MAX_NOISE_SIZE;
/** the number of foreground pixels at each vertical line */
LONG* g_iaBlobPixCountH=NULL;
LONG* g_iaBlobPixCountV=NULL;
SHORT *stack_x=NULL, *stack_y=NULL;
#define BLOB_SATCK_SIZE 512
#ifdef __cplusplus
extern "C" {
#endif
/** Allocate memory for Blob detection
* @param w,h the dimension of video to be processed
* @return void
* @author Gengyu Ma
*/
void Blob_Create(USHORT w, USHORT h)
{
Blob_Release();
g_iaBlobPixCountH = (LONG*)malloc(w*sizeof(LONG));
g_iaBlobPixCountV = (LONG*)malloc(h*sizeof(LONG));
stack_x = (SHORT*)malloc(BLOB_SATCK_SIZE*sizeof(SHORT));
stack_y = (SHORT*)malloc(BLOB_SATCK_SIZE*sizeof(SHORT));
}
/** release memory for Blob detection
* @return void
* @author Gengyu Ma
*/
void Blob_Release()
{
if (g_iaBlobPixCountH) free(g_iaBlobPixCountH);
g_iaBlobPixCountH = NULL;
if (g_iaBlobPixCountV) free(g_iaBlobPixCountV);
g_iaBlobPixCountV = NULL;
if (stack_x) free(stack_x);
stack_x = NULL;
if (stack_y) free(stack_y);
stack_y = NULL;
}
/** Scan line filling method
* @param labelimg the label image to be filled
* @param seedx, seedy the coordinate of seed, from where filling starts
* @param box the size and position of this region
* @return number of pixels in this blob
* @author Gengyu Ma
*/
LONG Blob_ScanLineFill(BYTE* labelimg, USHORT seedx, USHORT seedy, EmaRect* box)
{
// count how much foreground and theft pixel in this connecting regions
// forepixnum + theftpixnum = pnum
LONG fore_num, theft_num;
LONG pixnum;
INT stack_ptr = 0;
BYTE *cursrc;
INT displace;
float theft_thresh;
LONG maxheight = 0;
SHORT x,y, xl, xr, ya;
USHORT boxsize;
fore_num = theft_num = 0;
box->left = g_iImageWidth; box->right = 0;
box->top = g_iImageHeight; box->bottom = 0;
memset(g_iaBlobPixCountH, 0, sizeof(LONG)*g_iImageWidth);
stack_x[0] = seedx; stack_y[0] = seedy;
while (stack_ptr>=0)
{
y = stack_y[stack_ptr]; x = stack_x[stack_ptr];
-- stack_ptr;
// find left and right
displace = g_iImageWStep*y + x;
cursrc = labelimg + displace + 1;
xl = x+1;
while (xl>0 && *(cursrc-1)>=GAPFORE)
{
--xl; --cursrc;
*cursrc -= 100;
if ((*cursrc)==FOREGROUND)
{
++ fore_num;
++ g_iaBlobPixCountH[xl];
}
else if ((*cursrc)==THEFT)
{
++ theft_num;
++ g_iaBlobPixCountH[xl];
}
}
xr = x;
cursrc = labelimg + displace;
while (xr<g_iImageWidth-1 && *(cursrc+1)>=GAPFORE)
{
++xr; ++cursrc;
*cursrc -= 100;
if ((*cursrc)==FOREGROUND)
{
++ fore_num;
++ g_iaBlobPixCountH[xr];
}
else if ((*cursrc)==THEFT)
{
++ theft_num;
++ g_iaBlobPixCountH[xr];
}
}
// update box position
box->left = EMA_MIN(box->left, xl);
box->right = EMA_MAX(box->right, xr);
box->top = EMA_MIN(box->top, y);
box->bottom = EMA_MAX(box->bottom, y);
// find above
ya = y-1;
if (ya>=0)
{
displace = g_iImageWStep*ya + xl;
cursrc = labelimg + displace;
for (x=xl; x<=xr; x++)
{
if (*(cursrc)>=GAPFORE && (x==xl || *(cursrc-1)<GAPFORE))
{
++ stack_ptr;
stack_x[stack_ptr] = x;
stack_y[stack_ptr] = ya;
}
++ cursrc;
}
}
// find bellow
ya = y+1;
if (ya<g_iImageHeight)
{
displace = g_iImageWStep*ya + xl;
cursrc = labelimg + displace;
for (x=xl; x<=xr; x++)
{
if (*(cursrc)>=GAPFORE && (x==xl || *(cursrc-1)<GAPFORE))
{
++ stack_ptr;
stack_x[stack_ptr] = x;
stack_y[stack_ptr] = ya;
}
++ cursrc;
}
}
if (stack_ptr>=BLOB_SATCK_SIZE-1) break;
}
box->top += 3; box->bottom -= 3;
++ box->left; -- box->right;
// analyze box
pixnum = fore_num + theft_num;
if (pixnum<MIN_BLOB_SIZE) return pixnum;
maxheight = 0;
for (x=box->left; x<box->right; x++)
maxheight = EMA_MAX(maxheight, g_iaBlobPixCountH[x]);
// determine blob type
if (pixnum<1000) theft_thresh = 1.0f;
else if (pixnum<10000) theft_thresh = 1.7f;
else theft_thresh = 2.5f;
if (theft_num>fore_num*theft_thresh) box->evt = EMA_THEFT;
else box->evt = EMA_NOEVENT;
// shadow removal by shape
if (pixnum>200)
{
xl = box->left;
while (g_iaBlobPixCountH[xl]*3<maxheight*2) xl++;
while (box->left<=xl-maxheight/4
&& g_iaBlobPixCountH[box->left]*2<maxheight)
box->left++;
xr = box->right;
while (g_iaBlobPixCountH[xr]*3<maxheight*2) xr--;
while (box->right>=xr+maxheight/4
&& g_iaBlobPixCountH[box->right]*2<maxheight)
box->right--;
}
// remove blobs with very few foreground pixels in them
boxsize = (box->right-box->left)*(box->bottom-box->top);
if (pixnum>10 && (pixnum+4)<boxsize/5) return -1;
if (pixnum<(box->bottom-box->top)*3) return -1;
if (pixnum<(box->right-box->left)*3) return -1;
return pixnum;
}
/** Scan line filling method
* @param img the label image to be filled
* @param seedx, seedy the coordinate of seed, from where filling starts
* @param box the size and position of this region
* @return number of pixels in this blob
* @author Gengyu Ma
*/
INT Blob_ScanLineFill_Shadow(BYTE* img, USHORT seedx, USHORT seedy, EmaRect* box)
{
typedef struct tag_seed
{
USHORT x;
USHORT y;
USHORT rightlen;
struct tag_seed *next;
}seed;
INT pnum = 0;
// count how much foreground and theft pixel in this connecting regions
// forepixnum + theftpixnum = pnum
UINT forepixnum = 0, theftpixnum = 0;
// calculate how many adjacent pixels are shadow pixels
USHORT shadowborder = 0, totalborder = 0;
seed *head, *p1;
SHORT notshadowpos;
BYTE *cursrc;
INT displace;
float theft_thresh;
LONG maxheight = 0;
USHORT x, nl, nr;
LONG boxsize;
LONG pixnum;
// vertical projection map for strong shadow removal
memset(g_iaBlobPixCountH, 0, g_iImageWidth*sizeof(LONG));
box->left = box->right = seedx;
box->top = box->bottom = seedy;
//init head node
p1 = (seed*) malloc(sizeof(seed));
p1 ->x = seedx;
p1 ->y = seedy;
p1 ->rightlen = 1;
head = p1;
head ->next = NULL;
g_iaBlobPixCountH[p1->x]++;
displace = seedy*g_iImageWidth + seedx;
img[displace]--;
pnum = 1;
if (img[displace]==THEFT) theftpixnum++;
else forepixnum++;
// main loop
while(head!=NULL)
{
SHORT xleft = head->x - 1;
SHORT xright = head->x + head->rightlen;
SHORT xup = xleft;
SHORT yup = head->y - 1;
SHORT xdown = xleft;
SHORT ydown = head->y + 1;
SHORT startx = -1;
SHORT endx = -1;
displace = head->y*g_iImageWidth;
// remove current head
p1 = head;
head = p1->next;
free(p1);
// left pixels
notshadowpos = xleft+1;
cursrc = img + displace + xleft;
while (xleft>=0)
{
if ( *(cursrc)==THEFTPIXEL || *(cursrc)==FOREPIXEL)
{
(*cursrc) --;
g_iaBlobPixCountH[xleft]++;
xleft--;
notshadowpos--;
cursrc--;
pnum++;
if (*cursrc==THEFT) theftpixnum++;
else forepixnum++;
}
else if (*cursrc==GAPFORE)
{
(*cursrc) --;
xleft--;
cursrc--;
}
else
{
totalborder ++;
if (*cursrc==GAPFORE) shadowborder ++;
break;
}
}
xleft ++;
if (box->left>notshadowpos) box->left = notshadowpos;
// right pixels
cursrc = img + displace + xright;
notshadowpos = xright-1;
while (xright<g_iImageWidth)
{
if ( *(cursrc)==THEFTPIXEL || *(cursrc)==FOREPIXEL)
{
(*cursrc) --;
g_iaBlobPixCountH[xright]++;
notshadowpos++;
xright++;
cursrc++;
pnum++;
if (*cursrc==THEFT) theftpixnum++;
else forepixnum++;
}
else if (*cursrc==GAPFORE)
{
(*cursrc) --;
xright++;
cursrc++;
}
else
{
totalborder ++;
if (*cursrc==GAPFORE) shadowborder ++;
break;
}
}
xright --;
if (box->right<notshadowpos) box->right = notshadowpos;
// top line
startx = -1;
endx = -1;
notshadowpos = yup+1;
if (yup>=0)
{
displace = yup*g_iImageWidth + xleft;
cursrc = img + displace;
for (xup=xleft; xup<=xright; xup++)
{
if (*cursrc==BACKGROUND || *cursrc==GAPFORE) totalborder ++;
if (*cursrc==GAPFORE) shadowborder ++;
if (*cursrc==THEFTPIXEL || *cursrc==FOREPIXEL)
{
if (startx<0) startx = xup;
(*cursrc) --;
g_iaBlobPixCountH[xup]++;
pnum++;
if (*cursrc==THEFT) theftpixnum++;
else forepixnum++;
}
else if (*cursrc==GAPFORE)
{
if (startx<0) startx = xup;
(*cursrc) --;
}
else
{
if (startx>=0)
{
endx = xup-1;
p1 = (seed*) malloc(sizeof(seed));
p1 ->x = startx;
p1 ->y = yup;
p1->rightlen = endx-startx+1;
p1 ->next = head;
head = p1;
notshadowpos = yup;
startx = -1;
}
}
cursrc++;
}
}
if (startx>=0)
{
endx = xright;
p1 = (seed*) malloc(sizeof(seed));
p1 ->x = startx;
p1 ->y = yup;
p1->rightlen = endx-startx+1;
p1 ->next = head;
head = p1;
notshadowpos = yup;
startx = -1;
}
if (box->top>yup) box->top = yup;
// bottom line
startx = -1;
endx = -1;
notshadowpos = ydown-1;
if (ydown<g_iImageHeight)
{
displace = ydown*g_iImageWidth + xleft;
cursrc = img + displace;
for (xdown=xleft; xdown<=xright; xdown++)
{
if (*cursrc==BACKGROUND || *cursrc==GAPFORE) totalborder ++;
if (*cursrc==GAPFORE) shadowborder ++;
if (*cursrc==THEFTPIXEL || *cursrc==FOREPIXEL)
{
if (startx<0) startx = xdown;
(*cursrc) --;
g_iaBlobPixCountH[xdown]++;
pnum++;
if (*cursrc==THEFT) theftpixnum++;
else forepixnum++;
}
else if (*cursrc==GAPFORE)
{
if (startx<0) startx = xdown;
(*cursrc) --;
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -