海思多媒体处理平台(MPP)分为:视频输入(VI),视频处理(VPSS),视频编码(VENC),视频解码(VDEC),视频输出(VO)、视频侦测分析(VDA),音频输入(AI),音频输出(AO),音频编码(AENC),音频解码(ADEC),区域管理(REGION)等模块. 这里介绍视频侦测分析(VDA)中的运动检测。
视频侦测分析(The video detection analysis VDA)通过检测视频的亮度变化,得出视频侦测分析结果。VDA 包含运动侦测(motion detection (MD))和遮挡检测(occlusion detection (OD))两种工作模式,视频侦测分析结果也由当前工作模式区分为运动侦测结果和遮挡检测结果:
关于视频遮挡和运动检测的详细参数,可以查看文档《HiMPP V3.0 媒体处理软件开发参考》
在海思官方给的mpp sample中,vda模块的代码它是使用一个h264视频流来模拟数据流。为了测试其准确性,在本文中使用VI中的数据数据流来进行测试。
我使用的是720P摄像头,所以VI输入的分辨率是1280*720;但是vda模块的最大输入分辨率是:960*960;所以在VPSS中我将720P的画面裁减成D1分辨率。VPSS 操作为:
/********************************************************
Function: BIAO_VDA_StartVpss
Description: 开启VPSS
Input: none
OutPut: none
Return: 0: success,none 0:error
Others:
这里对VI输入的视频数据进行裁剪操作
Author: Caibiao Lee
Date: 2020-02-02
*********************************************************/
HI_S32 BIAO_VDA_StartVpss(HI_S32 s32VpssGrpNum, HI_U32 u32VpssChn,PIC_SIZE_E enInputSize,PIC_SIZE_E enOutputSize)
{
HI_S32 i = 0;
HI_S32 s32Ret;
HI_U32 u32Depth;
VPSS_CHN_MODE_S stVpssChnMode;
VPSS_GRP_ATTR_S stGrpAttr;
HI_U32 u32OverlayMask;
VPSS_CROP_INFO_S stCropInfo;
if(PIC_HD720==enInputSize)
{
stGrpAttr.u32MaxW = 1280;
stGrpAttr.u32MaxH = 720;
}else
{
stGrpAttr.u32MaxW = 720;
stGrpAttr.u32MaxH = 576;
}
stGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
stGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;
stGrpAttr.bIeEn = HI_FALSE;
stGrpAttr.bNrEn = HI_FALSE;
stGrpAttr.bHistEn = HI_FALSE;
stGrpAttr.bDciEn = HI_FALSE;
stGrpAttr.bEsEn = HI_FALSE;
for (i = 0; i < s32VpssGrpNum; i++)
{
s32Ret = HI_MPI_VPSS_CreateGrp(i, &stGrpAttr);
if (HI_SUCCESS != s32Ret)
{
printf("creat vpss grp%d fail, s32Ret: 0x%x.\n", i, s32Ret);
return s32Ret;
}
/**输入与输出不一致,开启裁减功能,将图像裁减成输出的分辨率**/
if(enOutputSize!=enInputSize)
{
s32Ret = HI_MPI_VPSS_GetGrpCrop(i, &stCropInfo);
if(s32Ret != HI_SUCCESS)
{
printf("Get Crop %d fail, s32Ret: 0x%x.\n", i, s32Ret);
return s32Ret;
}
stCropInfo.bEnable = 1;
stCropInfo.enCropCoordinate = VPSS_CROP_ABS_COOR;
stCropInfo.stCropRect.s32X = 0;
stCropInfo.stCropRect.s32Y = 0;
if(PIC_D1==enOutputSize)
{
stCropInfo.stCropRect.u32Width = 720;
stCropInfo.stCropRect.u32Height = 576;
}else
{
stCropInfo.stCropRect.u32Width = 368;
stCropInfo.stCropRect.u32Height = 288;
}
s32Ret = HI_MPI_VPSS_SetGrpCrop(i, &stCropInfo);
if(s32Ret != HI_SUCCESS)
{
printf("Set Crop %d fail, s32Ret: 0x%x.\n", i, s32Ret);
return s32Ret;
}
}
s32Ret = HI_MPI_VPSS_EnableChn(i, u32VpssChn);
if (HI_SUCCESS != s32Ret)
{
printf("creat vpss grp%d chnl%d fail, s32Ret: 0x%x.\n", i, u32VpssChn, s32Ret);
return s32Ret;
}
s32Ret = HI_MPI_VPSS_GetChnMode(i, u32VpssChn, &stVpssChnMode);
if (HI_SUCCESS != s32Ret)
{
printf("get vpss grp%d chn%d mode fail, s32Ret: 0x%x.\n", i, u32VpssChn, s32Ret);
return s32Ret;
}
stVpssChnMode.bDouble = HI_FALSE;
stVpssChnMode.enChnMode = VPSS_CHN_MODE_USER;
stVpssChnMode.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
if(PIC_D1==enOutputSize)
{
stVpssChnMode.u32Width = 720;
stVpssChnMode.u32Height = 576;
}else
{
stVpssChnMode.u32Width = 1280;
stVpssChnMode.u32Height = 720;
}
stVpssChnMode.enCompressMode = COMPRESS_MODE_NONE;
s32Ret = HI_MPI_VPSS_SetChnMode(i, u32VpssChn, &stVpssChnMode);
if (HI_SUCCESS != s32Ret)
{
printf("set vpss grp%d chn%d mode fail, s32Ret: 0x%x.\n", i, u32VpssChn, s32Ret);
return s32Ret;
}
s32Ret = HI_MPI_VPSS_StartGrp(i);
if (HI_SUCCESS != s32Ret)
{
printf("start vpss grp%d fail, s32Ret: 0x%x.\n", i, s32Ret);
return s32Ret;
}
u32Depth = 6;
s32Ret = HI_MPI_VPSS_SetDepth(i, u32VpssChn, u32Depth);
if (HI_SUCCESS != s32Ret)
{
printf("HI_MPI_VPSS_SetDepth fail! Grp: %d, Chn: %d! s32Ret: 0x%x.\n", i, u32VpssChn, s32Ret);
return s32Ret;
}
u32OverlayMask = 255;
s32Ret = HI_MPI_VPSS_SetChnOverlay(i, u32VpssChn, u32OverlayMask);
if (HI_SUCCESS != s32Ret)
{
printf("HI_MPI_VPSS_SetChnOverlay fail! Grp: %d, Chn: %d! s32Ret: 0x%x.\n", i, u32VpssChn, s32Ret);
return s32Ret;
}
}
return HI_SUCCESS;
}
视频遮挡整个流程可以按如下进行:
/********************************************************
Function: BIAO_VDA_OD
Description: 开启遮挡检测
Input: none
OutPut: none
Return: 0: success,none 0:error
Others:
绑定关系为: VI->VPSS->vda
Author: Caibiao Lee
Date: 2020-02-02
*********************************************************/
HI_S32 BIAO_VDA_OD(HI_VOID)
{
HI_S32 s32Ret = HI_SUCCESS;
VDA_CHN VdaChn_Od = 1;
SIZE_S stSize;
MPP_CHN_S stSrcChn, stDesChn;
VDEC_SENDPARAM_S stVdesSendPram;
VPSS_GRP_ATTR_S stGrpAttr;
PIC_SIZE_E enSize = PIC_HD720;
PIC_SIZE_E VpssSize = PIC_D1;
VIDEO_NORM_E enNorm = VIDEO_ENCODING_MODE_PAL;
SAMPLE_VI_MODE_E enViMode = SAMPLE_VI_MODE_2_720P;
HI_S32 s32VpssGrpNum;
HI_U32 u32VpssChn;
/*************************************************
step 1: mpp system init.
*************************************************/
s32Ret = BIAO_VDA_SYS_Init(enSize,enNorm);
if (HI_SUCCESS != s32Ret)
{
printf("system init failed! s32Ret: 0x%x.\n", s32Ret);
goto END_0;
}
/******************************************
step 2: start vi dev & chn
******************************************/
s32Ret = SAMPLE_COMM_VI_Start(enViMode, enNorm);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("start vi failed!\n");
goto END_1;
}
/*************************************************
step 3: start vpss group and chn
*************************************************/
s32VpssGrpNum = 1;
u32VpssChn = VPSS_CHN2;
s32Ret = BIAO_VDA_StartVpss(s32VpssGrpNum, u32VpssChn,enSize,VpssSize);
if(HI_SUCCESS != s32Ret)
{
printf("SAMPLE_RGN_StartVpss failed! s32Ret: 0x%x.\n", s32Ret);
goto END_2;
}
/*************************************************
step 4: bind vi and vpss
*************************************************/
stSrcChn.enModId = HI_ID_VIU;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = 0;
stDesChn.enModId = HI_ID_VPSS;
stDesChn.s32DevId = 0;
stDesChn.s32ChnId = u32VpssChn;
s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDesChn);
if(HI_SUCCESS != s32Ret)
{
printf("HI_MPI_SYS_Bind failed! s32Ret: 0x%x.\n", s32Ret);
goto END_3;
}
/*************************************************
step 5: start VDA OD process
*************************************************/
s32Ret = SAMPLE_COMM_SYS_GetPicSize(enNorm, VpssSize, &stSize);
if (HI_SUCCESS != s32Ret)
{
printf("SAMPLE_COMM_SYS_GetPicSize failed! s32Ret: 0x%x.\n", s32Ret);
goto END_4;
}
if (0 != stSize.u32Width % VDA_WIDTH_ALIGN)
{
stSize.u32Width = (stSize.u32Width / VDA_WIDTH_ALIGN + 1) * VDA_WIDTH_ALIGN;
}
if (0 != stSize.u32Height % VDA_HEIGHT_ALIGN)
{
stSize.u32Height = (stSize.u32Height / VDA_HEIGHT_ALIGN + 1) * VDA_HEIGHT_ALIGN;
}
s32Ret = SAMPLE_COMM_VDA_OdStart(VdaChn_Od, u32VpssChn, &stSize);
if (HI_SUCCESS != s32Ret)
{
printf("VDA OD Start failed! s32Ret: 0x%x.\n", s32Ret);
goto END_4;
}
printf("Press any key to stop!");
getchar();
END_4:
SAMPLE_COMM_VDA_OdStop(VdaChn_Od, u32VpssChn);
END_3:
SAMPLE_COMM_VI_UnBindVpss(enViMode);
END_2:
BIAO_VDA_StopVpss(s32VpssGrpNum);
END_1:
SAMPLE_COMM_VI_Stop(enViMode);
END_0:
BIAO_VDA_SYS_Exit();
return s32Ret;
}
使用海思官方默认参数,对输入为D1的实时画面进行检测,不管是视频运动检测还是视频遮挡检测,它的准确度都不高,如果要准确检测,还需要自己进行调试或是使用其它的方式进行检测分析。
本章频测工程可以从「目录与序言」提供的地址去获取
本专栏第一篇文章「目录与序言」列出了专栏的完整目录,按目录顺序阅读,有助于你的理解。