关于海思3559A V100芯片IVE算子的总结

您所在的位置:网站首页 海思3559功耗 关于海思3559A V100芯片IVE算子的总结

关于海思3559A V100芯片IVE算子的总结

2024-07-14 07:24| 来源: 网络整理| 查看: 265

hi.jpg

海思3559AV100

关于这颗芯片: http://www.hisilicon.com/-/media/Hisilicon/pdf/Surveillance_mobilecam/Hi3559AV100.pdf

关于海思芯片的简介真是少之又少,海思似乎没有开放官方的销售渠道,所有的购买都需要经过第三方经销商。这倒也可以理解,因为只有一颗芯片没什么用,必须有它配套的驱动板才行。

在实习期间,我有幸接触了3559a这颗最高端的视频芯片。

hisi.png

重要概念

这颗芯片的特点是有独立的nnie硬件和ive硬件,并且支持svp平台编码。在这里我先解释一下这些名词。

Hardware: NNIE: Neural Network Inference Engine DPU: Distributed Processing Unit DSP: Digital Signal Processing IVE: Intelligent Video Engine IVS: Intelligent Video Surveillance Software: SVP: Smart Vision Processing MMP: Media Process Platform 句柄(handle)

用户在调用算子创建任务时,系统会为每个任务分配一个handle,用于标识不同的任务。

及时返回结果标志bInstant

用户在创建某个任务后,希望及时得到该任务完成的信息,则需要在创建该任务时,将bInstant设置为HI_TRUE。否则,如果用户不关心该任务是否完成,建议将bInstant设置为HI_FALSE,这样可以与后续任务组链执行,减少中断次数,提 升性能。

查询(query)

用户根据系统返回的handle,调用HI_MPI_IVE_Query可以查询对应算子任务是否完成。

及时刷cache

IVE 硬件只能从DDR中获取数据。如果用户在调用IVE任务时,访问空间可cache而且CPU曾经访问,为了保证IVE 输入输出数据不被CPU cahce 干扰,此时用户需要调用HI_MPI_SYS_MmzFlushCache 接口刷cache(详细信息请参见《HiMPP Vx.y 媒体处理软件开发参考》),将数据从cache 刷到DDR,以供IVE使用。

跨度(stride)

与图像或二维数据的width 度量一致的量,如图1-1 所示。IVE_IMAGE_S图像数据跨度,表示图像一行以“像素”计算的单元个数,“像素”位宽可以是8bit,16bit等。IVE_DATA_S 二维数据跨度,表示二维数据一行的字节数,即为图1-1 中n=8的情况。 可以将IVE_DATA_S看成一个“像素”用8bit表示的图像,那么跨度即统一表述为图像或二维数据的一行以“像素”计算的单元个数。

算子

我主要使用的是IVE硬件,这颗强悍的图像处理芯片。我用到了如下一些算子:

HI_MPI_IVE_CSC HI_MPI_IVE_Dilate HI_MPI_IVE_Erode HI_MPI_IVE_Thresh HI_MPI_IVE_EqualizeHist HI_MPI_IVE_GMM HI_MPI_IVE_GMM2 HI_MPI_IVE_Resize HI_MPI_IVE_MatchBgModel HI_MPI_IVE_UpdateBgModel HI_MPI_IVE_Query

在调试算子的时候,一定一定要有耐心。稍不留神就会导致整个程序无法运行。我每次调试的时候都是先用windows平台的模拟器模拟编译环境,在windows上调试完成之后再迁移到板子上,用linux编译成可执行文件,放到板子上看结果。我可以很负责任地说,调试一个算子大约需要一个星期的时间。

首先需要明确,windows上的模拟和实际在板子上运行完全不是一回事。一个最明显的区别就是,在windows上完全不需要考虑物理地址的事儿,只要有虚拟地址,windows会自动调用相应的驱动,自动分配地址、自动运算。而在板子上,所有的操作都需要手动完成,从开辟物理地址、刷新物理内存到query函数是否执行完、物理内存释放等等。更要命的是,在板子上没法调试啊!它没有显示器,所有的可视化调试工具全都没用,想调试那就只能看最终的结果,猜测是哪里出的问题。

我使用的第一个算子就是Erode算子。讲道理,在OpenCV里,Erode就是一行代码的事儿啊!可是放在硬件上就完全不是这回事了。其实海思在windows平台上提供了一套完整的模拟库文件,并且为每个算子提供了模拟代码。(如果有需求可以给我发邮件[email protected])然而在这套模拟代码里完全没有照顾多平台运行的事儿,所以几乎也只是个参考意义。在真正使用IVE硬件的时候,为了驱动每一个算子都花了很长时间。接下来我分情况介绍一下这些算子和使用心得吧!

开辟内存

由于需要使用硬件,所以内存的开辟是必不可少的。在海思提供的示例中,开辟内存的函数叫做HI_CreateIveImage,但是该函数并没有考虑到硬件的物理地址。所以我就在此基础上进行了一些更改。在图片的存储过程中,需要特别留意存储的格式。在有些情况下,图像的每一行的像素数需要是32的倍数,如果不是,则需要使用一个特殊的标记来说明,这个标记被称为u32Stride。通常,这个标记会补齐剩余的位数,说明还差多少个像素到32的倍数。通常的计算方法是:

HI_U32 HI_CalcStride(HI_U32 u32Width, HI_U32 u32Align) { HI_U32 u16stride = u32Width + (u32Align - u32Width % u32Align) % u32Align; return u16stride; } 其中`u32Align`表示要补齐的格式,在上述例子中,该值为32. 除此之外,对于每一种图像的格式,开辟内存的方法也是不一样的。在海思硬件中,图像的存储是有专门的说明文档的。受限于保密协议,我不能把图片直接放在这里。我们需要根据不同的存储格式定义不同的开辟内存的方法,比如一张RGB planar格式的图片与一张灰度图,他们的内存肯定是不一样的。 case IVE_IMAGE_TYPE_U8C1:

case IVE_IMAGE_TYPE_S8C1:

