海思人脸识别(1) -- YUV2BGR
海思人脸识别(1) – YUV2BGR
这可能是全网第一个YUV转BGR(B0B1B2…G0G1G2…R0R1R2…)的博客。
网上全部都是yuv2rgb(B0G0R0B1G1R1…),而且代码都不规整,没有做出最后的效果。所以自己在实际过程中整理了一份YUV2BGR的详细过程。
任务要求:人脸识别模型要求图像输入格式BGR(B0B1B2…G0G1G2…R0R1R2…),输入图片的大小是1024 * 576,需要先在外面把图片缩放和格式转化。
-
需要用到的模块VI、VPSS、IVE
-
需要理解的视频格式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
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)