运动目标检测 之 GMM背景模型算法

综述

单高斯背景建模是一种基于像素样本统计信息的背景表示方法,它是根据视频中的每个像素在时域上的概率统计信息(均值/方差)来构建各个像素的颜色分布模型,依次来达到背景建模的目的。背景建模完成后,使用统计差分进行目标像素判断以达到对前景目标的检测,同时用目标像素不断更新背景模型以实现对动态背景的建模拟合。

混合高斯背景模型是有限个单高斯分布的加权和,它能描述像素的多峰状态,适用于对光照渐变、树木摇摆等复杂背景进行准确建模。所谓多峰状态就是在同一时间段内,由于场景的复杂性某个像素点存在多个背景状态,比如树木摇摆的某个像素点,在树枝覆盖了这个像素点时它的像素点值(R:35,G:45,B:65),在下帧图像中树枝由于风吹没有覆盖这个像素点时它的值为(R:135,G:200,B:35),对这个像素来说它有这两种背景状态,在视频中很多帧图像的时序上来说,这个像素点不停的出现这两种状态,就呈现了一个多峰的背景分布模型。

高斯背景模型中,认为像素之间的颜色信息互不相关,对各像素点的处理都是相互独立的。对于视频图像中的每一个像素点,其值在序列图像中的变化可看作是不断产生像素值的随机过程,即用高斯分布来描述每个像素点的颜色呈现规律(多峰/单峰)。

原理

在混合高斯背景模型维护中,场景中的一个像素值的混合高斯模型我们假设它有K个高斯分布组成,那么在图像中像素j在时刻t取值为 的概率为:

其中表示t时刻像素j的混合高斯模型中第i个高斯分布的权重,满足:
其中
表示 第i个高斯成分的均值
是协方差:,其中是标准差,I是单位矩阵
为高斯概率密度函数:

算法逻辑

1、初始化:取视频第一帧图像中每个像素的值来对各自混合高斯模型中K个单高斯分布的均值赋值,对K个单高斯分布的方差赋值为,对这K个高斯分布权重初始化为

2、在视频流中每帧新图像每个像素值与当前像素的K个单高斯模型逐个进行比较,判断是否与高斯模型的均值的偏差在一定范围内

其中,是标准差的倍数,表示前一时刻,在视频流里就是前一帧

3、如果符合上述公式则这个像素值符合这个单高斯背景要求是某个K个模型中某个单高斯背景点,否则是这个单高斯的前景点

4、如果像素点与某一高斯模式匹配,那么这个高斯模式假设是第i个模式的参数更新如下:


5、如果第二步中没有任何模式匹配,则这个像素对应的K个高斯模式中的最小的被替换,替换的模式的均值为,方差为,权重为

6、跳出模式的遍历循环后,各个模式的权值按如下公式更新,

其中,学习速率,对于匹配的模式不匹配的模式,然后对各模式权重归一化

7、各个模式根据的值降序排列,权重大,标准差小的模式排在前面

8、排序完成后,取前个高斯模型作为整个混合高斯模型的背景分布,要求就是,这个高斯的权重累加起来的和大于一定阈值:

其中:T是人为设定的阈值,k是表示几个高斯模型。

9、结合第3步与第8步,将第3步判断中,如果一个像素相对于第8步中的k个高斯分布来说都是前景点的话,就认为这个像素点是目标检测的目标的一个像素点,将所有这样的像素点组合起来形成前景目标,实现视频目标检测。

算法源码

.h文件

#ifndef OBJDET_INNERHEAD_H
#define OBJDET_INNERHEAD_H

#ifdef __cplusplus
extern "C"{
#endif

#include "ObjDet_Interface.h"

//#define OD_EXE_DSP

#ifdef OD_EXE_DSP

#else
#define OD_VIBE
#endif

#define IN 
#define OUT
#define INOUT


#define OBJ_WH_MIN    32  /*目标宽高最低值*/
#define OBJ_WH_MAX    128 /*目标宽高最大值*/

#define ALIGN_1(a) ((0 == a % 8) ? (a) : (((a + 8)>>3)<<3))
#define ALIGN_2(a) ((0 == a % 16) ? (a) : (((a + 16)>>4)<<4))
#define ALIGN_3(a) ((0 == a % 32) ? (a) : (((a + 32)>>5)<<5))

#define FLTMAX(a, b) ((a > b) ? (a) : (b))
#define FLTMIN(a, b) ((a < b) ? (a) : (b))
#define MEDINCHAR(x) (((x) < 0 ? 0 : ((x) > 255 ? 255 : (x))))

#define SWAP_VALUE(A, B) {int tmpSwap;tmpSwap=A; A=B; B=tmpSwap;}

#define DIFABS(a, b) ((a > b) ? (a - b) : (0))


typedef unsigned char          U8;   
typedef unsigned short         U16; 
typedef unsigned int           U32;
#ifdef CHIP_DM6467
typedef unsigned long long     U64;
#else
typedef unsigned __int64       U64;
#endif

typedef signed char            S8;
typedef signed short           S16;
typedef signed int             S32;
#ifdef CHIP_DM6467
typedef signed long long       S64;
#else
typedef signed __int64         S64;
#endif

typedef float                  FL;
typedef double                 DB;
typedef void                   VD;

typedef unsigned char *         PU8;   
typedef unsigned short *        PU16; 
typedef unsigned int *          PU32;
#ifdef CHIP_DM6467
typedef unsigned long long *    PU64;
#else
typedef unsigned __int64   *    PU64;
#endif

typedef signed char *           PS8;
typedef signed short *          PS16;
typedef signed int *            PS32;
#ifdef CHIP_DM6467
typedef signed long long *      PS64;
#else
typedef signed __int64   *      PS64;
#endif

typedef float *                 PFL;
typedef double *                PDB;
typedef void *                  PVD;


/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^函数结构体定义^^^^^^^^^^^^^^^^^^^^^^*/



/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv函数结构体定义vvvvvvvvvvvvvvvvvvvvvv*/
#ifdef __cplusplus
}
#endif
#endif