{ uiSize = (UINT32)(u32Stride * u32Height); #if defined(WIN32) || defined(X86) pstImage->au64VirAddr[0] = (HI_U64)malloc(uiSize); HI_CHECK_ET_RET(pstImage->au64VirAddr[0], 0, HI_FAILURE); pstImage->au64PhyAddr[0] = (HI_U64)pstImage->au64VirAddr[0]; pstImage->au32Stride[0] = u32Stride; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, u32Width * u32Height); #else iRet = HI_MPI_SYS_MmzAlloc_Cached(&pstImage->au64PhyAddr[0], (void **)&pstImage->au64VirAddr[0], NULL, HI_NULL, uiSize); if (iRet != HI_SUCCESS) { IPC_LOG_ERR(IPC_MAX_CHANNEL_NUM, "failed to malloc image mem (size=%u)\n", uiSize); iRet = IPC_ERRCODE_NOMEM; break; } pstImage->au32Stride[0] = u32Stride; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, u32Width * u32Height); #endif } break; case IVE_IMAGE_TYPE_YUV420SP: { #if defined(WIN32) || defined(X86) pstImage->au64VirAddr[0] = (HI_U64)malloc(u32Stride * u32Height * BGR_CHANNEL_NUM / 2); HI_CHECK_ET_RET(pstImage->au64VirAddr[0], 0, HI_FAILURE); pstImage->au64VirAddr[1] = pstImage->au64VirAddr[0] + u32Stride * u32Height; pstImage->au64PhyAddr[0] = (HI_U64)pstImage->au64VirAddr[0]; pstImage->au64PhyAddr[1] = (HI_U64)pstImage->au64VirAddr[1]; pstImage->au32Stride[0] = u32Stride; pstImage->au32Stride[1] = pstImage->au32Stride[0]; #else uiSize = u32Stride * u32Height * BGR_CHANNEL_NUM / 2; iRet = HI_MPI_SYS_MmzAlloc_Cached(&pstImage->au64PhyAddr[0], (void **)&pstImage->au64VirAddr[0], NULL, HI_NULL, uiSize); if (iRet != HI_SUCCESS) { IPC_LOG_ERR(IPC_MAX_CHANNEL_NUM, "failed to malloc image mem (size=%u)\n", uiSize); iRet = IPC_ERRCODE_NOMEM; break; } pstImage->au64VirAddr[1] = pstImage->au64VirAddr[0] + u32Stride * u32Height; pstImage->au64VirAddr[2] = pstImage->au64VirAddr[1] + 1; pstImage->au64PhyAddr[1] = pstImage->au64PhyAddr[0] + u32Stride * u32Height; pstImage->au64PhyAddr[2] = pstImage->au64PhyAddr[1] + 1; pstImage->au32Stride[0] = u32Stride; pstImage->au32Stride[1] = pstImage->au32Stride[0]; memset((HI_VOID *)pstImage->au64VirAddr[0], 255, uiSize); #endif } case IVE_IMAGE_TYPE_S16C1:

case IVE_IMAGE_TYPE_U16C1:

{ uiSize = (UINT32)(u32Stride * u32Height) * 2; #if defined(WIN32) || defined(X86) pstImage->au64VirAddr[0] = (HI_U64)malloc(uiSize); HI_CHECK_ET_RET(pstImage->au64VirAddr[0], 0, HI_FAILURE); pstImage->au64PhyAddr[0] = (HI_U64)pstImage->au64VirAddr[0]; pstImage->au32Stride[0] = u32Stride; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, uiSize); #else iRet = HI_MPI_SYS_MmzAlloc_Cached(&pstImage->au64PhyAddr[0], (void **)&pstImage->au64VirAddr[0], NULL, HI_NULL, uiSize); pstImage->au32Stride[0] = u32Stride; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, uiSize); if (iRet != HI_SUCCESS) { IPC_LOG_ERR(IPC_MAX_CHANNEL_NUM, "failed to malloc image mem (size=%u)\n", uiSize); iRet = IPC_ERRCODE_NOMEM; break; } #endif }

case IVE_IMAGE_TYPE_U8C3_PACKAGE:

{ uiSize = (UINT32)(u32Stride * u32Height * 3); #if defined(WIN32) || defined(X86) pstImage->au64VirAddr[0] = (HI_U64)malloc(uiSize); HI_CHECK_ET_RET(pstImage->au64VirAddr[0], 0, HI_FAILURE); pstImage->au64VirAddr[1] = pstImage->au64VirAddr[0] + 1; pstImage->au64VirAddr[2] = pstImage->au64VirAddr[1] + 1; pstImage->au64PhyAddr[0] = (HI_U64)pstImage->au64VirAddr[0]; pstImage->au64PhyAddr[1] = (HI_U64)pstImage->au64VirAddr[1]; pstImage->au64PhyAddr[2] = (HI_U64)pstImage->au64VirAddr[2]; pstImage->au32Stride[0] = u32Stride; pstImage->au32Stride[1] = pstImage->au32Stride[0]; pstImage->au32Stride[2] = pstImage->au32Stride[0]; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, uiSize); #else iRet = HI_MPI_SYS_MmzAlloc_Cached(&pstImage->au64PhyAddr[0], (void **)&pstImage->au64VirAddr[0], NULL, HI_NULL, uiSize); if (iRet != HI_SUCCESS) { IPC_LOG_ERR(IPC_MAX_CHANNEL_NUM, "failed to malloc image mem (size=%u)\n", uiSize); iRet = IPC_ERRCODE_NOMEM; break; } pstImage->au64VirAddr[1] = pstImage->au64VirAddr[0] + 1; pstImage->au64VirAddr[2] = pstImage->au64VirAddr[1] + 1; pstImage->au64PhyAddr[1] = pstImage->au64PhyAddr[0] + 1; pstImage->au64PhyAddr[2] = pstImage->au64PhyAddr[1] + 1; pstImage->au32Stride[0] = u32Stride; pstImage->au32Stride[1] = pstImage->au32Stride[0]; pstImage->au32Stride[2] = pstImage->au32Stride[0]; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, uiSize); #endif }

case IVE_IMAGE_TYPE_U8C3_PLANAR:

{ #if defined(WIN32) || defined(X86) pstImage->au64VirAddr[0] = (HI_U64)malloc(u32Stride * u32Height * 3); HI_CHECK_ET_RET(pstImage->au64VirAddr[0], 0, HI_FAILURE); pstImage->au64VirAddr[1] = pstImage->au64VirAddr[0] + u32Stride * u32Height; pstImage->au64VirAddr[2] = pstImage->au64VirAddr[1] + u32Stride * u32Height; pstImage->au64PhyAddr[0] = (HI_U64)pstImage->au64VirAddr[0]; pstImage->au64PhyAddr[1] = (HI_U64)pstImage->au64VirAddr[1]; pstImage->au64PhyAddr[2] = (HI_U64)pstImage->au64VirAddr[2]; pstImage->au32Stride[0] = u32Stride; pstImage->au32Stride[1] = pstImage->au32Stride[0]; pstImage->au32Stride[2] = pstImage->au32Stride[0]; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, uiSize); #else uiSize = (UINT32)u32Stride * u32Height * 3; iRet = HI_MPI_SYS_MmzAlloc_Cached(&pstImage->au64PhyAddr[0], (void **)&pstImage->au64VirAddr[0], NULL, HI_NULL, uiSize); if (iRet != HI_SUCCESS) { IPC_LOG_ERR(IPC_MAX_CHANNEL_NUM, "failed to malloc image mem (size=%u)\n", uiSize); iRet = IPC_ERRCODE_NOMEM; break; } pstImage->au64VirAddr[1] = pstImage->au64VirAddr[0] + u32Stride * u32Height; pstImage->au64VirAddr[2] = pstImage->au64VirAddr[1] + u32Stride * u32Height; pstImage->au64PhyAddr[1] = pstImage->au64PhyAddr[0] + u32Stride * u32Height; pstImage->au64PhyAddr[2] = pstImage->au64PhyAddr[1] + u32Stride * u32Height; pstImage->au32Stride[0] = u32Stride; pstImage->au32Stride[1] = pstImage->au32Stride[0]; pstImage->au32Stride[2] = pstImage->au32Stride[0]; memset((HI_VOID *)pstImage->au64VirAddr[0], 0, uiSize); #endif }

总而言之,就是每次开辟内存的时候都需要注意是否需要使用硬件,如果是在模拟器上运行,则物理地址和虚拟地址为同一个地址就可以了,而如果是在板子上运行,则需要使用海思开辟物cash内存的函数HI_MPI_SYS_MmzAlloc_Cached。在开辟内存之后,还需要根据每种图片储存的格式,把相应的结构指针指向对应的位置。当然,最后的memset不是必须的。海思提供的开辟内存方法接口如下:

/* alloc mmz memory with cache */ HI_S32 HI_MPI_SYS_MmzAlloc_Cached(HI_U64* pu64PhyAddr, HI_VOID** ppVirAddr, const HI_CHAR* pstrMmb, const HI_CHAR* pstrZone, HI_U32 u32Len);

注意!开辟内存之后内存不会主动释放,即使程序异常退出,该内存依然会保留!所以一定要手动释放这部分内存,而且要随用随开辟,用完就删除。对于一张图片来说,如果图片尺寸较大,这些内存占用将是非常可观的。释放函数叫做HI_DestroyIveImage

/****************************************************** 函数名称: HI_DestroyIveImage 函数功能: 创建IVE图像 建立时间: 2020-06-27 修改时间: 建 立 人: 吴子健 修 改 人: ******************************************************/ HI_S32 HI_DestroyIveImage(IVE_IMAGE_S *pstImage) { //printf("HI_DestroyIveImage.. "); //printf("PHY_addr = %x\n", pstImage->au64PhyAddr); HI_CHECK_ET_NULL_RET(pstImage, HI_FAILURE); if (0 != pstImage->au64VirAddr[0]) { #if defined(WIN32) || defined(X86) free((HI_VOID *)pstImage->au64VirAddr[0]); #else HI_MPI_SYS_MmzFree(pstImage->au64PhyAddr[0], (VOID *)pstImage->au64VirAddr[0]); #endif pstImage->au64VirAddr[0] = (uintptr_t)NULL; pstImage->au64PhyAddr[0] = pstImage->au64VirAddr[0]; } return HI_SUCCESS; } - HI_MPI_IVE_CSC

这是一个格式转换的算子。可实现YUV2RGB\YUV2HSV\YUV2LAB\RGB2YUV的色彩空间转换。这个算子是最简单的算子,我认为。需要注意的是,所有内存都需要提前开辟,否则经过CSC算子之后的图像会出现随机的线条,我不知道这是不是我使用的这颗芯片的个例。

在使用这个算子的时候需要使用Query函数判断运算是否完成,如果运算还没完成就去取结果,如果在开辟内存的时候没有memset则会乱码。HI_MPI_SYS_MmzFlushCache也是必要的,这步的目的是把内存变化刷入硬件。

以下例子是利用两次CSC算子把package格式图片转换成planar格式,当然也有其他方法实现转换,只不过在图像尺寸较大的情况下,耗时比这种方法多。

/****************************************************** 函数名称: IPC_Package2Planar_BIG 函数功能: 利用两次CSC算子把package格式图片转换成planar格式 建立时间: 2020-06-27 修改时间: 建 立 人: 吴子健 修 改 人: ******************************************************/ INT32 IPC_Package2Planar_BIG(IVE_IMAGE_S *pstSrcPackage, IVE_IMAGE_S *pstDstPlanar) { HI_S32 iRet; HI_BOOL bFinish, bBlock; bBlock = HI_TRUE; IVE_IMAGE_S stDstExFrame; //CSC算子所需中间变量,需要提前开辟内存,否则出现随机线条 IVE_CSC_CTRL_S stCtrlCSC; IVE_HANDLE hIveHandleCSC_1; IVE_HANDLE hIveHandleCSC_2; stCtrlCSC.enMode = IVE_CSC_MODE_PIC_BT601_RGB2YUV; //这里使用PICTURE转换模式,RGB->YUV iRet = HI_CreateIveImage(&stDstExFrame, IVE_IMAGE_TYPE_YUV420SP, pstSrcPackage->u32Width, pstSrcPackage->u32Height); HI_CHECK_ET_GOTO(iRet, HI_FAILURE, FAILURE); //CSC_1 #if !(defined(WIN32) || defined(X86)) HI_MPI_SYS_MmzFlushCache(pstSrcPackage->au64PhyAddr[0], (void *)pstSrcPackage->au64VirAddr[0], pstSrcPackage->u32Height*pstSrcPackage->au32Stride[0]*3); HI_MPI_SYS_MmzFlushCache(stDstExFrame.au64PhyAddr[0], (void *)stDstExFrame.au64VirAddr[0], stDstExFrame.au32Stride[0]*stDstExFrame.u32Height*3/2); #endif #if defined(WIN32) || defined(HISI) iRet = HI_MPI_IVE_CSC(&hIveHandleCSC_1, pstSrcPackage, &stDstExFrame, &stCtrlCSC, HI_TRUE); HI_CHECK_NET_GOTO_PRT(iRet, HI_SUCCESS, FAILURE, "HI_MPI_IVE_CSC_1 fail %#x\n", iRet); iRet = HI_MPI_IVE_Query(hIveHandleCSC_1, &bFinish, bBlock); HI_CHECK_NET_GOTO_PRT(iRet, HI_SUCCESS, FAILURE, "Query fail %#x\n", iRet); #endif // SAVE_IVE_IMG_BGR(&stDstExFrame, "stDstExFrame.png"); // SAVE_IVE_IMG_BGR(pstSrcPackage, "pstSrcPackage.png"); //CSC_2 #if !(defined(WIN32) || defined(X86)) HI_MPI_SYS_MmzFlushCache(stDstExFrame.au64PhyAddr[0], (void *)stDstExFrame.au64VirAddr[0], stDstExFrame.au32Stride[0] * stDstExFrame.u32Height * 3 / 2); HI_MPI_SYS_MmzFlushCache(pstDstPlanar->au64PhyAddr[0], (void *)pstDstPlanar->au64VirAddr[0], pstDstPlanar->au32Stride[0] * pstDstPlanar->u32Height * 3); #endif #if defined(WIN32) || defined(HISI) stCtrlCSC.enMode = IVE_CSC_MODE_PIC_BT601_YUV2RGB; iRet = HI_MPI_IVE_CSC(&hIveHandleCSC_2, &stDstExFrame, pstDstPlanar, &stCtrlCSC, HI_TRUE); HI_CHECK_NET_GOTO_PRT(iRet, HI_SUCCESS, FAILURE, "HI_MPI_IVE_CSC_2 fail %#x\n", iRet); iRet = HI_MPI_IVE_Query(hIveHandleCSC_2, &bFinish, bBlock); HI_CHECK_NET_GOTO_PRT(iRet, HI_SUCCESS, FAILURE, "Query fail %#x\n", iRet); #endif FAILURE: if (stDstExFrame.au64VirAddr[0] != HI_NULL) { HI_DestroyIveImage(&stDstExFrame); } // SAVE_IVE_IMG_BGR(pstDstPlanar, "pstDstPlanar.png"); return iRet; } - HI_MPI_IVE_Thresh

这个算子和opencv的阈值类似。作用是取一个阈值创建二值化的图像。

/***************************************************************************** * Prototype: HI_MPI_IVE_Thresh * Description : Thresh operation to the input image. * Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task * IVE_SRC_IMAGE_S *pstSrc Input source data. Only the U8C1 input format is supported. * IVE_DST_IMAGE_S *pstDst Output result * IVE_THRESH_CTRL_S*pstThrCtrlControl parameters * HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. * Return Value : HI_SUCCESS: Success;Error codes: Failure. * Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. * The stride must be 16-pixel-aligned. * History: * * 1. Date : 2011-05-16 * Author : * Modification : Created function * 2. Date : 2013-07-23 * Author : * Modification : Modification * *****************************************************************************/ HI_S32 HI_MPI_IVE_Thresh(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, IVE_DST_IMAGE_S *pstDst, IVE_THRESH_CTRL_S *pstThrCtrl, HI_BOOL bInstant);

输入和输出的图像都可以是IVE_IMAGE_TYPE_U8C1格式。我没有尝试过其他格式。

它的控制结构可以这样设定:

stCtrlThresh.enMode = IVE_THRESH_MODE_BINARY; stCtrlThresh.u8MaxVal = 255; stCtrlThresh.u8MinVal = 0; stCtrlThresh.u8LowThr = HI_GenRand(HI_MAX_U8, 0); - HI_MPI_IVE_Dilate

形态学的图像处理常规操作之一,没什么好解释的。pu8Mask是膨胀的mask,中间的点必须是255,其他的点可以是任意值,意思是以中心的点为中心,向外膨胀这么多像素。这里的Flush是非常关键的操作,之前运行失败就是这里的问题。

/****************************************************** 函数名称: IPC_Dilate 函数功能: 海思IVEDilate算法 建立时间: 2020-04-27 修改时间: 建 立 人: 吴子健 修 改 人: ******************************************************/ INT32 IPC_Dilate(Mat &frame) { INT32 iRet = IPC_ERRCODE_OK; // HI_DOUBLE dilatetime[6]={0}; // dilatetime[0] = (HI_DOUBLE)HI_GetTickCount(); HI_S32 s32Ret = HI_SUCCESS; IVE_SRC_IMAGE_S stSrc; IVE_DST_IMAGE_S stDst1; IVE_DST_IMAGE_S stDst2; IVE_DILATE_CTRL_S stCtrlDilate; IVE_THRESH_CTRL_S stCtrlThresh; //IplImage *frametest = NULL; HI_S32 s32Result; HI_U16 u16Width; HI_U16 u16Height; HI_BOOL bFinish, bBlock; bBlock = HI_TRUE; //FILE *fp; IVE_HANDLE handle1, handle2; //HI_DOUBLE dTime; HI_U8 pu8Mask[25] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; memset(&stSrc, 0, sizeof(IVE_SRC_IMAGE_S)); memset(&stDst1, 0, sizeof(IVE_DST_IMAGE_S)); memset(&stDst2, 0, sizeof(IVE_DST_IMAGE_S)); memset(&stCtrlDilate, 0, sizeof(IVE_DILATE_CTRL_S)); memset(&stCtrlThresh, 0, sizeof(IVE_THRESH_CTRL_S)); u16Width = frame.cols; u16Height = frame.rows; Mat DstDilate(frame.rows, frame.cols, CV_8U); //8U //threshold(frame, frame, 170, 255, CV_THRESH_BINARY); s32Result = HI_CreateIveImage(&stSrc, IVE_IMAGE_TYPE_U8C1, u16Width, u16Height); HI_CHECK_NET_GOTO_PRT(s32Result, HI_SUCCESS, FAILURE, "HI_CreateIveImage fail %#x\n", s32Result); s32Result = HI_CreateIveImage(&stDst1, IVE_IMAGE_TYPE_U8C1, u16Width, u16Height); HI_CHECK_NET_GOTO_PRT(s32Result, HI_SUCCESS, FAILURE, "HI_CreateIveImage fail %#x\n", s32Result); s32Result = HI_CreateIveImage(&stDst2, IVE_IMAGE_TYPE_U8C1, u16Width, u16Height); HI_CHECK_NET_GOTO_PRT(s32Result, HI_SUCCESS, FAILURE, "HI_CreateIveImage fail %#x\n", s32Result); // dilatetime[1] = (HI_DOUBLE)HI_GetTickCount(); memcpy((void *)stSrc.au64VirAddr[0], frame.data, (size_t)u16Width * u16Height); #ifndef WIN32 HI_MPI_SYS_MmzFlushCache(stSrc.au64PhyAddr[0], (void *)stSrc.au64VirAddr[0], u16Width * u16Height); #endif // dilatetime[2] = (HI_DOUBLE)HI_GetTickCount(); stCtrlThresh.enMode = IVE_THRESH_MODE_BINARY; stCtrlThresh.u8MaxVal = 255; stCtrlThresh.u8MinVal = 0; stCtrlThresh.u8LowThr = HI_GenRand(HI_MAX_U8, 0); s32Result = HI_MPI_IVE_Thresh(&handle1, &stSrc, &stDst1, &stCtrlThresh, HI_TRUE); // dilatetime[3] = (HI_DOUBLE)HI_GetTickCount(); HI_CHECK_NET_GOTO_PRT(s32Result, HI_SUCCESS, FAILURE, "HI_MPI_IVE_Thresh fail %#x\n", s32Result); memcpy(stCtrlDilate.au8Mask, pu8Mask, sizeof(HI_U8) * 25); s32Result = HI_MPI_IVE_Dilate(&handle2, &stDst1, &stDst2, &stCtrlDilate, HI_TRUE); // dilatetime[4] = (HI_DOUBLE)HI_GetTickCount(); HI_CHECK_NET_GOTO_PRT(s32Result, HI_SUCCESS, FAILURE, "HI_MPI_IVE_Dilate fail %#x\n", s32Result); QUERY: s32Ret = HI_MPI_IVE_Query(handle2, &bFinish, bBlock); HI_CHECK_ET_GOTO(s32Ret, HI_FAILURE, FAILURE); //std::cout pstGmm2Model->stFactor, IVE_IMAGE_TYPE_U16C1, frame.cols, frame.rows); HI_CHECK_NET_GOTO_PRT(s32Ret, HI_SUCCESS, FAILURE, "HI_CreateIveImage fail\n"); //for matched model information s32Ret = HI_CreateIveImage(&pstHandle->pstGmm2Model->stMatchModelInfo, IVE_IMAGE_TYPE_U8C1, frame.cols, frame.rows); HI_CHECK_NET_GOTO_PRT(s32Ret, HI_SUCCESS, FAILURE, "HI_CreateIveImage fail\n"); //for models #if defined(WIN32) || defined(X86) pstHandle->pstGmm2Model->stModel.u32Size = pstHandle->pstGmm2Model->stGMM2Ctrl.u8ModelNum * 12 * frame.cols * frame.rows; pstHandle->pstGmm2Model->stModel.u64VirAddr = (HI_U64)malloc(pstHandle->pstGmm2Model->stModel.u32Size); HI_CHECK_ET_GOTO_PRT(pstHandle->pstGmm2Model->stModel.u64VirAddr, 0, FAILURE, "malloc fail\n"); memset((HI_U8 *)pstHandle->pstGmm2Model->stModel.u64VirAddr, 0, pstHandle->pstGmm2Model->stGMM2Ctrl.u8ModelNum * 12 * frame.cols * frame.rows); pstHandle->pstGmm2Model->stModel.u64PhyAddr = (HI_U64)pstHandle->pstGmm2Model->stModel.u64VirAddr; #else pstHandle->pstGmm2Model->stModel.u32Size = pstHandle->pstGmm2Model->stGMM2Ctrl.u8ModelNum * 12 * pstHandle->pstGmm2Model->stIveImg.u32Width * pstHandle->pstGmm2Model->stIveImg.u32Height; HI_MPI_SYS_MmzAlloc_Cached(&pstHandle->pstGmm2Model->stModel.u64PhyAddr, (void **)&pstHandle->pstGmm2Model->stModel.u64VirAddr, NULL, HI_NULL, pstHandle->pstGmm2Model->stModel.u32Size); HI_CHECK_ET_GOTO_PRT(pstHandle->pstGmm2Model->stModel.u64VirAddr, 0, FAILURE, "malloc fail\n"); memset((HI_U8 *)pstHandle->pstGmm2Model->stModel.u64VirAddr, 0, pstHandle->pstGmm2Model->stGMM2Ctrl.u8ModelNum * 12 * frame.cols * frame.rows); //pstHandle->pstGmm2Model->stModel.u64PhyAddr = (HI_U64)pstHandle->pstGmm2Model->stModel.u64VirAddr; #endif pstHandle->pGmm2Fg = new Mat(frame.size(), CV_8U); pstHandle->ulinit2 = IPC_GetMsTime(); IPC_LOG_ERR(IPC_MAX_CHANNEL_NUM, "frame number = %u, GMM2 Initialization of the backgrounds ... ... Initialization time: %d ms\n", pstHandle->uiDealCountNum, pstHandle->ulinit2 - pstHandle->ulinit1); pstHandle->pstGmm2Model->uiGMM2CurrentNumber = 1; } // aulTime[0] = IPC_GetMsTime(); if (pcvBgBGR == HI_NULL) { pcvBgBGR = cvCreateImage(cvSz, IPL_DEPTH_8U, BGR_CHANNEL_NUM); HI_CHECK_ET_GOTO_PRT(pcvBgBGR, NULL, FAILURE, "cvCreateImage fail\n"); } memcpy((HI_U8 *)pstHandle->pstGmm2Model->stIveImg.au64VirAddr[0], frame.data, frame.cols * frame.rows * 3); #if !(defined(WIN32) || defined(X86)) HI_MPI_SYS_MmzFlushCache(pstHandle->pstGmm2Model->stIveImg.au64PhyAddr[0], (void *)pstHandle->pstGmm2Model->stIveImg.au64VirAddr[0], frame.cols * frame.rows * 3); #endif //To building a stable background model quickly at the begin, some parameters are set specially. if (1 == pstHandle->pstGmm2Model->stGMM2Ctrl.u8ModelNum) { //If the parameter u8ModelNum is set to 1, the parameter u16FreqReduFactor //is usually set to a small value at the first N frames. Here, N = 500. pstHandle->pstGmm2Model->stGMM2Ctrl.u16FreqReduFactor = (pstHandle->pstGmm2Model->uiGMM2CurrentNumber >= N) ? 0xFFA0 : 0xFC00; } else { //If the parameter u8ModelNum is more than 1, the global life mode should be used at the first N frames, //and the parameter u16GlbLifeUpdateFactor is usually set to a big value. Here, N = 500. pstHandle->pstGmm2Model->stGMM2Ctrl.u16GlbLifeUpdateFactor = (pstHandle->pstGmm2Model->uiGMM2CurrentNumber >= N) ? 4 : 0xFFFF / pstHandle->pstGmm2Model->uiGMM2CurrentNumber; } s32Ret = HI_MPI_IVE_GMM2( &hIveHandle, &pstHandle->pstGmm2Model->stIveImg, &pstHandle->pstGmm2Model->stFactor, &pstHandle->pstGmm2Model->stIveFg, &pstHandle->pstGmm2Model->stIveBg, &pstHandle->pstGmm2Model->stMatchModelInfo, &pstHandle->pstGmm2Model->stModel, &pstHandle->pstGmm2Model->stGMM2Ctrl, bInstant); HI_CHECK_NET_GOTO_PRT(s32Ret, HI_SUCCESS, FAILURE, " HI_MPI_IVE_GMM2 fail,Error(%#x)\n", s32Ret); #ifndef WIN32 QUERY: s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, bBlock); HI_CHECK_NET_GOTO_PRT(s32Ret, HI_SUCCESS, FAILURE, " HI_MPI_IVE_Query fail,Error(%#x)\n", s32Ret); //cout pstGmm2Model->stIveFg.au64VirAddr[0], frame.cols * frame.rows); memcpy(pcvBgBGR->imageData, (HI_U8 *)pstHandle->pstGmm2Model->stIveBg.au64VirAddr[0], frame.rows * pstHandle->pstGmm2Model->stIveBg.au32Stride[0] * 3); } else { HI_CHECK_NET_GOTO_PRT(bFinish, 1, QUERY, " Query fail\n"); } //show the results #else memcpy(pstHandle->pGmm2Fg->data, (HI_U8 *)pstHandle->pstGmm2Model->stIveFg.au64VirAddr[0], frame.cols * frame.rows); memcpy(pcvBgBGR->imageData, (HI_U8 *)pstHandle->pstGmm2Model->stIveBg.au64VirAddr[0], frame.rows * pstHandle->pstGmm2Model->stIveBg.au32Stride[0] * 3); #endif // !WIN32 //show the results { if(pstHandle->pPreImage == NULL) { pstHandle->pPreImage = new Mat(frame.rows, frame.cols, CV_8UC3); } Mat frame_bg = Mat(pcvBgBGR); frame_bg.copyTo(*(pstHandle->pPreImage)); } if(pstHandle->pstGmm2Model->uiGMM2CurrentNumberpGmm2Fg); #endif if (pcvBgBGR) { cvReleaseImage(&pcvBgBGR); } // aulTime[1] = IPC_GetMsTime(); medianBlur(*(pstHandle->pGmm2Fg), *(pstHandle->pGmm2Fg), 5); #ifdef WIN32 imshow("medianBlur", *pstHandle->pGmm2Fg); #endif // aulTime[2] = IPC_GetMsTime(); *(pstHandle->pGmm2Fg) = CloseOP(*(pstHandle->pGmm2Fg)); // aulTime[3] = IPC_GetMsTime(); #ifdef WIN32 imshow("CloseOP", *pstHandle->pGmm2Fg); #endif //if (debug) //cout //stIveImg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stIveImg FAILED.\n"); } if (pstHandle->pstGmm2Model->stIveFg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstGmm2Model->stIveFg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stIveFg FAILED.\n"); } if (pstHandle->pstGmm2Model->stIveBg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstGmm2Model->stIveBg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stIveBg FAILED.\n"); } if (pstHandle->pstGmm2Model->stFactor.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstGmm2Model->stFactor); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stFactor FAILED.\n"); } if (pstHandle->pstGmm2Model->stMatchModelInfo.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstGmm2Model->stMatchModelInfo); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stMatchModelInfo FAILED.\n"); } #if defined(WIN32) || defined(X86) if (pstHandle->pstGmm2Model->stModel.u64VirAddr != HI_NULL) { HI_FREE_64(pstHandle->pstGmm2Model->stModel.u64VirAddr); } #else if (pstHandle->pstGmm2Model->stModel.u64VirAddr != HI_NULL) { S32Ret = HI_MPI_SYS_MmzFree(pstHandle->pstGmm2Model->stModel.u64PhyAddr, (VOID *)pstHandle->pstGmm2Model->stModel.u64VirAddr); if (S32Ret != IPC_ERRCODE_OK) { IPC_LOG_ERR(pstHandle->iChannelIndex, "Free stModel FAILED. Error code = %#x \n", S32Ret); } } #endif free(pstHandle->pstBgModel); pstHandle->pstBgModel = NULL; free(pstHandle->pstGmm2Model); pstHandle->pstGmm2Model = NULL; return S32Ret; } - HI_MPI_IVE_Resize

这个算子的作用是实现resize操作,本来opencv就一行代码就能实现的操作,在使用算子的情况下中遇到了前所未有的挑战。主要bug是随机的线条,在图像的上半部分会出现黄色的5个像素宽的随机线条,在图像的下半部分会出现彩色(随机颜色)的1个像素宽的线条。直到现在这个问题还没有从根本解决,只是调整了代码的位置,这个问题就不再出现了。如果有人遇到相似的问题,欢迎探讨!

这个算子的缺点是只能使用planar格式的图片,所以在每次使用的时候还需要注意图片格式。本来使用这个算子的目的是节约时间,然而如果考虑到格式转换,在图片尺寸较小的情况下,节约的时间非常有限。然而如果本来就需要planar格式的图片,这种方法还是非常有效的。纯粹的resize耗时10毫秒以内。 海思提供的Resize接口如下:

/***************************************************************************** * Prototype: HI_MPI_IVE_Resize * Description : Resize. * Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task * IVE_SRC_IMAGE_S astSrc[] The input source.Only the U8C1/U8C3_PLANAR input format is supported. * IVE_DST_IMAGE_S astDst[] Output result.Only the U8C1/U8C3_PLANAR format is supported. * IVE_RESIZE_CTRL_S *pstResizeCtrl Control parameter * HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. * Return Value : HI_SUCCESS: Success;Error codes: Failure. * Spec : The size of the input data ranges from 32x16 pixels to 1920x1080 pixels. * The stride must be 16-pixel-aligned. * History: * * 1. Date : 2015-03-26 * Author : * Modification : Created function * *****************************************************************************/ HI_S32 HI_MPI_IVE_Resize(IVE_HANDLE *pIveHandle,IVE_SRC_IMAGE_S astSrc[], IVE_DST_IMAGE_S astDst[],IVE_RESIZE_CTRL_S *pstResizeCtrl,HI_BOOL bInstant);

这个接口使用起来并不困难,而且例子中有比较完整的代码。我认为该算子的难点在于格式的转换。我花了很多时间测试各种格式转换的方法,力求耗时最小,然而最终的耗时与OpenCV的resize差不多。以下是完整代码:

/****************************************************** 函数名称: IPC_CSC_AND_Resize_Area 函数功能: 海思IVE算子Resize 建立时间: 2020-04-27 修改时间: 建 立 人: 吴子健 修 改 人: ******************************************************/ INT32 IPC_CSC_AND_Resize_Area(const IPC_IMAGE_S *pstImage, IplImage *pstDstColorImg, HI_U16 au16ResizeWidth, HI_U16 au16ResizeHeight, BOOL isplanar) { // HI_DOUBLE resizeTime[8] = { 0 }; IVE_HANDLE hIveHnd; HI_BOOL bFinish, bBlock; bBlock = HI_TRUE; IVE_IMAGE_S astSrc; IVE_IMAGE_S astDst; IVE_RESIZE_CTRL_S stCtrl; HI_S32 iRet; HI_U32 i, j; IVE_IMAGE_S stSrcExFrame; memset(&stSrcExFrame, 0, sizeof(IVE_IMAGE_S)); //1. Load Image use opencv cvLoadImage function IplImage *pstColorImg = NULL; //HI_ASSERT(HI_NULL != pstColorImg); pstColorImg = cvCreateImageHeader(cvSize(pstImage->uiWidth, pstImage->uiHeight), IPL_DEPTH_8U, BGR_CHANNEL_NUM); cvSetData(pstColorImg, (VOID *)pstImage->ulAddr_virt, pstImage->uiWidth * BGR_CHANNEL_NUM); //2.set src iRet = HI_CreateIveImage(&astSrc, IVE_IMAGE_TYPE_U8C3_PLANAR, pstColorImg->width, pstColorImg->height); HI_CHECK_ET_GOTO(iRet, HI_FAILURE, FAILURE); //3. set dst iRet = HI_CreateIveImage(&astDst, IVE_IMAGE_TYPE_U8C3_PLANAR, au16ResizeWidth, au16ResizeHeight); HI_CHECK_ET_GOTO(iRet, HI_FAILURE, FAILURE); //4.set ctrl #if defined(WIN32) || defined(X86) stCtrl.u16Num = 1; stCtrl.stMem.u32Size = 2 * stCtrl.u16Num * sizeof(IVE_IMAGE_FILL_U8C3_PLANAR_S); stCtrl.stMem.u64VirAddr = (HI_U64)malloc(stCtrl.stMem.u32Size); stCtrl.stMem.u64PhyAddr = (HI_U64)stCtrl.stMem.u64VirAddr; stCtrl.enMode = IVE_RESIZE_MODE_AREA; #else stCtrl.u16Num = 1; stCtrl.stMem.u32Size = stCtrl.u16Num * sizeof(IVE_IMAGE_FILL_U8C3_PLANAR_S); iRet = HI_MPI_SYS_MmzAlloc_Cached(&stCtrl.stMem.u64PhyAddr, (void **)&stCtrl.stMem.u64VirAddr, NULL, HI_NULL, stCtrl.stMem.u32Size); HI_CHECK_ET_GOTO(iRet, HI_FAILURE, FAILURE); memset((void *)stCtrl.stMem.u64VirAddr, 0, stCtrl.stMem.u32Size); stCtrl.enMode = IVE_RESIZE_MODE_LINEAR; #endif // resizeTime[0] = (HI_DOUBLE)HI_GetTickCount(); //Change the image format from opencv rgb package to rgb planar #if 1 //test of double CSC //src stSrcExFrame.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE; stSrcExFrame.u32Width = pstImage->uiWidth; stSrcExFrame.u32Height = pstImage->uiHeight; stSrcExFrame.au64PhyAddr[0] = pstImage->ulAddr_phy; stSrcExFrame.au64PhyAddr[1] = stSrcExFrame.au64PhyAddr[0] + 1; stSrcExFrame.au64PhyAddr[2] = stSrcExFrame.au64PhyAddr[1] + 1; stSrcExFrame.au64VirAddr[0] = pstImage->ulAddr_virt; stSrcExFrame.au64VirAddr[1] = stSrcExFrame.au64VirAddr[0] + 1; stSrcExFrame.au64VirAddr[2] = stSrcExFrame.au64VirAddr[1] + 1; stSrcExFrame.au32Stride[0] = pstImage->uiWidth; //要求宽为16倍数 stSrcExFrame.au32Stride[1] = pstImage->uiWidth; stSrcExFrame.au32Stride[2] = pstImage->uiWidth; IPC_Package2Planar_BIG(&stSrcExFrame, &astSrc); //astSrc=stSrcExFrame; // SAVE_IVE_IMG_BGR(&astSrc, "astSrc.png"); #else for (i = 0; i < astSrc.u32Height; i++) { for (j = 0; j < astSrc.u32Width; j++) { *((HI_U8 *)astSrc.au64VirAddr[0] + i * astSrc.au32Stride[0] + j) = pstColorImg->imageData[i * pstColorImg->widthStep + 3 * j]; *((HI_U8 *)astSrc.au64VirAddr[1] + i * astSrc.au32Stride[1] + j) = pstColorImg->imageData[i * pstColorImg->widthStep + 3 * j + 1]; *((HI_U8 *)astSrc.au64VirAddr[2] + i * astSrc.au32Stride[2] + j) = pstColorImg->imageData[i * pstColorImg->widthStep + 3 * j + 2]; } } #endif // resizeTime[1] = (HI_DOUBLE)HI_GetTickCount(); #if !(defined(WIN32) || defined(X86)) HI_MPI_SYS_MmzFlushCache(astSrc.au64PhyAddr[0], (void *)astSrc.au64VirAddr[0], astSrc.u32Width * astSrc.u32Height * 3); HI_MPI_SYS_MmzFlushCache(stCtrl.stMem.u64PhyAddr, (void *)stCtrl.stMem.u64VirAddr, stCtrl.stMem.u32Size); HI_MPI_SYS_MmzFlushCache(astDst.au64PhyAddr[0], (void *)astDst.au64VirAddr[0], astDst.u32Width * astDst.u32Height * 3); #endif // !WIN32 #if defined(WIN32) || defined(HISI) //5.resize // resizeTime[2] = (HI_DOUBLE)HI_GetTickCount(); iRet = HI_MPI_IVE_Resize(&hIveHnd, &astSrc, &astDst, &stCtrl, HI_FALSE); HI_CHECK_NET_GOTO_PRT(iRet, HI_SUCCESS, FAILURE, "HI_MPI_IVE_Resize fail %#x\n", iRet); #endif // resizeTime[3] = (HI_DOUBLE)HI_GetTickCount(); #if !(defined(WIN32) || defined(X86)) iRet = HI_MPI_IVE_Query(hIveHnd, &bFinish, bBlock); HI_CHECK_NET_GOTO_PRT(iRet, HI_SUCCESS, FAILURE, "Query fail\n"); #endif // resizeTime[4] = (HI_DOUBLE)HI_GetTickCount(); if (isplanar == TRUE) { memcpy(pstDstColorImg->imageData, (void *)astDst.au64VirAddr[0], (size_t)au16ResizeWidth * au16ResizeHeight * 3); //cvSaveImage("dst1.png", pstDstColorImg); } else { for (i = 0; i < au16ResizeHeight; i++) { for (j = 0; j < au16ResizeWidth; j++) { pstDstColorImg->imageData[i * pstDstColorImg->widthStep + 3 * j] = *((HI_U8 *)astDst.au64VirAddr[0] + i * astDst.au32Stride[0] + j); pstDstColorImg->imageData[i * pstDstColorImg->widthStep + 3 * j + 1] = *((HI_U8 *)astDst.au64VirAddr[1] + i * astDst.au32Stride[1] + j); pstDstColorImg->imageData[i * pstDstColorImg->widthStep + 3 * j + 2] = *((HI_U8 *)astDst.au64VirAddr[2] + i * astDst.au32Stride[2] + j); } } // cvSaveImage("dst2.png", pstDstColorImg); } // resizeTime[5] = (HI_DOUBLE)HI_GetTickCount(); FAILURE: //6. release cvReleaseImageHeader(&pstColorImg); if (NULL != pstColorImg) cvReleaseImage(&pstColorImg); if (astSrc.au64VirAddr[0] != HI_NULL) { HI_DestroyIveImage(&astSrc); } if (astDst.au64VirAddr[0] != HI_NULL) { HI_DestroyIveImage(&astDst); } #if defined(WIN32) || defined(X86) if (stCtrl.stMem.u64VirAddr != HI_NULL) { HI_FREE_64(stCtrl.stMem.u64VirAddr); } #else if (stCtrl.stMem.u64VirAddr != HI_NULL) { iRet = HI_MPI_SYS_MmzFree(stCtrl.stMem.u64PhyAddr, (VOID *)stCtrl.stMem.u64VirAddr); if (iRet != IPC_ERRCODE_OK) { cout u32FrmChkPeriod = 10; // 背景检查周期 pstHandle->pstBgModel->stThrCtrl.enMode = IVE_THRESH_MODE_MIN_MID_MAX; //,50, 100, 0, 100, 255}; pstHandle->pstBgModel->stThrCtrl.u8LowThr = 20; /*用户定义的阈值,0 stThrCtrl.u8HighThr = 160; /*用户定义的阈值,如果enMode /*则不使用u8HighThr,否则0 pstBgModel->stThrCtrl.u8MidVal = 100; /*三级阈值时的中间值,如果enMode pstBgModel->stThrCtrl.u8MaxVal = 255; /*三级阈值时的最大值*/ pstHandle->pstBgModel->pstStatData = new IVE_DST_MEM_INFO_S(); //malloc pstStatData pstHandle->pstBgModel->stMatchBgModelCtrl.u32CurFrmNum = 0; /*当前帧时间戳,以帧为单位*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u32PreFrmNum = -1; /*前一帧时间戳,以帧为单位*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u16TimeThr = 100; /*潜在的背景替换时间阈值(范围:2到100帧;默认值:20)*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u8DiffThrCrlCoef = 5; /*微分阈值和灰度值之间的相关系数(范围:0到5;默认值:0)*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u8DiffMaxThr = 15; /*最大背景差异阈值(范围:3到15;默认值:6)*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u8DiffMinThr = 9; /*最小背景差异阈值(范围:3到15;默认值:4)*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u8DiffThrInc = 0; /*动态背景差分阈值增量(范围:0到6;默认值:0)*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u8FastLearnRate = 4; /*快速背景学习率(范围:0到4;默认值:2)*/ pstHandle->pstBgModel->stMatchBgModelCtrl.u8DetChgRegion = 1; /*是否检测更改区域(范围:0(否),1(是);默认值:0)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32CurFrmNum = 0; /*当前帧时间戳,以帧为单位*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32PreChkTime = 0; /*上次检查背景状态的时间*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32FrmChkPeriod = 2000; /*背景状态检查周期(范围:0到2000帧;默认值:50)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32InitMinTime = 25; /*背景初始化的最短时间(范围:20到6000帧;默认值:100)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32StyBgMinBlendTime = 6000; /*稳定的背景整合时间最短(范围:20到6000帧;默认值:200)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32StyBgMaxBlendTime = 40000; /*稳定的背景整合时间最长(范围:20到40000帧;默认值:1500)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32DynBgMinBlendTime = 6000; /*动态背景整合最短时间(范围:0到6000帧;默认值:0)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u32StaticDetMinTime = 80; /*静态检测最短时间(范围:20到6000帧;默认值:80)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u16FgMaxFadeTime = 255; /*前景消失的最长时间(范围:1到255秒;默认值:15)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u16BgMaxFadeTime = 255; /*背景消失的最长时间(范围:1到255秒;默认值:60)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8StyBgAccTimeRateThr = 80; /*稳定的后台访问时间比率阈值(范围:10到100;默认值:80)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8ChgBgAccTimeRateThr = 60; /*更改后台访问时间比率阈值(范围:10到100;默认值:60)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8DynBgAccTimeThr = 50; /*动态背景访问时间比率阈值(范围:0到50;默认值:0)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8DynBgDepth = 3; /*动态背景深度(范围:0到3;默认值:3)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8BgEffStaRateThr = 99; /*初始化时的背景状态时间比率阈值(范围:90到100;默认值:90)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8AcceBgLearn = 1; /*是否加速背景学习(范围:0(否),1(是);默认值:0)*/ pstHandle->pstBgModel->stUpdateBgModelCtrl.u8DetChgRegion = 1; /*是否检测更改区域(范围:0(否),1(是);默认值:0)*/ //end init mog return iRet; } 核心代码

这里的写法相对复杂,不过整体逻辑与GMM2类似,只不过这里与背景的匹配、更新背景被独立成两个算子。大体逻辑还是先初始化算法,开辟内存,然后分别做匹配和更新。

/****************************************************** 函数名称: IPC_MoveDet_MOG 函数功能: MOG 算法 建立时间: 2020-06-16 修改时间: 建 立 人: 吴子健 ******************************************************/ INT32 IPC_MoveDet_MOG(IPC_MOVEDET_S* pstHandle, Mat frame_g) { //UINT64 aulTime[4] = {0}; //aulTime[0] = IPC_GetMsTime(); IplImage* pstCvImgGray = NULL; Mat frame_gray; HI_S32 s32Result = IPC_ERRCODE_OK; HI_BOOL bInstant = HI_TRUE; IplImage temp; HI_U32 u32FrameNum = 0; IVE_HANDLE hIveHandle = 0; IplImage* pstCvFg = NULL; IplImage* pstCvBgGray = NULL; CvSize stSize; if (pstHandle->bInit == TRUE) //模型初始化 { pstHandle->ulinit1 = IPC_GetMsTime(); //init mog2 //=========================================================== stSize = cvSize(frame_g.cols, frame_g.rows); pstCvImgGray = cvCreateImage(stSize, IPL_DEPTH_8U, 1); cvtColor(frame_g, frame_gray, CV_BGR2GRAY); IplImage temp = (IplImage)frame_gray; pstCvImgGray = &temp; #ifdef WIN32 pstHandle->pstBgModel->stBgModel.u32Width = sizeof(IVE_BG_MODEL_PIX_S) * frame_gray.cols; pstHandle->pstBgModel->stBgModel.u32Height = frame_gray.rows; pstHandle->pstBgModel->stBgModel.u32Stride = HI_CalcStride(pstHandle->pstBgModel->stBgModel.u32Width, HI_IVE2_STRIDE_ALIGN); pstHandle->pstBgModel->stBgModel.u64VirAddr = (HI_U64)malloc(pstHandle->pstBgModel->stBgModel.u32Stride * frame_gray.rows); memset((HI_VOID*)pstHandle->pstBgModel->stBgModel.u64VirAddr, 0, pstHandle->pstBgModel->stBgModel.u32Stride * frame_gray.rows); pstHandle->pstBgModel->stBgModel.u64PhyAddr = (HI_U32)pstHandle->pstBgModel->stBgModel.u64VirAddr; IPC_LOG_INFO(pstHandle->iChannelIndex, "Creating stBgModel at physical address %x\n", (unsigned int)pstHandle->pstBgModel->stBgModel.u64VirAddr); #else pstHandle->pstBgModel->stBgModel.u32Width = sizeof(IVE_BG_MODEL_PIX_S) * frame_gray.cols; pstHandle->pstBgModel->stBgModel.u32Height = frame_gray.rows; pstHandle->pstBgModel->stBgModel.u32Stride = HI_CalcStride(pstHandle->pstBgModel->stBgModel.u32Width, HI_IVE2_STRIDE_ALIGN); s32Result = HI_MPI_SYS_MmzAlloc_Cached(&pstHandle->pstBgModel->stBgModel.u64PhyAddr, (void**)&pstHandle->pstBgModel->stBgModel.u64VirAddr, NULL, HI_NULL, pstHandle->pstBgModel->stBgModel.u32Stride * frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); memset((HI_VOID*)pstHandle->pstBgModel->stBgModel.u64VirAddr, 0, pstHandle->pstBgModel->stBgModel.u32Stride * frame_gray.rows); IPC_LOG_INFO(pstHandle->iChannelIndex, "Creating stBgModel at physical address %x\n", (unsigned int)pstHandle->pstBgModel->stBgModel.u64PhyAddr); #endif #ifdef WIN32 pstHandle->pstBgModel->pstStatData->u32Size = sizeof(IVE_BG_STAT_DATA_S); pstHandle->pstBgModel->pstStatData->u64VirAddr = (HI_U64)malloc(pstHandle->pstBgModel->pstStatData->u32Size); pstHandle->pstBgModel->pstStatData->u64PhyAddr = (HI_U32)pstHandle->pstBgModel->pstStatData->u64VirAddr; IPC_LOG_INFO(pstHandle->iChannelIndex, "create stStatData at %x\n", (unsigned int)pstHandle->pstBgModel->pstStatData->u64VirAddr); #else pstHandle->pstBgModel->pstStatData->u32Size = sizeof(IVE_BG_STAT_DATA_S); s32Result = HI_MPI_SYS_MmzAlloc_Cached(&pstHandle->pstBgModel->pstStatData->u64PhyAddr, (void**)&pstHandle->pstBgModel->pstStatData->u64VirAddr, NULL, HI_NULL, pstHandle->pstBgModel->pstStatData->u32Size); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); IPC_LOG_INFO(pstHandle->iChannelIndex, "create stStatData at %x\n", (unsigned int)pstHandle->pstBgModel->pstStatData->u64PhyAddr); #endif s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stCurImg, IVE_IMAGE_TYPE_U8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stFgFlag, IVE_IMAGE_TYPE_U8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stBgDiffFg, IVE_IMAGE_TYPE_S8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stFrmDiffFg, IVE_IMAGE_TYPE_S8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stBgImg, IVE_IMAGE_TYPE_U8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stChgStaImg, IVE_IMAGE_TYPE_U8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stChgStaFg, IVE_IMAGE_TYPE_S8C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); s32Result = HI_CreateIveImage(&pstHandle->pstBgModel->stChgStaLife, IVE_IMAGE_TYPE_U16C1, frame_gray.cols, frame_gray.rows); HI_CHECK_ET_GOTO(s32Result, HI_FAILURE, MVFAILURE); pstHandle->pMogFt = new Mat(frame_gray.size(), CV_8U); pstHandle->ulinit2 = IPC_GetMsTime(); IPC_LOG_ERR(pstHandle->iChannelIndex, "frame number = %u, MOG Initialization of the backgrounds ... ... Initialization time: %d\n", pstHandle->uiDealCountNum, pstHandle->ulinit2 - pstHandle->ulinit1); IPC_Detection_target_reset(pstHandle); return s32Result; } u32FrameNum = pstHandle->uiDealCountNum; cvtColor(frame_g, frame_gray, CV_BGR2GRAY); temp = (IplImage)frame_gray; pstCvImgGray = &temp; CopyCvToIve(&pstHandle->pstBgModel->stCurImg, pstCvImgGray); pstHandle->pstBgModel->stMatchBgModelCtrl.u32PreFrmNum = pstHandle->pstBgModel->stMatchBgModelCtrl.u32CurFrmNum; pstHandle->pstBgModel->stMatchBgModelCtrl.u32CurFrmNum = u32FrameNum; s32Result = HI_MPI_IVE_MatchBgModel(&hIveHandle, &pstHandle->pstBgModel->stCurImg, &pstHandle->pstBgModel->stBgModel, &pstHandle->pstBgModel->stFgFlag, &pstHandle->pstBgModel->stBgDiffFg, &pstHandle->pstBgModel->stFrmDiffFg, pstHandle->pstBgModel->pstStatData, &pstHandle->pstBgModel->stMatchBgModelCtrl, bInstant); if (s32Result != HI_SUCCESS) { IPC_LOG_ERR(pstHandle->iChannelIndex, "HI_MPI_IVE_MatchBgModel fail.\n"); return s32Result; } if (pstHandle->pstBgModel->u32UpdCnt == 0 || u32FrameNum >= pstHandle->pstBgModel->u32PreUpdTime + pstHandle->pstBgModel->u32FrmUpdPeriod) { //HI_DOUBLE updbgmodel = (HI_DOUBLE)HI_GetTickCount(); pstHandle->pstBgModel->u32UpdCnt++; pstHandle->pstBgModel->u32PreUpdTime = u32FrameNum; pstHandle->pstBgModel->stUpdateBgModelCtrl.u32CurFrmNum = u32FrameNum; pstHandle->pstBgModel->stUpdateBgModelCtrl.u32PreChkTime = pstHandle->pstBgModel->u32PreChkTime; pstHandle->pstBgModel->stUpdateBgModelCtrl.u32FrmChkPeriod = 0; if (u32FrameNum >= pstHandle->pstBgModel->u32PreChkTime + pstHandle->pstBgModel->u32FrmChkPeriod) { pstHandle->pstBgModel->stUpdateBgModelCtrl.u32FrmChkPeriod = pstHandle->pstBgModel->u32FrmChkPeriod; pstHandle->pstBgModel->u32PreChkTime = u32FrameNum; } s32Result = HI_MPI_IVE_UpdateBgModel(&hIveHandle, &pstHandle->pstBgModel->stBgModel, &pstHandle->pstBgModel->stFgFlag, &pstHandle->pstBgModel->stBgImg, &pstHandle->pstBgModel->stChgStaImg, &pstHandle->pstBgModel->stChgStaFg, &pstHandle->pstBgModel->stChgStaLife, pstHandle->pstBgModel->pstStatData, &pstHandle->pstBgModel->stUpdateBgModelCtrl, bInstant); //updbgmodel = (HI_DOUBLE)HI_GetTickCount() - updbgmodel; // cout stFg.enType = IVE_IMAGE_TYPE_U8C1; pstHandle->pstBgModel->stFg.au64VirAddr[0] = pstHandle->pstBgModel->stBgDiffFg.au64VirAddr[0]; pstHandle->pstBgModel->stFg.au64PhyAddr[0] = pstHandle->pstBgModel->stBgDiffFg.au64PhyAddr[0]; pstHandle->pstBgModel->stFg.u32Width = pstHandle->pstBgModel->stBgDiffFg.u32Width; pstHandle->pstBgModel->stFg.u32Height = pstHandle->pstBgModel->stBgDiffFg.u32Height; pstHandle->pstBgModel->stFg.au32Stride[0] = pstHandle->pstBgModel->stBgDiffFg.au32Stride[0]; s32Result = HI_MPI_IVE_Thresh(&hIveHandle, &pstHandle->pstBgModel->stFg, &pstHandle->pstBgModel->stFg, &pstHandle->pstBgModel->stThrCtrl, bInstant); if (s32Result != HI_SUCCESS) { IPC_LOG_ERR(pstHandle->iChannelIndex, "HI_MPI_IVE_Thresh fail.\n"); return s32Result; } CopyIveToCv(pstCvFg, &pstHandle->pstBgModel->stFg); // for show bg if (HI_NULL == pstCvBgGray) { stSize = cvSize(frame_gray.cols, frame_gray.rows); pstCvBgGray = cvCreateImage(stSize, IPL_DEPTH_8U, 1); if (pstCvBgGray == NULL) goto MVFAILURE; } CopyIveToCv(pstCvBgGray, &pstHandle->pstBgModel->stBgImg); memcpy(pstHandle->pMogFt->data, (void*)pstHandle->pstBgModel->stFg.au64VirAddr[0], (size_t)pstHandle->pstBgModel->stFg.u32Width * pstHandle->pstBgModel->stFg.u32Height); #ifdef WIN32 cvNamedWindow("Bg", 0); cvShowImage("Bg", pstCvBgGray); imshow("MOG Original", *(pstHandle->pMogFt)); #endif //aulTime[1] = IPC_GetMsTime(); * (pstHandle->pMogFt) = CloseOP(*(pstHandle->pMogFt)); //aulTime[2] = IPC_GetMsTime(); medianBlur(*(pstHandle->pMogFt), *(pstHandle->pMogFt), 5); //aulTime[3] = IPC_GetMsTime(); #ifdef WIN32 imshow("MOG", *(pstHandle->pMogFt)); #endif // cout // stCurImg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stCurImg FAILED.\n"); } if (pstHandle->pstBgModel->stFgFlag.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stFgFlag); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stFgFlag FAILED.\n"); } if (pstHandle->pstBgModel->stBgDiffFg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stBgDiffFg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stBgDiffFg FAILED.\n"); } if (pstHandle->pstBgModel->stFrmDiffFg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stFrmDiffFg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stFrmDiffFg FAILED.\n"); } if (pstHandle->pstBgModel->stBgImg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stBgImg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stBgImg FAILED.\n"); } if (pstHandle->pstBgModel->stChgStaImg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stChgStaImg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stChgStaImg FAILED.\n"); } if (pstHandle->pstBgModel->stChgStaFg.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stChgStaFg); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stChgStaFg FAILED.\n"); } if (pstHandle->pstBgModel->stChgStaLife.au64VirAddr[0] != HI_NULL) { S32Ret = HI_DestroyIveImage(&pstHandle->pstBgModel->stChgStaLife); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stChgStaLife FAILED.\n"); } #ifdef WIN32 if (pstHandle->pstBgModel->stBgModel.u64VirAddr != HI_NULL) { HI_FREE_64(pstHandle->pstBgModel->stBgModel.u64VirAddr); } if (pstHandle->pstBgModel->pstStatData->u64VirAddr != HI_NULL) { HI_FREE_64(pstHandle->pstBgModel->pstStatData->u64VirAddr); } #else if (pstHandle->pstBgModel->stBgModel.u64VirAddr != HI_NULL) { S32Ret = HI_MPI_SYS_MmzFree(pstHandle->pstBgModel->stBgModel.u64PhyAddr, (VOID*)pstHandle->pstBgModel->stBgModel.u64VirAddr); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage stBgModel FAILED.\n"); } if (pstHandle->pstBgModel->pstStatData->u64VirAddr != HI_NULL) { S32Ret = HI_MPI_SYS_MmzFree(pstHandle->pstBgModel->pstStatData->u64PhyAddr, (VOID*)pstHandle->pstBgModel->pstStatData->u64VirAddr); if (S32Ret != IPC_ERRCODE_OK) IPC_LOG_ERR(pstHandle->iChannelIndex, "DestroyIveImage pstStatData FAILED.\n"); } #endif free(pstHandle->pstBgModel); pstHandle->pstBgModel = NULL; return S32Ret; } - HI_MPI_IVE_Query

这个算子是比较常用的算子,几乎上述每个算子都会用到。主要作用是判断在IVE中相应的操作是否完成。

【注意】

在用户使用IVE 任务结果前,为确保IVE 任务已完成,用户可以使用阻塞方式调用此接口查询。 IVE 内部是按任务创建顺序依次执行任务的,所以用户不必每次都使用查询接口,如用户依次创建了A,B两个任务,那么如果B 任务完成了,这个时候A 任务肯定也完成了,此时使用A 任务的结果时不必再次调用查询接口。 返回值为HI_ERR_IVE_QUERY_TIMEOUT(查询超时)时,可以继续查询。 返回值为HI_ERR_IVE_SYS_TIMEOUT(系统超时)时,用户的IVE 任务必须全部重新提交。

在Windows上模拟的时候,Query的结果永远为true。

/*****************************

Prototype : HI_MPI_IVE_Query Description : This API is used to query the status of a called function by using the returned IveHandle of the function. In block mode, the system waits until the function that is being queried is called. In non-block mode, the current status is queried and no action is taken. Parameters : IVE_HANDLE IveHandle IveHandle of a called function. It is entered by users. HI_BOOL *pbFinish Returned status HI_BOOL bBlock Flag indicating the block mode or non-block mode HI_BOOL *pbFinish Return Value : HI_SUCCESS: Success;Error codes: Failure. Spec : History: Date : 2011-05-16 Author : Modification : Created function * *****************************/ HI_S32 HI_MPI_IVE_Query(IVE_HANDLE IveHandle, HI_BOOL *pbFinish, HI_BOOL bBlock);

sample.png



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3