如何使用IPP将RGB转换为NV12色彩空间

5

视频编码器,如Intel® Media SDK,需要NV12视频输入格式。

NV12格式是YUV 4:2:0格式,按内存顺序排列,先是Y平面,然后是交错的UV平面中的打包色度样本。

例如:
YYYYYY
YYYYYY
UVUVUV

enter image description here

RGB颜色格式,指的是像素顺序为RGB(每个像素一个字节,低位字节为红色):
RGBRGBRGBRGBRGB
RGBRGBRGBRGBRGB

enter image description here

我进行了一些网络研究,发现在NV12方面,YUV被定义为YCbCr颜色空间。目前至少有两种可能的YCbCr格式适用于NV12: 我的问题是:是否有IPP函数可以将RGB颜色空间转换为NV12?

@Rotem:请澄清您是否正在寻找Matlab答案,如果不是,请进行另一次编辑以更改我添加的最后一句话。(并删除“[matlab]”标签) - Peter Cordes
我应该将这个问题分成三个不同的问题吗:1. 使用IPP,2. 痛苦的C代码,3. SSE优化代码? - Rotem
1
如果你编写了一个高度专业化的工具箱,GitHub可能是更好的选择。自问自答仅在Stack Overflow上适用于符合主题的问题。由于问题过于广泛,因此根据关闭情况,您的问题不适用于此。要么尝试将其编写为一个狭窄的问题,并提供适当解释的答案(而不是纯代码转储),要么创建一个GitHub页面来展示你的工具箱。 - Adriaan
3
就像这样看待它:你制造了世界上最好的自行车之一。如果你想推广它,汽车展会就不是一个好地方。两者都是交通工具,但种类不同。关于如何在Stack Overflow上编写一个良好的自问自答示例,我建议您查看这个链接:https://dev59.com/_1wY5IYBdhLWcg3wpJH_ - Adriaan
好的,我已经为IPP解决方案提供了焦点。 - Rotem
3
看起来现在是一个不错的自问自答问题 - 投票重新开放。 - Paul R
1个回答

13

我发现IPP函数存在:

ippiRGBToYCbCr420_8u_C3P2R

这个函数很难找到,因为函数名称或描述中没有提到NV12。
该函数使用BT.601标准。

以下是在BT.601 标准下将RGB转换为NV12 的代码示例:

void Rgb2NV12(const unsigned char I[], int image_width, int image_height, unsigned char J[])
{
    IppStatus ipp_status;
    int srcStep = image_width*3;
    int dstYStep = image_width;
    int dstCbCrStep = image_width;
    IppiSize roiSize = {image_width, image_height};

    const Ipp8u* pSrc = (Ipp8u*)I;

    Ipp8u *pDstY    = (Ipp8u*)J;                            //Y color plane is the first image_width*image_height pixels of J.
    Ipp8u *pDstCbCr = (Ipp8u*)&J[image_width*image_height]; //In NV12 format, UV plane starts below Y.

    ipp_status = ippiRGBToYCbCr420_8u_C3P2R(pSrc, srcStep, pDstY, dstYStep, pDstCbCr, dstCbCrStep, roiSize);

    //if (ipp_status != ippStsNoErr), Handle errors...          
}



使用BT.709标准将RGB转换为NV12:

截至2019年,BT.709(高清电视)标准可能比BT.601(标准清晰度电视)更为相关。

IPP缺少直接将RGB转换为BT.709标准下的NV12的函数。
有一个函数可以将BGR转换为NV12
解决方案包括两个阶段:

  1. RGB转换为BGR(交换通道)。
    代码示例使用ippiSwapChannels_8u_C3R进行RGBBGR转换。
  2. BGR转换为NV12
    代码示例使用ippiBGRToYCbCr420_709CSC_8u_C3P2R进行BGRNV12转换。

示例函数需要一些额外的内存空间来存储中间的BGR图像。
指向草图内存的指针传递给函数(内存应在函数外分配)。

这是一个将RGB转换为BT.709标准下的NV12的代码示例:

//sketch_buff - Temporary buffer for storing image in BGR format.
//              Size of sketch_buff must be at least image_width*image_height*3 bytes.
void Rgb2NV12_709(const unsigned char I[],
                  const int image_width, 
                  const int image_height,
                  unsigned char sketch_buff[],
                  unsigned char J[])
{
    IppStatus ipp_status;    
    int srcStep = image_width*3;
    int dstBgrStep = image_width*3;
    int dstYStep = image_width;
    int dstCbCrStep = image_width;
    IppiSize roiSize = {image_width, image_height};

    const Ipp8u* pRGB = (Ipp8u*)I;
    Ipp8u* pBGR = (Ipp8u*)sketch_buff; //BGR image is stored in sketch_buff
    Ipp8u *pDstY    = (Ipp8u*)J;                            //Y color plane is the first image_width*image_height pixels of J.
    Ipp8u *pDstCbCr = (Ipp8u*)&J[image_width*image_height]; //In NV12 format, UV plane starts below Y.

    const int bgrOrder[3] = {2, 1, 0};

    //Swap Red and Blue color channels - convert from RGB to BGR
    //Store the result into sketch_buff (sketch buffer is allocated outside the function)
    ipp_status = ippiSwapChannels_8u_C3R(pRGB, srcStep, pBGR, dstBgrStep, roiSize, bgrOrder);

    //if (ipp_status != ippStsNoErr), Handle errors...

    //Convert BGR to NV12 in BT.709 standard
    ipp_status = ippiBGRToYCbCr420_709CSC_8u_C3P2R(pBGR, srcStep, pDstY, dstYStep, pDstCbCr, dstCbCrStep, roiSize);

    //if (ipp_status != ippStsNoErr), Handle errors...
}

1
我的优化C语言实现(使用SSE指令集向量化)可以在这里找到:https://github.com/cohenrotem/Rgb2NV12。 - Rotem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接