海思人脸识别(1) – YUV2BGR

这可能是全网第一个YUV转BGR(B0B1B2…G0G1G2…R0R1R2…)的博客。

网上全部都是yuv2rgb(B0G0R0B1G1R1…),而且代码都不规整,没有做出最后的效果。所以自己在实际过程中整理了一份YUV2BGR的详细过程。

任务要求:人脸识别模型要求图像输入格式BGR(B0B1B2…G0G1G2…R0R1R2…),输入图片的大小是1024 * 576,需要先在外面把图片缩放和格式转化。

  1. 需要用到的模块VI、VPSS、IVE

  2. 需要理解的视频格式YUV420SP、RGB

vi模块:这里我们摄像头采用BT.601接口。

在这里插入图片描述

VPSS模块:需要对源视频流进行裁剪,1920 * 1080->1024 * 576的缩放

IVE模块:是海思媒体处理芯片智能分析系统中的硬件加速模块,也是这次的重点模块。

接下来的两幅图片详细说明这两种格式的区别,图片来源于HI IVE API参考:

在这里插入图片描述

在这里插入图片描述

网上都是IVE_IMAGE_TYPE_U8C3_PACKAGE,所以直接调用fwrite写入大小为stDst.u32Width * stDst.u32Height * 3就行了

注意看IVE_IMAGE_TYPE_U8C3_PLANER的格式,指针数组VirAddr[3]按顺序分别存储B、G、R的指针,所以代码部分需要做出相应的改变(这也是我研究很久后才发现的)。

废话不多说,上代码,如下代码参考https://github.com/openhisilicon/HIVIEW/blob/master/mod/svp/3516d/nnie/sample/vpss_capture.cpp代码,做出小部分更改

HI_S32 yuvFrame2rgb(VIDEO_FRAME_S* pVBuf)
{
	HI_S32 ret;
	IVE_SRC_IMAGE_S stSrc;
    IVE_SRC_IMAGE_S stDst;
	IVE_HANDLE IveHandle;
	IVE_CSC_CTRL_S stCscCtrl;
	HI_BOOL bInstant = HI_TRUE;
	unsigned char *pImage;

	stSrc.au64PhyAddr[0] = pVBuf->u64PhyAddr[0];
	stSrc.au64PhyAddr[1] = pVBuf->u64PhyAddr[1];
	stSrc.au64PhyAddr[2] = pVBuf->u64PhyAddr[2];
	stSrc.au64VirAddr[0] = pVBuf->u64VirAddr[0];
	stSrc.au64VirAddr[1] = pVBuf->u64VirAddr[1];
	stSrc.au64VirAddr[2] = pVBuf->u64VirAddr[2];
	stSrc.au32Stride[0]  = pVBuf->u32Stride[0];
	stSrc.au32Stride[1]  = pVBuf->u32Stride[1];
	stSrc.au32Stride[2]  = pVBuf->u32Stride[2];
	stSrc.u32Width  = pVBuf->u32Width;
	stSrc.u32Height = pVBuf->u32Height;

	switch (pVBuf->enPixelFormat)
	{
		case PIXEL_FORMAT_YVU_PLANAR_420:
			stSrc.enType = IVE_IMAGE_TYPE_YUV420P;
			break ;
		case PIXEL_FORMAT_YVU_SEMIPLANAR_420:
			stSrc.enType = IVE_IMAGE_TYPE_YUV420SP;
			break ;
		default:
			printf("unsupported PixelFormat yet, %d\n", pVBuf->enPixelFormat);
			break ;
	}

	stDst.au32Stride[0]  = pVBuf->u32Width;
	stDst.au32Stride[1]  = pVBuf->u32Width;
	stDst.au32Stride[2]  = pVBuf->u32Width;
	stDst.u32Width  = pVBuf->u32Width;
	stDst.u32Height = pVBuf->u32Height;
	//stDst.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE;
    stDst.enType = IVE_IMAGE_TYPE_U8C3_PLANAR;		// 重点,重点,重点,需要使用这种格式

	//if(img.cols != pVBuf->u32Width || img.rows != pVBuf->u32Height || !stDst.au64VirAddr[0])
	{
		ret = HI_MPI_SYS_MmzAlloc_Cached(&stDst.au64PhyAddr[0],
				(HI_VOID **)&stDst.au64VirAddr[0],
				NULL,HI_NULL,
				stDst.u32Height*stDst.u32Width*3);
		if (HI_FAILURE == ret)
		{
			printf("MmzAlloc_Cached failed!\n");
			return HI_FAILURE;
		}

		printf("MmzAlloc_Cached OK!\n");
	}

	// 重点,重点,重点,加上偏移的大小是stDst.au32Stride[0]*stDst.u32Height
	stDst.au64PhyAddr[1] = stDst.au64PhyAddr[0] + stDst.au32Stride[0]*stDst.u32Height;
	stDst.au64PhyAddr[2] = stDst.au64PhyAddr[1] + stDst.au32Stride[1]*stDst.u32Height;
	stDst.au64VirAddr[1] = stDst.au64VirAddr[0] + stDst.au32Stride[0]*stDst.u32Height;
	stDst.au64VirAddr[2] = stDst.au64VirAddr[1] + stDst.au32Stride[1]*stDst.u32Height;

	stCscCtrl.enMode = IVE_CSC_MODE_PIC_BT601_YUV2RGB;
	ret = HI_MPI_IVE_CSC(&IveHandle, &stSrc, &stDst, &stCscCtrl, bInstant); 
	if (HI_FAILURE == ret)
	{
		printf("YUV Convert to RGB failed!\n");
		return HI_FAILURE;
	}

	pImage = (unsigned char *)stDst.au64VirAddr[0];
	if(NULL == pImage)
	{
		printf( "stDst.au64VirAddr[0] is null!\n");
		return HI_FAILURE;    
	}

    FILE *pfd;
    uint64_t count = 0;
    pfd = fopen("/home/buffer/1024_576.bgr", "wb+");


    fflush(pfd);
    // 重点:注意写入数据的大小stDst.u32Width*stDst.u32Height
    fwrite((HI_VOID *)stDst.au64VirAddr[0], stDst.u32Width*stDst.u32Height, 1, pfd);
    fflush(pfd);
    fwrite((HI_VOID *)stDst.au64VirAddr[1], stDst.u32Width*stDst.u32Height, 1, pfd);
    fflush(pfd);
    fwrite((HI_VOID *)stDst.au64VirAddr[2], stDst.u32Width*stDst.u32Height, 1, pfd);
    
    printf( "after fwrite()!\n");
    fflush(pfd);

	return 0;
}

最后将1024_576.bgr转化成BMP即可(转换bmp的代码去网上搜索即可),最终效果如下。如果有任何问题或者疑问,欢迎留言。

在这里插入图片描述

图片来源于网络,如侵权,联系我删除。

参考链接:

https://github.com/openhisilicon/HIVIEW/blob/master/mod/svp/3516d/nnie/sample/vpss_capture.cpp

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