加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

hi3516下yuv图片到NNIE的bgr_u8c3格式转换

(2020-05-22 18:04:53)
标签:

it

教育

分类: *机器学习
首先要看的sdk文檔(HiIVE API 参考)
其中详细说明了
IVE_IMAGE_TYPE_YUV420SP,     IVE_IMAGE_TYPE_YUV420P, IVE_IMAGE_TYPE_YUV422SP,
IVE_IMAGE_TYPE_U8C3_PACKAGE, IVE_IMAGE_TYPE_U8C3_PLANAR
等文件格式,
而我们也需要使用 IVE 提供的 HI_MPI_IVE_CSC 进行图片格式的转换,那么我们来看看这个函数:

///
// Prototype    : HI_MPI_IVE_CSC
// Description  : YUV2RGB\YUV2HSV\YUV2LAB\RGB2YUV color space conversion are supported.
// Parameters   : IVE_HANDLE     * pIveHandle   Returned handle ID of a task         
//                IVE_SRC_IMAGE_S* pstSrc       Input source data:
//                                              1. SP420\SP422 type for YUV2RGB\YUV2HSV\YUV2LAB;
//                                              2. U8C3_PACKAGE\U8C3_PLANAR type for RGB2YUV;
//                IVE_DST_IMAGE_S* pstDst       Output result:
//                                              1. U8C3_PACKAGE\U8C3_PLANAR typed for YUV2RGB\YUV2HSV\YUV2LAB;
//                                              2. SP420\SP422 type for RGB2YUV;
//                IVE_CSC_CTRL_S*  pstCscCtrl   Control parameters for CSC
//                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 physical addresses of the input data and output data must be 16-byte-aligned.
//                The stride must be 16-pixel-aligned.
///

由于我们模型使用的是 IVE_IMAGE_TYPE_U8C3_PLANAR 此种数据格式,
因此只能使用 YUV2RGB ,也就是注释中的第一种情况中的 SP420 to U8C3_PLANAR 。
注:
U8C3_PACKAGE the array with the BGRBGRBGR pixel data
U8C3_PLANAR  the array with the BBBGGGRRR pixel data

// the array with the BGRBGRBGR pixel data
byte[] source;

// the array with the BBBGGGRRR pixel data
byte[] result;

// the amount of pixels in one channel
int imageSize = width * height;
 
for (int i  = 0;
         < source.Length;
         i += 3)
{
    result[i/3]                 = source[i + 0]; // BBB...
    result[i/3 + imageSize]     = source[i + 1]; // GGG...
    result[i/3 + imageSize * 2] = source[i+2];   // RRR...
}

再来看看从摄像头出来的图片格式吧,将图片用 7yuv 工具打开,
发现是 YUV420 planar I420 ,对应到 ive 里的图片格式为 IVE_IMAGE_TYPE_YUV420P 。

因此在使用 HI_MPI_IVE_CSC 之前要先进行图片转换,
先将 IVE_IMAGE_TYPE_YUV420P 转换为 IVE_IMAGE_TYPE_YUV420SP 后使用。

具体 demo 代码如下:

typedef struct tag_csc_s
{
    HI_S32           sWidth;
    HI_S32           sHeight;
    IVE_SRC_IMAGE_S  stSrc;
    IVE_DST_IMAGE_S  stDst;
    IVE_CSC_CTRL_S   stCtrl;
}CSC_S;