.c文件

#ifdef __cplusplus
extern "C"{
#endif

#include "ObjDet_GmmHead.h"


/*****************************************************************************
 函 数 名  : OD_GmmDestroy
 功能描述  : XXXX
 输入参数  : INOUT void **pWorkHandl  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 

 修改历史      :
  1.日    期   : 2015223日
    作    者   : TL_ImgFIlter
    修改内容   : 新生成函数

*****************************************************************************/
S32 OD_GmmDestroy(INOUT void **pWorkHandl)
{
    U8 ucModePtrIdx = 0;

    GMM_InnerInfoS *pstGmmInnerInfo = NULL;

    if(NULL == *pWorkHandl)
    {
        return OD_RLT_NO;
    }

    pstGmmInnerInfo = (GMM_InnerInfoS *)(*pWorkHandl);

    pstGmmInnerInfo->uiGmmFrmNum = 0;

    pstGmmInnerInfo->stGmmAreaPosLTRB.usLftTopPotX = 0;
    pstGmmInnerInfo->stGmmAreaPosLTRB.usLftTopPotY = 0;
    pstGmmInnerInfo->stGmmAreaPosLTRB.usRgtBtmPotX = 0;
    pstGmmInnerInfo->stGmmAreaPosLTRB.usRgtBtmPotY = 0;

    pstGmmInnerInfo->usGmmImgWth = 0;
    pstGmmInnerInfo->usGmmImgHgt = 0;
    pstGmmInnerInfo->usGmmImgStp = 0;
    pstGmmInnerInfo->ucGmmImgChn = 0;

    if(NULL != pstGmmInnerInfo->pucModeNum)
    {
        free(pstGmmInnerInfo->pucModeNum);
        pstGmmInnerInfo->pucModeNum = NULL;
    }

    if(NULL != pstGmmInnerInfo->pucRsltImg)
    {
        free(pstGmmInnerInfo->pucRsltImg);
        pstGmmInnerInfo->pucRsltImg = NULL;
    }

    for(ucModePtrIdx = 0; ucModePtrIdx < GMM_MAX_NUM; ucModePtrIdx++)
    {
        GMM_PixModeS * pstGrmmPixMode = pstGmmInnerInfo->apstGmmModeImg[ucModePtrIdx];

        if(NULL != pstGrmmPixMode)
        {
            free(pstGrmmPixMode); 
            pstGrmmPixMode = NULL;
        }
    }

    free(pstGmmInnerInfo);
    pstGmmInnerInfo = NULL;

    #ifdef GMM_DBG
    if(NULL != pstGmmInnerInfo->pstGmmImgDbg)
    {
        cvReleaseImage(&pstGmmInnerInfo->pstGmmImgDbg);
    }
    cvDestroyWindow("GMM");
    #endif
}

/*****************************************************************************
 函 数 名  : OD_GmmInitInterface
 功能描述  : XXXX
 输入参数  : IN    OD_AreaPotPosS *pstGmmAreaPos  
             IN    unsigned int uiImgWth          
             IN    unsigned int uiImgHgt          
             INOUT void **pWorkHandl              
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 

 修改历史      :
  1.日    期   : 2015223日
    作    者   : TL_ImgFIlter
    修改内容   : 新生成函数

*****************************************************************************/
S32 OD_GmmInitInterface(IN    OD_AreaPotPosS *pstGmmAreaPos,
                        IN    unsigned int uiImgWth,
                        IN    unsigned int uiImgHgt,
                        INOUT void **pWorkHandl)
{
    S32 iRetOk = OD_RLT_OK;

    #ifndef OD_EXE_DSP
    {
        U8 ucModeIdx = 0;

        U32 uiGmmModeMemSize = 0;

        U16 usAreaGmmLftTopX = pstGmmAreaPos->usLftTopPotX;
        U16 usAreaGmmLftTopY = pstGmmAreaPos->usLftTopPotY;
        U16 usAreaGmmRgtBtmX = pstGmmAreaPos->usRgtBtmPotX;
        U16 usAreaGmmRgtBtmY = pstGmmAreaPos->usRgtBtmPotY;

        GMM_InnerInfoS *pstODGmmInnerS = (GMM_InnerInfoS *)(malloc(sizeof(GMM_InnerInfoS)));

        if(NULL == pstODGmmInnerS)
        {
            return OD_RLT_NO;
        }

        memset(pstODGmmInnerS, 0, sizeof(GMM_InnerInfoS));

        usAreaGmmLftTopX = (0 != usAreaGmmLftTopX%2) ? (usAreaGmmLftTopX-1) : (usAreaGmmLftTopX);
        usAreaGmmLftTopY = (0 != usAreaGmmLftTopY%2) ? (usAreaGmmLftTopY-1) : (usAreaGmmLftTopY);
        usAreaGmmRgtBtmX = (0 != usAreaGmmRgtBtmX%2) ? (usAreaGmmRgtBtmX+1) : (usAreaGmmRgtBtmX);
        usAreaGmmRgtBtmY = (0 != usAreaGmmRgtBtmY%2) ? (usAreaGmmRgtBtmY+1) : (usAreaGmmRgtBtmY);

        usAreaGmmRgtBtmX = (uiImgWth == usAreaGmmRgtBtmX) ? (usAreaGmmRgtBtmX-2) : (usAreaGmmRgtBtmX);
        usAreaGmmRgtBtmY = (uiImgHgt == usAreaGmmRgtBtmY) ? (usAreaGmmRgtBtmY-2) : (usAreaGmmRgtBtmY); 

        pstODGmmInnerS->stGmmAreaPosLTRB.usLftTopPotX = usAreaGmmLftTopX;
        pstODGmmInnerS->stGmmAreaPosLTRB.usLftTopPotY = usAreaGmmLftTopY;
        pstODGmmInnerS->stGmmAreaPosLTRB.usRgtBtmPotX = usAreaGmmRgtBtmX;
        pstODGmmInnerS->stGmmAreaPosLTRB.usRgtBtmPotY = usAreaGmmRgtBtmY;

        /*In Parameter Check*/
        pstODGmmInnerS->usGmmImgWth = DIFABS(usAreaGmmRgtBtmX, usAreaGmmLftTopX);
        pstODGmmInnerS->usGmmImgHgt = DIFABS(usAreaGmmRgtBtmY, usAreaGmmLftTopY);
        pstODGmmInnerS->usGmmImgStp = ALIGN_1(pstODGmmInnerS->usGmmImgWth);

        if(pstODGmmInnerS->usGmmImgWth > OD_AREA_WH_MAX ||
           pstODGmmInnerS->usGmmImgWth < OD_AREA_WH_MIN ||
           pstODGmmInnerS->usGmmImgHgt > OD_AREA_WH_MAX ||
           pstODGmmInnerS->usGmmImgHgt < OD_AREA_WH_MIN)
        {
            printf("GMM_INIT_ERROR_WTH_HGT_WRN:%d %d\n", pstODGmmInnerS->usGmmImgWth, pstODGmmInnerS->usGmmImgHgt);

            /*这里有个销毁函数*/
            iRetOk = OD_GmmDestroy(pstODGmmInnerS);
            if(OD_RLT_NO == iRetOk)
            {
                return iRetOk;
            }

            return OD_RLT_NO;
        }

        pstODGmmInnerS->usGmmWgtThr = 768;    /*设为默认值0.75*1024*/
        pstODGmmInnerS->ucGmmImgChn = 3;      /*设为默认值3*/

        pstODGmmInnerS->pucModeNum = (PU8)(malloc(pstODGmmInnerS->usGmmImgStp*pstODGmmInnerS->usGmmImgHgt*sizeof(U8)));
        if(NULL == pstODGmmInnerS->pucModeNum)
        {
            return OD_RLT_NO;
        }

        pstODGmmInnerS->pucRsltImg = (PU8)(malloc(pstODGmmInnerS->usGmmImgStp*pstODGmmInnerS->usGmmImgHgt*sizeof(U8)*pstODGmmInnerS->ucGmmImgChn));
        if(NULL == pstODGmmInnerS->pucRsltImg)
        {
            return OD_RLT_NO;
        }

        memset(pstODGmmInnerS->pucModeNum, 0, pstODGmmInnerS->usGmmImgStp*pstODGmmInnerS->usGmmImgHgt*sizeof(U8));
        memset(pstODGmmInnerS->pucRsltImg, 0, pstODGmmInnerS->usGmmImgStp*pstODGmmInnerS->usGmmImgHgt*sizeof(U8)*pstODGmmInnerS->ucGmmImgChn);

        uiGmmModeMemSize = (U32)(pstODGmmInnerS->usGmmImgStp * pstODGmmInnerS->usGmmImgHgt * sizeof(GMM_PixModeS));

        for(ucModeIdx = 0; ucModeIdx < GMM_MAX_NUM; ucModeIdx++)
        {
            GMM_PixModeS * pstGrmmPixMode = (GMM_PixModeS *)(malloc(uiGmmModeMemSize));

            if(NULL == pstGrmmPixMode)
            {
                iRetOk = OD_GmmDestroy(pstODGmmInnerS);
                if(OD_RLT_NO == iRetOk)
                {
                    return iRetOk;
                }

                return OD_RLT_NO;
            }

            pstODGmmInnerS->apstGmmModeImg[ucModeIdx] = pstGrmmPixMode;

            memset(pstGrmmPixMode, 0, uiGmmModeMemSize);
        }      

        #ifdef GMM_DBG
        pstODGmmInnerS->pstGmmImgDbg = cvCreateImage(cvSize(pstODGmmInnerS->usGmmImgStp, pstODGmmInnerS->usGmmImgHgt*4), 8, 3);
        if(NULL == pstODGmmInnerS->pstGmmImgDbg)
        {
            return OD_RLT_NO;   
        }        
        #endif

        *pWorkHandl = (void *)(pstODGmmInnerS);
    }
    #else
    {
        /*暂不处理*/
    }
    #endif
}


/*****************************************************************************
 函 数 名  : OD_PixModeHandle
 功能描述  : XXXX
 输入参数  : IN U8 ucRVal                        
             IN U8 ucGVal                        
             IN U8 ucBVal                        
             IN PU8 pucFGFlg                     

 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 

 修改历史      :
  1.日    期   : 2015226日
    作    者   : schao
    修改内容   : 新生成函数

*****************************************************************************/
S32 OD_PixModeHandle(IN U8 ucRVal,
                     IN U8 ucGVal,
                     IN U8 ucBVal,
                     IN PU8 pucPixModeNum,
                     IN U16 usGmmWgtThr,
                     INOUT PU8 pucFGFlg,
                     INOUT GMM_PixModeS **ppstGmmPixMode)
{
    S32 iRetOk = OD_RLT_OK;

    U8 ucModeIdx = 0;

    U8 ucBGFixFlg = GMM_CATCH_N;     /*用来判断是否找到当前点所匹配的模式*/
    U8 ucBGFGFlag = GMM_FG_FLG;      /*用来判断当前点是前景点还是背景点*/

    U8 ucModeR = 0;
    U8 ucModeG = 0;
    U8 ucModeB = 0;
    U16 usTmpModeWgt = 0;
    U16 usTmpModeVar = 0;

    S16 sModeUpdSpeed = 256;   /*归一化到[0, 1024]*/
    S16 sModeOppSpeed = 768;

    S16 sTmpVal = 0;

    U8  ucModeNum     = *pucPixModeNum;

    U16 usModeBgWgtSum  = 0;
    U8  ucModeBgNum     = 0;

    GMM_PixModeS stTmpGmmPixMode;

    GMM_PixModeS *pstGmmPixMode = NULL;

    for(ucModeIdx = 0; ucModeIdx < ucModeNum; ucModeIdx++)
    {
        pstGmmPixMode = (GMM_PixModeS *)(ppstGmmPixMode[ucModeIdx]);

        if(usModeBgWgtSum < usGmmWgtThr)
        {
            ucModeBgNum++;
            usModeBgWgtSum += pstGmmPixMode->usModeWht;
        }
        else
        {
            break;   
        }
    }

    for(ucModeIdx = 0; ucModeIdx < ucModeNum; ucModeIdx++)
    {
        pstGmmPixMode = (GMM_PixModeS *)(ppstGmmPixMode[ucModeIdx]);

        ucModeR = pstGmmPixMode->ucMValChn0;
        ucModeG = pstGmmPixMode->ucMValChn1;
        ucModeB = pstGmmPixMode->ucMValChn2;
        usTmpModeWgt = pstGmmPixMode->usModeWht;
        usTmpModeVar = pstGmmPixMode->usModeVar;

        if(GMM_CATCH_N == ucBGFixFlg)
        {
            S16 sRDiff = (S16)(ucRVal) - (S16)(ucModeR);
            S16 sGDiff = (S16)(ucGVal) - (S16)(ucModeG);
            S16 sBDiff = (S16)(ucBVal) - (S16)(ucModeB);

            U16 usRGBDiffMean = (sRDiff*sRDiff + sGDiff*sGDiff + sBDiff*sBDiff) / 3;

            if(usRGBDiffMean < (usTmpModeVar>>1))
            {
                ucBGFixFlg = GMM_CATCH_Y;   /*找到匹配模型*/

                if(ucModeIdx < ucModeBgNum)
                {
                    ucBGFGFlag = GMM_BG_FLG;
                }

                sTmpVal = ((S16)(ucModeR) + (sRDiff*sModeUpdSpeed>>10));
                ucModeR = (U8)((sTmpVal < 0) ? (0) : ((sTmpVal > 255) ? (255) : (sTmpVal)));
                sTmpVal = ((S16)(ucModeG) + (sGDiff*sModeUpdSpeed>>10));
                ucModeG = (U8)((sTmpVal < 0) ? (0) : ((sTmpVal > 255) ? (255) : (sTmpVal)));
                sTmpVal = ((S16)(ucModeB) + (sBDiff*sModeUpdSpeed>>10));
                ucModeB = (U8)((sTmpVal < 0) ? (0) : ((sTmpVal > 255) ? (255) : (sTmpVal)));

                usTmpModeWgt = (U16)((sModeOppSpeed*usTmpModeWgt + sModeUpdSpeed + 512)>>10);

                sTmpVal = (S16)(usTmpModeVar) + (sModeUpdSpeed*((S32)(usRGBDiffMean) - (S32)(usTmpModeVar))>>10);

                usTmpModeVar = (sTmpVal > GMM_VAR_MAX) ? (GMM_VAR_MAX) : ((sTmpVal < GMM_VAR_MIN) ? (GMM_VAR_MIN) : (sTmpVal));

                pstGmmPixMode->ucMValChn0 = ucModeR;
                pstGmmPixMode->ucMValChn1 = ucModeG;
                pstGmmPixMode->ucMValChn2 = ucModeB;
                pstGmmPixMode->usModeWht  = usTmpModeWgt;
                pstGmmPixMode->usModeVar  = usTmpModeVar;
            }
            else
            {
                pstGmmPixMode->usModeWht = ((usTmpModeWgt * sModeOppSpeed + 512)>>10);
            }
        }
        else
        {
            pstGmmPixMode->usModeWht = ((usTmpModeWgt * sModeOppSpeed + 512)>>10);
        }
    }

    /*如果没有匹配的模型*/
    if(GMM_CATCH_N == ucBGFixFlg)
    {
        U16 usModeWgtSum = 0;

        /*如果模型达到最大替换最小*//*如果模型未达则添加新的模型*/
        ucModeNum += (GMM_MAX_NUM == ucModeNum) ? (0) : (1);

        /*给新的模型赋初值*/
        ppstGmmPixMode[ucModeNum-1]->usModeWht = (1 == ucModeNum) ? (1024) : (GMM_INIT_WGT);

        ppstGmmPixMode[ucModeNum-1]->ucMValChn0 = ucRVal;
        ppstGmmPixMode[ucModeNum-1]->ucMValChn1 = ucGVal;
        ppstGmmPixMode[ucModeNum-1]->ucMValChn2 = ucBVal;

        ppstGmmPixMode[ucModeNum-1]->usModeVar = GMM_INIT_VAR;

        /*将权重重新归一化下*/
        for(ucModeIdx = 0; ucModeIdx < ucModeNum; ucModeIdx++)
        {
            usModeWgtSum += ppstGmmPixMode[ucModeIdx]->usModeWht;
        }

        for(ucModeIdx = 0; ucModeIdx < ucModeNum; ucModeIdx++)
        {
            ppstGmmPixMode[ucModeIdx]->usModeWht = (ppstGmmPixMode[ucModeIdx]->usModeWht<<10 + 512)/usModeWgtSum;
        }

        /*从大到小排序*/
        for(ucModeIdx = 0; ucModeIdx < GMM_DIFABS(ucModeNum, 1); ucModeIdx++)
        {
            U8 ucTmpIdx = 0;

            for(ucTmpIdx = ucModeIdx; ucTmpIdx < GMM_DIFABS(ucModeNum, 1); ucTmpIdx++)
            {
                if(ppstGmmPixMode[ucTmpIdx]->usModeWht < ppstGmmPixMode[ucTmpIdx+1]->usModeWht)
                {
                    stTmpGmmPixMode                       = *ppstGmmPixMode[ucTmpIdx]; 
                    *ppstGmmPixMode[ucTmpIdx]             = *ppstGmmPixMode[ucTmpIdx+1];
                    *ppstGmmPixMode[ucTmpIdx+1]           = stTmpGmmPixMode;
                }
            }
        }
    }
    else
    {        
        U16 usModeWgtSum = 0;

        /*根据权重排序,同时归一化权重*/ 
        for(ucModeIdx = 0; ucModeIdx < ucModeNum; ucModeIdx++)
        {
            usModeWgtSum += ppstGmmPixMode[ucModeIdx]->usModeWht;
        }

        for(ucModeIdx = 0; ucModeIdx < ucModeNum; ucModeIdx++)
        {
            ppstGmmPixMode[ucModeIdx]->usModeWht = (ppstGmmPixMode[ucModeIdx]->usModeWht<<10+512)/usModeWgtSum;
        }

        for(ucModeIdx = 0; ucModeIdx < GMM_DIFABS(ucModeNum, 1); ucModeIdx++)
        {
            U8 ucTmpIdx = 0;

            for(ucTmpIdx = ucModeIdx; ucTmpIdx < GMM_DIFABS(ucModeNum, 1); ucTmpIdx++)
            {
                if(ppstGmmPixMode[ucTmpIdx]->usModeWht < ppstGmmPixMode[ucTmpIdx+1]->usModeWht)
                {
                    stTmpGmmPixMode                       = *ppstGmmPixMode[ucTmpIdx]; 
                    *ppstGmmPixMode[ucTmpIdx]             = *ppstGmmPixMode[ucTmpIdx+1];
                    *ppstGmmPixMode[ucTmpIdx+1]           = stTmpGmmPixMode;
                }
            }
        }
    }

    *pucPixModeNum = ucModeNum;

    *pucFGFlg = ucBGFGFlag;

    return iRetOk;
}



/*****************************************************************************
 函 数 名  : OD_RGBBgSub
 功能描述  : XXXX
 输入参数  : pucGmmAllImgRGB  
             usGmmImgWth      
             usGmmImgHgt      
             usGmmImgStp      
             pucGmmFGMask     
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 

 修改历史      :
  1.日    期   : 2015226日
    作    者   : schao
    修改内容   : 新生成函数

*****************************************************************************/
S32 OD_RGBBgSub(IN PU8 pucInpRGBImg,
                IN GMM_PixModeS **ppstGmmPixMode,
                IN PU8 pucImgModeNum,
                IN U16 usGmmWgtThr,
                IN U16 usGmmImgWth,
                IN U16 usGmmImgHgt,
                IN U16 usGmmImgStp,
                OUT PU8 pucGmmFGMask)
{
    S32 iRetOk = OD_RLT_OK;

    U8 ucRVal = 0;
    U8 ucGVal = 0;
    U8 ucBVal = 0;

    U8 ucFGFlg = 0;

    U16 usYIdx = 0;
    U16 usXIdx = 0;

    U32 uiRGBTtlYIdx = 0;
    U32 uiRGBTtlXIdx = 0;

    U32 uiTtlYIdx = 0;
    U32 uiTtlXIdx = 0;

    GMM_PixModeS *apstGmmPixMode[GMM_MAX_NUM] = {NULL, NULL, NULL, NULL};

    PU8 pucPixModeNum = NULL;

    if(NULL == pucInpRGBImg || NULL == pucGmmFGMask)
    {
        return OD_RLT_NO;
    }

    for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
    {
        uiRGBTtlYIdx = usYIdx * usGmmImgStp * 3;
        uiTtlYIdx    = usYIdx * usGmmImgStp;
        for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
        {
            uiRGBTtlXIdx = uiRGBTtlYIdx + usXIdx+ usXIdx+ usXIdx;
            uiTtlXIdx    = uiTtlYIdx + usXIdx;

            ucRVal = pucInpRGBImg[uiRGBTtlXIdx];
            ucGVal = pucInpRGBImg[uiRGBTtlXIdx+1];
            ucBVal = pucInpRGBImg[uiRGBTtlXIdx+2];

            apstGmmPixMode[0] = (GMM_PixModeS *)(ppstGmmPixMode[0]) + uiTtlXIdx;
            apstGmmPixMode[1] = (GMM_PixModeS *)(ppstGmmPixMode[1]) + uiTtlXIdx;
            apstGmmPixMode[2] = (GMM_PixModeS *)(ppstGmmPixMode[2]) + uiTtlXIdx;
            apstGmmPixMode[3] = (GMM_PixModeS *)(ppstGmmPixMode[3]) + uiTtlXIdx;

            pucPixModeNum  = pucImgModeNum + uiTtlXIdx;

            OD_PixModeHandle(ucRVal,
                             ucGVal,
                             ucBVal,
                             pucPixModeNum,
                             usGmmWgtThr,
                             &ucFGFlg,
                             apstGmmPixMode);

            if(GMM_FG_FLG == ucFGFlg)
            {
                pucGmmFGMask[uiRGBTtlXIdx]   = ucRVal;
                pucGmmFGMask[uiRGBTtlXIdx+1] = ucGVal;
                pucGmmFGMask[uiRGBTtlXIdx+2] = ucBVal;
            }
        }
    }

    return iRetOk;
}


/*****************************************************************************
 函 数 名  : OD_GmmWorkInterface
 功能描述  : GMM工作接口函数
 输入参数  : &pvdObjDetHandle          
             pucOri_All_Y              
             pucOri_All_UV             
             stODTShrMem.pucMem        
             stODTShrMem.iMemNotUsed   
             (unsigned int)(usImgWth)  
             (unsigned int)(usImgHgt)  
             (unsigned int)(usImgStp)  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 

 修改历史      :
  1.日    期   : 2015223日
    作    者   : schao
    修改内容   : 新生成函数

*****************************************************************************/
S32 OD_GmmWorkInterface(IN PVD *pvdWorkHandle,
                        IN PU8 pucAllImgY,
                        IN PU8 pucAllImgUV,
                        IN U32 uiFrmNum,
                        IN PU8 pucTmpShrMem,
                        IN U32 uiShrMemNotUsed,
                        IN U32 uiAllImgWth,
                        IN U32 uiAllImgHgt,
                        IN U32 uiAllImgStp)
{
    S32 iRetOk = OD_RLT_NO;

    PU8 pucImgModeNum = NULL;
    PU8 pucRsltImg    = NULL;

    U16 usYIdx = 0;
    U16 usXIdx = 0;

    U16 usGmmImgWth = 0;
    U16 usGmmImgHgt = 0;
    U16 usGmmImgStp = 0;

    U8  ucGmmImgChn = 0;
    U16 usGmmWgtThr = 0;

    U16 usGmmAreaLftTopX = 0;
    U16 usGmmAreaLftTopY = 0;
    U16 usGmmAreaRgtBtmX = 0;
    U16 usGmmAreaRgtBtmY = 0;

    U32 uiOriYTtlIdxY = 0;
    U32 uiOriXTtlIdxY = 0;

    U32 uiOriYTtlIdxUV = 0;
    U32 uiOriXTtlIdxUV = 0;

    U32 uiGmmYTtlIdxRGB = 0;
    U32 uiGmmXTtlIdxRGB = 0;

    PU8 pucGmmAllImgY   = NULL;
    PU8 pucGmmAllImgUV  = NULL;
    PU8 pucGmmAllImgRGB = NULL;

    U32 uiShrMemUsed = 0;

    GMM_InnerInfoS * pstGmmInnerInfo = NULL;
    GMM_PixModeS   **ppstGmmPixMode  = NULL;

    if(NULL == (*pvdWorkHandle))
    {
        return OD_RLT_NO;
    }

    pstGmmInnerInfo = (GMM_InnerInfoS *)(*pvdWorkHandle);

    pucImgModeNum = pstGmmInnerInfo->pucModeNum;
    pucRsltImg    = pstGmmInnerInfo->pucRsltImg;
    usGmmWgtThr  = pstGmmInnerInfo->usGmmWgtThr;

    usGmmImgWth = pstGmmInnerInfo->usGmmImgWth;
    usGmmImgHgt = pstGmmInnerInfo->usGmmImgHgt;
    usGmmImgStp = pstGmmInnerInfo->usGmmImgStp;
    ucGmmImgChn = pstGmmInnerInfo->ucGmmImgChn; 

    usGmmAreaLftTopX = pstGmmInnerInfo->stGmmAreaPosLTRB.usLftTopPotX;
    usGmmAreaLftTopY = pstGmmInnerInfo->stGmmAreaPosLTRB.usLftTopPotY;
    usGmmAreaRgtBtmX = pstGmmInnerInfo->stGmmAreaPosLTRB.usRgtBtmPotX;
    usGmmAreaRgtBtmY = pstGmmInnerInfo->stGmmAreaPosLTRB.usRgtBtmPotY;

    ppstGmmPixMode = pstGmmInnerInfo->apstGmmModeImg;

    if(usGmmImgWth < OD_AREA_WH_MIN ||
       usGmmImgWth > OD_AREA_WH_MAX ||
       usGmmImgHgt < OD_AREA_WH_MIN ||
       usGmmImgHgt > OD_AREA_WH_MAX ||
       usGmmImgWth > usGmmImgStp)
    {
        return  OD_RLT_NO;
    }

    /*分配共享内存*//*加一个内存是否够的判断*/   
    pucGmmAllImgRGB = pucTmpShrMem + uiShrMemUsed;
    uiShrMemUsed   += (usGmmImgStp * usGmmImgHgt) * sizeof(U8) * 3;

    /*YUV转成RGB*/
    pucGmmAllImgY  = pucAllImgY + usGmmAreaLftTopY       * uiAllImgStp +   usGmmAreaLftTopX;
    pucGmmAllImgUV = pucAllImgUV + (usGmmAreaLftTopY>>1) * uiAllImgStp + ((usGmmAreaLftTopX>>1)<<1);
    for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
    {
        uiOriYTtlIdxY   =  usYIdx     *  uiAllImgStp;
        uiOriYTtlIdxUV  = (usYIdx>>1) *  uiAllImgStp;
        uiGmmYTtlIdxRGB =  usYIdx     * (usGmmImgStp*3);
        for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
        {
            S32 iTmp1 = 0;
            S32 iTmp2 = 0;
            S32 iTmp3 = 0;

            S32 iRTmp = 0;
            S32 iGTmp = 0;
            S32 iBTmp = 0;

            uiOriXTtlIdxY   =  uiOriYTtlIdxY   +  usXIdx;
            uiOriXTtlIdxUV  =  uiOriYTtlIdxUV  + ((usXIdx>>1)<<1);
            uiGmmXTtlIdxRGB =  uiGmmYTtlIdxRGB + usXIdx+usXIdx+usXIdx;

            /*--------YUV==YCbCr------*/            
            //R' = 1.164*(Y’-16) + 1.596*(Cr'-128)
            //G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)
            //B' = 1.164*(Y’-16) + 2.017*(Cb'-128)

            iTmp1 = (((S32)(pucGmmAllImgY[uiOriXTtlIdxY])- 16) * 1192);
            iTmp2 = ((S32)(pucGmmAllImgUV[uiOriXTtlIdxUV])   - 128);
            iTmp3 = ((S32)(pucGmmAllImgUV[uiOriXTtlIdxUV+1]) - 128);

            iRTmp = abs((iTmp1 + 1634 * iTmp3 + 512)>>10);
            iGTmp = abs((iTmp1 - 833  * iTmp3 - 401 * iTmp2 + 512)>>10);
            iBTmp = abs((iTmp1 + 2065 * iTmp2 + 512)>>10);

            iRTmp = (iRTmp > 255) ? (255) : (iRTmp);
            iGTmp = (iGTmp > 255) ? (255) : (iGTmp);
            iBTmp = (iBTmp > 255) ? (255) : (iBTmp);

            pucGmmAllImgRGB[uiGmmXTtlIdxRGB]   = (U8)(iRTmp);
            pucGmmAllImgRGB[uiGmmXTtlIdxRGB+1] = (U8)(iGTmp);
            pucGmmAllImgRGB[uiGmmXTtlIdxRGB+2] = (U8)(iBTmp);
        }
    }    

    #if 1
    {
        U16  usYIdx = 0;
        U16  usXIdx = 0;

        char acPreAll[100] = {0};
        char acPreNum[10]  = {0};

        unsigned char *pucTmpTmp = NULL;

        IplImage  *pImgFrmTmpMerge = cvCreateImage(cvSize(usGmmImgWth, usGmmImgHgt), 8, 3);

        for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
        {   
            uiGmmYTtlIdxRGB =  usYIdx * (usGmmImgStp*3);

            for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
            {
                /*--------YUV==YCbCr------*/            
                //R' = 1.164*(Y’-16) + 1.596*(Cr'-128)
                //G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)
                //B' = 1.164*(Y’-16) + 2.017*(Cb'-128)

                //S32 iTmpY = pucTmpTmp[usXIdx];
                //S32 iTmpU = 128;
                //S32 iTmpV = 128;

                //S32 iTmp1 = ((iTmpY- 16)*1192);
                //S32 iTmp2 = (iTmpU - 128);
                //S32 iTmp3 = (iTmpV - 128);

                //S32 iRTmp = ((iTmp1 +  1634*iTmp3 + 512)>>10);
                //S32 iGTmp = ((iTmp1 -  833*iTmp3 - 401*iTmp2 + 512)>>10);
                //S32 iBTmp = ((iTmp1 +  2065*iTmp2 + 512)>>10);

                //iRTmp = (iRTmp < 0) ? (0) : (iRTmp);
                //iGTmp = (iGTmp < 0) ? (0) : (iGTmp);
                //iBTmp = (iBTmp < 0) ? (0) : (iBTmp);

                uiGmmXTtlIdxRGB =  uiGmmYTtlIdxRGB + usXIdx+usXIdx+usXIdx;

                pImgFrmTmpMerge->imageData[usYIdx * pImgFrmTmpMerge->widthStep + usXIdx*3]       = pucGmmAllImgRGB[uiGmmXTtlIdxRGB+2];
                pImgFrmTmpMerge->imageData[usYIdx * pImgFrmTmpMerge->widthStep + usXIdx * 3 + 1] = pucGmmAllImgRGB[uiGmmXTtlIdxRGB+1];
                pImgFrmTmpMerge->imageData[usYIdx * pImgFrmTmpMerge->widthStep + usXIdx * 3 + 2] = pucGmmAllImgRGB[uiGmmXTtlIdxRGB];
            }
        }

        _itoa_s((S32)(uiFrmNum), acPreNum, 10, 10);
        strcpy_s(acPreAll, sizeof(acPreAll), "F:\\Subjects_Codes\\练习代码类\\OD\\ODT_ObjDetTrack\\TestVideo\\Ori");
        strcat_s(acPreAll, sizeof(acPreAll), acPreNum);
        strcat_s(acPreAll, sizeof(acPreAll), ".jpg");

        cvSaveImage(acPreAll, pImgFrmTmpMerge, 0);
    }
    #endif

    memset(pucRsltImg, 0, sizeof(U8)*usGmmImgStp*usGmmImgHgt*ucGmmImgChn);

    OD_RGBBgSub(pucGmmAllImgRGB,
                ppstGmmPixMode,
                pucImgModeNum,
                usGmmWgtThr,
                usGmmImgWth,
                usGmmImgHgt,
                usGmmImgStp,
                pucRsltImg);

    #ifdef GMM_DBG
    {
        int ic = 0;
        U16 usYIdx = 0;
        U16 usXIdx = 0;

        U32 uiYTtlIdx = 0;
        U32 uiXTtlIdx = 0;

        char acPreAll[100] = {0};
        char acPreNum[10]  = {0};

        PS8 pcTmp = pstGmmInnerInfo->pstGmmImgDbg->imageData;

        for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
        {
            uiYTtlIdx = usYIdx*usGmmImgStp;

            for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
            {
                uiXTtlIdx = uiYTtlIdx + usXIdx;

                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+2] = ppstGmmPixMode[0][uiXTtlIdx].ucMValChn0;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+1] = ppstGmmPixMode[0][uiXTtlIdx].ucMValChn1;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+0] = ppstGmmPixMode[0][uiXTtlIdx].ucMValChn2;
            }
        }

        pcTmp = pstGmmInnerInfo->pstGmmImgDbg->imageData+pstGmmInnerInfo->pstGmmImgDbg->widthStep*usGmmImgHgt+0;
        for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
        {
            uiYTtlIdx = usYIdx*usGmmImgStp;

            for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
            {
                uiXTtlIdx = uiYTtlIdx + usXIdx;

                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+2] = ppstGmmPixMode[1][uiXTtlIdx].ucMValChn0;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+1] = ppstGmmPixMode[1][uiXTtlIdx].ucMValChn1;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+0] = ppstGmmPixMode[1][uiXTtlIdx].ucMValChn2;
            }
        }

        pcTmp = pstGmmInnerInfo->pstGmmImgDbg->imageData+pstGmmInnerInfo->pstGmmImgDbg->widthStep*usGmmImgHgt*2+0;
        for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
        {
            uiYTtlIdx = usYIdx*usGmmImgStp;

            for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
            {
                uiXTtlIdx = uiYTtlIdx + usXIdx;

                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+2] = ppstGmmPixMode[2][uiXTtlIdx].ucMValChn0;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+1] = ppstGmmPixMode[2][uiXTtlIdx].ucMValChn1;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+0] = ppstGmmPixMode[2][uiXTtlIdx].ucMValChn2;
            }
        }

        pcTmp = pstGmmInnerInfo->pstGmmImgDbg->imageData+pstGmmInnerInfo->pstGmmImgDbg->widthStep*usGmmImgHgt*3+0;
        for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
        {
            uiYTtlIdx = usYIdx*usGmmImgStp;

            for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
            {
                uiXTtlIdx = uiYTtlIdx + usXIdx;

                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+2] = ppstGmmPixMode[3][uiXTtlIdx].ucMValChn0;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+1] = ppstGmmPixMode[3][uiXTtlIdx].ucMValChn1;
                pcTmp[usYIdx*pstGmmInnerInfo->pstGmmImgDbg->widthStep+usXIdx*3+0] = ppstGmmPixMode[3][uiXTtlIdx].ucMValChn2;
            }
        }

        _itoa_s((S32)(uiFrmNum), acPreNum, 10, 10);
        strcpy_s(acPreAll, sizeof(acPreAll), "F:\\Subjects_Codes\\练习代码类\\OD\\ODT_ObjDetTrack\\TestVideo\\Mod");
        strcat_s(acPreAll, sizeof(acPreAll), acPreNum);
        strcat_s(acPreAll, sizeof(acPreAll), ".jpg");

        cvSaveImage(acPreAll, pstGmmInnerInfo->pstGmmImgDbg, 0);

        /*显示结果图像*/
        cvShowImage("GMM", pstGmmInnerInfo->pstGmmImgDbg);
        ic = cvWaitKey(10);
        //if(27 == ic){break;}
    }
    {
        U16 usYIdx = 0;
        U16 usXIdx = 0;

        U32 uiYTtlIdx = 0;
        U32 uiXTtlIdx = 0;

        char *pcTmp = gpucVibeMaskPtr + guiImgStp*gusLftTopY+gusLftTopX+gusLftTopX+gusLftTopX;

        for(usYIdx = 0; usYIdx < usGmmImgHgt; usYIdx++)
        {
            uiYTtlIdx = usYIdx*usGmmImgStp*3;

            for(usXIdx = 0; usXIdx < usGmmImgWth; usXIdx++)
            {               
                int iRTmp = pucRsltImg[uiYTtlIdx+usXIdx+usXIdx+usXIdx];
                int iGTmp = pucRsltImg[uiYTtlIdx+usXIdx+usXIdx+usXIdx+1];
                int iBTmp = pucRsltImg[uiYTtlIdx+usXIdx+usXIdx+usXIdx+2];

                *(pcTmp + usYIdx*guiImgStp + usXIdx+usXIdx+usXIdx+2) = iRTmp;
                *(pcTmp + usYIdx*guiImgStp + usXIdx+usXIdx+usXIdx+1) = iGTmp;
                *(pcTmp + usYIdx*guiImgStp + usXIdx+usXIdx+usXIdx+0) = iBTmp;
            }
        }
    }
    #endif

    return iRetOk;
}

#ifdef __cplusplus
}
#endif

你可能感兴趣的:(模式识别)