前言:
海思多媒體處理平臺(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))兩種工作模式,視頻偵測分析結果也由當前工作模式區分爲運動偵測結果和遮擋檢測結果:
- 運動偵測(MD)偵測 VDA 通道接收的視頻的運動狀態,並輸出運動偵測結果。包含每幀圖像的宏塊 SAD 值信息、運動區域(OBJ)信息和整幀報警像素個數。
- 遮擋檢測(OD)檢測 VDA 通道接收的視頻是否出現被遮擋現象,並輸出遮擋檢測結果。
關於視頻遮擋和運動檢測的詳細參數,可以查看文檔《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的實時畫面進行檢測,不管是視頻運動檢測還是視頻遮擋檢測,它的準確度都不高,如果要準確檢測,還需要自己進行調試或是使用其它的方式進行檢測分析。
本章頻測工程可以從「目錄與序言」提供的地址去獲取
本專欄第一篇文章「目錄與序言」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解。