void
CreateCSC(CSC_S* pstCSC,
          HI_S32 sWidth,
          HI_S32 sHeight)
{
    pstCSC->sWidth  = sWidth;
    pstCSC->sHeight = sHeight;

    // input image
    memset(&pstCSC->stSrc,
           0,
           sizeof(IVE_SRC_IMAGE_S));
    
    pstCSC->stSrc.enType = IVE_IMAGE_TYPE_YUV420SP;

    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc_Cached(&pstCSC->stSrc.au64PhyAddr[0],
                                               (HI_VOID**)&pstCSC->stSrc.au64VirAddr[0],
                                               "InputImage",
                                               HI_NULL,
                                               sWidth * sHeight * 3 / 2);
    if (HI_SUCCESS != s32Ret)
    {
        printf("can't alloc InputImage memory for %x\n", s32Ret);
    }
    
    pstCSC->stSrc.u32Width      = sWidth;
    pstCSC->stSrc.u32Height     = sHeight;
    pstCSC->stSrc.au32Stride[0] = sWidth;

    // SP420
    pstCSC->stSrc.au32Stride[1]  = pstCSC->stSrc.au32Stride[0];
    pstCSC->stSrc.au64PhyAddr[1] = pstCSC->stSrc.au64PhyAddr[0] + pstCSC->stSrc.au32Stride[0] * pstCSC->stSrc.u32Height;
    pstCSC->stSrc.au64VirAddr[1] = pstCSC->stSrc.au64VirAddr[0] + pstCSC->stSrc.au32Stride[0] * pstCSC->stSrc.u32Height;

    // output image
    memset(&pstCSC->stDst,
           0,
           sizeof(IVE_DST_IMAGE_S));
           
    const HI_U32 u32Size = sWidth * sHeight * 3;
    
    pstCSC->stDst.enType = IVE_IMAGE_TYPE_U8C3_PLANAR;
    
    s32Ret = HI_MPI_SYS_MmzAlloc(&pstCSC->stDst.au64PhyAddr[0],
                                 (void**)&pstCSC->stDst.au64VirAddr[0],
                                 "OutputImage",
                                 HI_NULL,
                                 u32Size);
    if (HI_SUCCESS != s32Ret)
    {
        printf("can't alloc OutputImage memory for %x\n", s32Ret);
    }
    
    pstCSC->stDst.u32Width      = sWidth;
    pstCSC->stDst.u32Height     = sHeight;
    pstCSC->stDst.au32Stride[0] = sWidth;

    pstCSC->stDst.au64VirAddr[1] = pstCSC->stDst.au64VirAddr[0] + pstCSC->stDst.u32Height * pstCSC->stDst.au32Stride[0];
    pstCSC->stDst.au64PhyAddr[1] = pstCSC->stDst.au64PhyAddr[0] + pstCSC->stDst.u32Height * pstCSC->stDst.au32Stride[0];
    pstCSC->stDst.au32Stride[1] = pstCSC->stDst.au32Stride[0];

    pstCSC->stDst.au64VirAddr[2] = pstCSC->stDst.au64VirAddr[1] + pstCSC->stDst.u32Height * pstCSC->stDst.au32Stride[1];
    pstCSC->stDst.au64PhyAddr[2] = pstCSC->stDst.au64PhyAddr[1] + pstCSC->stDst.u32Height * pstCSC->stDst.au32Stride[1];
    
    pstCSC->stDst.au32Stride[2] = pstCSC->stDst.au32Stride[0];
   
    // ctrl
    memset(&pstCSC->stCtrl, 0, sizeof(IVE_CSC_CTRL_S));
    pstCSC->stCtrl.enMode = IVE_CSC_MODE_PIC_BT601_YUV2RGB;
}

void
DestoryCSC(CSC_S* pstCSC)
{
    if (NULL != pstCSC->stSrc.au64PhyAddr[0])
    {
        HI_MPI_SYS_MmzFree(pstCSC->stSrc.au64PhyAddr[0],
                           pstCSC->stSrc.au64VirAddr[0]);
    }

    if (NULL != pstCSC->stDst.au64PhyAddr[0])
    {
        HI_MPI_SYS_MmzFree(pstCSC->stDst.au64PhyAddr[0],
                           pstCSC->stDst.au64VirAddr[0]);
    }
}

void
ReadYUV420pFile(IVE_IMAGE_S* pstImg,
                FILE*        pFp)
{
    const HI_U16 width  = pstImg->u32Width;
    const HI_U16 height = pstImg->u32Height;
    
    HI_U8* pU8 = pstImg->au64VirAddr[0];
    
    for (HI_U16 idxH = 0;
                idxH < height;
                idxH++)
    {
        if (1 != fread(pU8,
                       width,
                       1,
                       pFp))
        {
            printf("Read file fail\n");
            return ;
        }

        pU8 += pstImg->au32Stride[0];
    }

    HI_U8* pUBuf = malloc(width * height / 4);
    HI_U8* pVBuf = malloc(width * height / 4);
    
    fread(pUBuf, 1, width * height / 4, pFp);
    fread(pVBuf, 1, width * height / 4, pFp);

    pU8 = pstImg->au64VirAddr[1];
    
    for (HI_U16 idxH = 0;
                idxH < height / 2;
                idxH++)
    {
        int nShift = idxH * width /2 ;
        
        for (HI_U16 idxW = 0;
                    idxW < width / 2;
                    idxW++)
        {
            pU8[2 * idxW + 0] = pVBuf[nShift + idxW];
            pU8[2 * idxW + 1] = pUBuf[nShift + idxW];
        }

        pU8 += pstImg->au32Stride[1];
    }
    
    free(pUBuf);
    free(pVBuf);
}

