RGB转换为NV12的代码

简介: RGB转换为NV12的代码

如何将RGB转换为NV12?


首先将RGB转换为YUV。这个容易。问题在于,NV12是YYYY YYYY UVUV这样的格式,Y的个数等于像素,而U、V分别是像素个数的1/4。这就有点……


最后终于在github找到了可行代码,经过测试、修改,确实可行。


增加了一个step,RGB为3,RGBA为4。

性能较差。再想办法解决。

代码链接是:

https://github.com/cohenrotem/Rgb2NV12/

//https://software.intel.com/en-us/node/503873
//YCbCr Color Model:
//    The YCbCr color space is used for component digital video and was developed as part of the ITU-R BT.601 Recommendation. YCbCr is a scaled and offset version of the YUV color space.
//    The Intel IPP functions use the following basic equations [Jack01] to convert between R'G'B' in the range 0-255 and Y'Cb'Cr' (this notation means that all components are derived from gamma-corrected R'G'B'):
//    Y' = 0.257*R' + 0.504*G' + 0.098*B' + 16
//    Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
//    Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
//Y' = 0.257*R' + 0.504*G' + 0.098*B' + 16
static float Rgb2Y(float r0, float g0, float b0)
{
    float y0 = 0.257f*r0 + 0.504f*g0 + 0.098f*b0 + 16.0f;
    return y0;
}
//U equals Cb'
//Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
static float Rgb2U(float r0, float g0, float b0)
{
    float u0 = -0.148f*r0 - 0.291f*g0 + 0.439f*b0 + 128.0f;
    return u0;
}
//V equals Cr'
//Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
static float Rgb2V(float r0, float g0, float b0)
{
    float v0 = 0.439f*r0 - 0.368f*g0 - 0.071f*b0 + 128.0f;
    return v0;
}
//Convert two rows from RGB to two Y rows, and one row of interleaved U,V.
//I0 and I1 points two sequential source rows.
//I0 -> rgbrgbrgbrgbrgbrgb...
//I1 -> rgbrgbrgbrgbrgbrgb...
//Y0 and Y1 points two sequential destination rows of Y plane.
//Y0 -> yyyyyy
//Y1 -> yyyyyy
//UV0 points destination rows of interleaved UV plane.
//UV0 -> uvuvuv
static void Rgb2NV12TwoRows(const unsigned char I0[],
                            const unsigned char I1[],
                            int step,
                            const int image_width,
                            unsigned char Y0[],
                            unsigned char Y1[],
                            unsigned char UV0[])
{
    int x;  //Column index
    //Process 4 source pixels per iteration (2 pixels of row I0 and 2 pixels of row I1).
    for (x = 0; x < image_width; x += 2)
    {
        //Load R,G,B elements from first row (and convert to float).
        float r00 = (float)I0[x*step + 0];
        float g00 = (float)I0[x*step + 1];
        float b00 = (float)I0[x*step + 2];
        //Load next R,G,B elements from first row (and convert to float).
        float r01 = (float)I0[x*step + step+0];
        float g01 = (float)I0[x*step + step+1];
        float b01 = (float)I0[x*step + step+2];
        //Load R,G,B elements from second row (and convert to float).
        float r10 = (float)I1[x*step + 0];
        float g10 = (float)I1[x*step + 1];
        float b10 = (float)I1[x*step + 2];
        //Load next R,G,B elements from second row (and convert to float).
        float r11 = (float)I1[x*step + step+0];
        float g11 = (float)I1[x*step + step+1];
        float b11 = (float)I1[x*step + step+2];
        //Calculate 4 Y elements.
        float y00 = Rgb2Y(r00, g00, b00);
        float y01 = Rgb2Y(r01, g01, b01);
        float y10 = Rgb2Y(r10, g10, b10);
        float y11 = Rgb2Y(r11, g11, b11);
        //Calculate 4 U elements.
        float u00 = Rgb2U(r00, g00, b00);
        float u01 = Rgb2U(r01, g01, b01);
        float u10 = Rgb2U(r10, g10, b10);
        float u11 = Rgb2U(r11, g11, b11);
        //Calculate 4 V elements.
        float v00 = Rgb2V(r00, g00, b00);
        float v01 = Rgb2V(r01, g01, b01);
        float v10 = Rgb2V(r10, g10, b10);
        float v11 = Rgb2V(r11, g11, b11);
        //Calculate destination U element: average of 2x2 "original" U elements.
        float u0 = (u00 + u01 + u10 + u11)*0.25f;
        //Calculate destination V element: average of 2x2 "original" V elements.
        float v0 = (v00 + v01 + v10 + v11)*0.25f;
        //Store 4 Y elements (two in first row and two in second row).
        Y0[x + 0]    = (unsigned char)(y00 + 0.5f);
        Y0[x + 1]    = (unsigned char)(y01 + 0.5f);
        Y1[x + 0]    = (unsigned char)(y10 + 0.5f);
        Y1[x + 1]    = (unsigned char)(y11 + 0.5f);
        //Store destination U element.
        UV0[x + 0]    = (unsigned char)(u0 + 0.5f);
        //Store destination V element (next to stored U element).
        UV0[x + 1]    = (unsigned char)(v0 + 0.5f);
    }
}
//Convert image I from pixel ordered RGB to NV12 format.
//I - Input image in pixel ordered RGB format
//image_width - Number of columns of I
//image_height - Number of rows of I
//J - Destination "image" in NV12 format.
//I is pixel ordered RGB color format (size in bytes is image_width*image_height*3):
//RGBRGBRGBRGBRGBRGB
//RGBRGBRGBRGBRGBRGB
//RGBRGBRGBRGBRGBRGB
//RGBRGBRGBRGBRGBRGB
//
//J is in NV12 format (size in bytes is image_width*image_height*3/2):
//YYYYYY
//YYYYYY
//UVUVUV
//Each element of destination U is average of 2x2 "original" U elements
//Each element of destination V is average of 2x2 "original" V elements
//
//Limitations:
//1. image_width must be a multiple of 2.
//2. image_height must be a multiple of 2.
//3. I and J must be two separate arrays (in place computation is not supported). 
void Rgb2NV12(const unsigned char I[], int step,
              const int image_width, 
              const int image_height,
              unsigned char J[])
{
    //In NV12 format, UV plane starts below Y plane.
    unsigned char *UV = &J[image_width*image_height];
    //I0 and I1 points two sequential source rows.
    const unsigned char *I0;  //I0 -> rgbrgbrgbrgbrgbrgb...
    const unsigned char *I1;  //I1 -> rgbrgbrgbrgbrgbrgb...
    //Y0 and Y1 points two sequential destination rows of Y plane.
    unsigned char *Y0;    //Y0 -> yyyyyy
    unsigned char *Y1;    //Y1 -> yyyyyy
    //UV0 points destination rows of interleaved UV plane.
    unsigned char *UV0; //UV0 -> uvuvuv
    int y;  //Row index
    //In each iteration: process two rows of Y plane, and one row of interleaved UV plane.
    for (y = 0; y < image_height; y += 2)
    {
        I0 = &I[y*image_width*step];        //Input row width is image_width*3 bytes (each pixel is R,G,B).
        I1 = &I[(y+1)*image_width*step];
        Y0 = &J[y*image_width];            //Output Y row width is image_width bytes (one Y element per pixel).
        Y1 = &J[(y+1)*image_width];
        UV0 = &UV[(y/2)*image_width];    //Output UV row - width is same as Y row width.
        //Process two source rows into: Two Y destination row, and one destination interleaved U,V row.
        Rgb2NV12TwoRows(I0,
                        I1,
                        step,
                        image_width,
                        Y0,
                        Y1,
                        UV0);
    }
}
目录
相关文章
|
18天前
|
存储 编解码 监控
RGB 和 YUV 区别
【10月更文挑战第26天】RGB和YUV在色彩表示原理、数据存储方式、应用场景以及转换关系等方面都存在着明显的区别,它们各自在不同的领域发挥着重要的作用。
|
存储 编解码 Android开发
NV21、NV12、YV12、RGB、YUV、RGBA、RGBX8888等图像色彩编码格式区别
NV21、NV12、YV12、RGB、YUV、RGBA、RGBX8888都是常见的图像颜色编码格式,它们之间的主要区别在于色彩空间和数据排列方式。
212 0
|
6月前
|
存储 编解码
解码失败会显示绿屏,及yuv和rgb简单理解
解码失败会显示绿屏,及yuv和rgb简单理解
182 0
|
编解码 API 开发工具
NV21、NV12、YV12、RGB565、YUV等颜色编码格式区别和接口设计探讨
NV21、NV12、YV12、RGB565、YUV分别是不同的颜色编码格式,这些颜色编码格式各有特点,适用于不同的应用场景。选择合适的颜色编码格式取决于具体的需求和环境:
231 1
RGB转换为NV12的代码
RGB转换为NV12的代码
249 0
FreeSwitch中,RGB颜色转换为YUV
FreeSwitch中,RGB颜色转换为YUV
88 0
|
存储 算法 知识图谱
RGB与YUV相互转换
本文介绍YUV跟RGB互转的各种公式,以及推导原理
372 0
YUV转RGB查表方式的代码
YUV转RGB查表方式的代码
121 0
CMKY与RGB的转换
CMKY与RGB的转换
106 0
NV21转YUV420SP的代码
NV21转YUV420SP的代码
82 0