void
WriteYUV420spFile(IVE_IMAGE_S* pstImg,
                  FILE*        pFp)
{
    const HI_U16 width  = pstImg->u32Width;
    const HI_U16 height = pstImg->u32Height * 3 / 2;
    
    HI_U8* pU8 = pstImg->au64VirAddr[0];
    
    for (HI_U16 idxH = 0;
                idxH < height;
                idxH++)
    {
        if (1 != fwrite(pU8,
                        width,
                        1,
                        pFp))
        {
            printf("write file error, idxH = %d\n", idxH);
            return;
        }

        pU8 += pstImg->au32Stride[0];
    }
}

void
WriteBGRPackFile(IVE_IMAGE_S* pstImg,
                 FILE*        pFp)
{
    const HI_U16 width  = pstImg->u32Width;
    const HI_U16 height = pstImg->u32Height * 3;
    
    HI_U8* pU8 = pstImg->au64VirAddr[0];
    
    for (HI_U16 idxH = 0;
                idxH < height;
                idxH++)
    {
        if (1 != fwrite(pU8,
                        width,
                        1,
                        pFp))
        {
            printf("write file error, idxH = %d\n", idxH);
            return;
        }

        pU8 += pstImg->au32Stride[0];
    }
}

void
TestCSC(HI_U8* pu8VirAddr)
 
    FILE* fP420 = fopen("./pipe0_chn0_w1920_h1080_P420.yuv",
                        "rb");
    if (HI_NULL == fP420)
    {
        printf("Open in file ./pipe0_chn0_w1920_h1080_P420.yuv fail\n");
        return;
    }
    
    FILE* fBGR = fopen("./pipe0_chn0_w1920_h1080_RGB.bgr",
                       "wb");
    if (HI_NULL == fBGR)
    {
        printf("Open out file ./pipe0_chn0_w1920_h1080_RGB.bgr fail\n");
        fclose(fP420);
        return;
    }

    FILE* fSP420 = fopen("./pipe0_chn0_w1920_h1080_SP420.yuv",
                         "wb");
    if(HI_NULL == fSP420)
    {
        printf("Open out file ./pipe0_chn0_w1920_h1080_SP420.yuv fail\n");
        fclose(fP420);
        fclose(fBGR);
        return;
    }

    int sWidth  = 1920;
    int sHeight = 1080;

    CSC_S stCSC;
    CreateCSC(&stCSC,
              sWidth,
              sHeight);
              
    ReadYUV420pFile(&stCSC.stSrc,
                    fP420);

    WriteYUV420spFile(&stCSC.stSrc,
                      fSP420);
    
    IVE_HANDLE hIveHandle;
    HI_MPI_IVE_CSC(&hIveHandle,
                   &stCSC.stSrc,
                   &stCSC.stDst,
                   &stCSC.stCtrl,
                   HI_TRUE);

    // B
    memcpy(pu8VirAddr,
           stCSC.stDst.au64VirAddr[0],
           sWidth * sHeight);
    
    // G
    memcpy(pu8VirAddr + sWidth * sHeight,
           stCSC.stDst.au64VirAddr[1],
           sWidth * sHeight);
    
    // R
    memcpy(pu8VirAddr + sWidth * sHeight * 2,
           stCSC.stDst.au64VirAddr[2],
           sWidth * sHeight);
    
    WriteBGRPackFile(&stCSC.stDst,
                     fBGR);
                     
    DestoryCSC(&stCSC);

    fclose(fP420);
    fclose(fBGR);
    fclose(fSP420);
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有