织梦CMS - 轻松建站从此开始!

罗索

YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blen

jackyhwei 发布于 2011-08-12 16:00 点击:次 
YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending: YUY2经常用于电视制式以及许多摄像头的输出格式.而我们在处理时经常需要将其转化为RGB进行处理,这里简单介绍下YUY2(YUV)与RGB之间相互转化的关系
TAG:

YUY2经常用于电视制式以及许多摄像头的输出格式.而我们在处理时经常需要将其转化为RGB进行处理,这里简单介绍下YUY2(YUV)与RGB之间相互转化的关系:

http://msdn2.microsoft.com/en-us/library/ms893078.aspx

YUY2(YUV) To RGB:

C = Y - 16

D = U - 128

E = V - 128

R = clip(( 298 * C           + 409 * E + 128) >> 8)
G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
B = clip(( 298 * C + 516 * D           + 128) >> 8)

其中 clip()为限制函数,将其取值限制在0-255之间.

RGB To YUY2(YUV):

Y = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16
U = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128
V = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128

上述两个公式在代码中的
int YUV2RGB(void* pYUV, void* pRGB, int width, int height, bool alphaYUV, bool alphaRGB);
int RGB2YUV(void* pRGB, void* pYUVX, int width, int height, bool alphaYUV, bool alphaRGB);
函数中转换。

在诸如摄像头的数据获取中,我们往往需要直接在YUY2(YUV)空间上进行一些图象处理,我们希望能够在YUY2(YUV)进行一些RGB上可以做到的处理。这里已blending为例,将两张带有透明度的YUY2(YUV)图片进行叠加,以达到在RGB空间进行图像合成的效果。

RGB空间进行图像叠加,通常背景(BG)是不透明的,而前景(FG)是带有透明度的。在RGB空间,可以简单表示为:
Rdest = Rfg*alpha + Rbg*(1-alpha);
Gdest = Gfg*alpha + Gbg*(1-alpha);
Bdest = Bfg*alpha + Bbg*(1-alpha);
// Rdest、Gdest、Bdest 为最终合成后的像素值

考虑到
Y = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16
U = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128
V = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128
我们可以推导出

(Ydest-16)<<8 = ((Yfg-16)<<8)*alpha + ((Ybg-16)<<8)*(1-alpha);
(Udest-128)<<8 = ((Ufg-128)<<8)*alpha + ((Ubg-128)<<8)*(1-alpha);
(Vdest-128)<<8 = ((Vfg-128)<<8)*alpha + ((Vbg-128)<<8)*(1-alpha);

从而可以得到
Ydest = (Yfg-16)*alpha + (Ybg-16)*(1-alpha) + 16;
Udest = (Ufg-128)*alpha + (Ubg-128)*(1-alpha) + 128;
Vdest = (Vfg-128)*alpha + (Vbg-128)*(1-alpha) + 128;

这个叠加过程在函数
int YUVBlending(void* pBGYUV, void* pFGYUV, int width, int height, bool alphaBG, bool alphaFG)
中实现。

由于本文针对摄像头采集所得的数据进行处理,因此数据为YUY2格式,即4个字节来表示两个像素点的YUV信息,
排列为Y1 U1 Y2 V2, 对于像素点1为(Y1, U1, V1),像素点2为(Y2, U1, V1)。即两个像素点共用U、V信息。

这里假设带有alpha透明度的YUV格式用6个字节来表示两个像素点的YUV以及alpha信息,排列为 Y1 U1 Y2 V1 alpha1 alpha2
其中像素点1为(Y1, U1, V1, alpha1),像素点2为(Y2, U1, V1, alpha2)。其中alpha为对应点的透明度信息。

而带有alpha透明度RGB格式的图片,假设为32bits的BMP图片,每个像素点用4bytes来表示,分别为B G R alpha信息。

上述函数的具体实现为:

//////////////////////////////////////////////////////////////////////////
// YUV2RGB
// pYUV            point to the YUV data
// pRGB            point to the RGB data
// width        width of the picture
// height        height of the picture
// alphaYUV        is there an alpha channel in YUV
// alphaRGB        is there an alpha channel in RGB
//////////////////////////////////////////////////////////////////////////
int YUV2RGB(void* pYUV, void* pRGB, int width, int height, bool alphaYUV, bool alphaRGB)
{
    if (NULL == pYUV)
    {
        return -1;
    }
    unsigned char* pYUVData = (unsigned char *)pYUV;
    unsigned char* pRGBData = (unsigned char *)pRGB;
    if (NULL == pRGBData)
    {
        if (alphaRGB)
        {
            pRGBData = new unsigned char[width*height*4];
        }
        else
            pRGBData = new unsigned char[width*height*3];
    }
    int Y1, U1, V1, Y2, alpha1, alpha2, R1, G1, B1, R2, G2, B2;
    int C1, D1, E1, C2;
    if (alphaRGB)
    {
        if (alphaYUV)
        {
            for (int i=0; i<height; ++i)
            {
                for (int j=0; j<width/2; ++j)
                {
                    Y1 = *(pYUVData+i*width*3+j*6);
                    U1 = *(pYUVData+i*width*3+j*6+1);
                    Y2 = *(pYUVData+i*width*3+j*6+2);
                    V1 = *(pYUVData+i*width*3+j*6+3);
                    alpha1 = *(pYUVData+i*width*3+j*6+4);
                    alpha2 = *(pYUVData+i*width*3+j*6+5);
                    C1 = Y1-16;
                    C2 = Y2-16;
                    D1 = U1-128;
                    E1 = V1-128;
                    R1 = ((298*C1 + 409*E1 + 128)>>8>255 ? 255 : (298*C1 + 409*E1 + 128)>>8);
                    G1 = ((298*C1 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C1 - 100*D1 - 208*E1 + 128)>>8);   
                    B1 = ((298*C1+516*D1 +128)>>8>255 ? 255 : (298*C1+516*D1 +128)>>8);   
                    R2 = ((298*C2 + 409*E1 + 128)>>8>255 ? 255 : (298*C2 + 409*E1 + 128)>>8);
                    G2 = ((298*C2 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C2 - 100*D1 - 208*E1 + 128)>>8);
                    B2 = ((298*C2 + 516*D1 +128)>>8>255 ? 255 : (298*C2 + 516*D1 +128)>>8);   
                    *(pRGBData+(height-i-1)*width*4+j*8+2) = R1<0 ? 0 : R1;
                    *(pRGBData+(height-i-1)*width*4+j*8+1) = G1<0 ? 0 : G1;
                    *(pRGBData+(height-i-1)*width*4+j*8) = B1<0 ? 0 : B1;
                    *(pRGBData+(height-i-1)*width*4+j*8+3) = alpha1;   
                    *(pRGBData+(height-i-1)*width*4+j*8+6) = R2<0 ? 0 : R2;
                    *(pRGBData+(height-i-1)*width*4+j*8+5) = G2<0 ? 0 : G2;
                    *(pRGBData+(height-i-1)*width*4+j*8+4) = B2<0 ? 0 : B2;
                    *(pRGBData+(height-i-1)*width*4+j*8+7) = alpha2;   
                }
            }   
        }
        else
        {
            int alpha = 255;
            for (int i=0; i<height; ++i)
            {
                for (int j=0; j<width/2; ++j)
                {
                    Y1 = *(pYUVData+i*width*2+j*4);
                    U1 = *(pYUVData+i*width*2+j*4+1);
                    Y2 = *(pYUVData+i*width*2+j*4+2);
                    V1 = *(pYUVData+i*width*2+j*4+3);
                    C1 = Y1-16;
                    C2 = Y2-16;
                    D1 = U1-128;
                    E1 = V1-128;
                    R1 = ((298*C1 + 409*E1 + 128)>>8>255 ? 255 : (298*C1 + 409*E1 + 128)>>8);
                    G1 = ((298*C1 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C1 - 100*D1 - 208*E1 + 128)>>8);   
                    B1 = ((298*C1+516*D1 +128)>>8>255 ? 255 : (298*C1+516*D1 +128)>>8);   
                    R2 = ((298*C2 + 409*E1 + 128)>>8>255 ? 255 : (298*C2 + 409*E1 + 128)>>8);
                    G2 = ((298*C2 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C2 - 100*D1 - 208*E1 + 128)>>8);
                    B2 = ((298*C2 + 516*D1 +128)>>8>255 ? 255 : (298*C2 + 516*D1 +128)>>8);   
                    *(pRGBData+(height-i-1)*width*4+j*8+2) = R1<0 ? 0 : R1;
                    *(pRGBData+(height-i-1)*width*4+j*8+1) = G1<0 ? 0 : G1;
                    *(pRGBData+(height-i-1)*width*4+j*8) = B1<0 ? 0 : B1;
                    *(pRGBData+(height-i-1)*width*4+j*8+3) = alpha;   
                    *(pRGBData+(height-i-1)*width*4+j*8+6) = R2<0 ? 0 : R2;
                    *(pRGBData+(height-i-1)*width*4+j*8+5) = G2<0 ? 0 : G2;
                    *(pRGBData+(height-i-1)*width*4+j*8+4) = B2<0 ? 0 : B2;
                    *(pRGBData+(height-i-1)*width*4+j*8+7) = alpha;   
                }
            }   
        }
    }
    else
    {
        if (alphaYUV)
        {
            for (int i=0; i<height; ++i)
            {
                for (int j=0; j<width/2; ++j)
                {
                    Y1 = *(pYUVData+i*width*3+j*4);
                    U1 = *(pYUVData+i*width*3+j*4+1);
                    Y2 = *(pYUVData+i*width*3+j*4+2);
                    V1 = *(pYUVData+i*width*3+j*4+3);
                    C1 = Y1-16;
                    C2 = Y2-16;
                    D1 = U1-128;
                    E1 = V1-128;
                    R1 = ((298*C1 + 409*E1 + 128)>>8>255 ? 255 : (298*C1 + 409*E1 + 128)>>8);
                    G1 = ((298*C1 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C1 - 100*D1 - 208*E1 + 128)>>8);   
                    B1 = ((298*C1+516*D1 +128)>>8>255 ? 255 : (298*C1+516*D1 +128)>>8);   
                    R2 = ((298*C2 + 409*E1 + 128)>>8>255 ? 255 : (298*C2 + 409*E1 + 128)>>8);
                    G2 = ((298*C2 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C2 - 100*D1 - 208*E1 + 128)>>8);
                    B2 = ((298*C2 + 516*D1 +128)>>8>255 ? 255 : (298*C2 + 516*D1 +128)>>8);   
                    *(pRGBData+(height-i-1)*width*3+j*6+2) = R1<0 ? 0 : R1;
                    *(pRGBData+(height-i-1)*width*3+j*6+1) = G1<0 ? 0 : G1;
                    *(pRGBData+(height-i-1)*width*3+j*6) = B1<0 ? 0 : B1;
                    *(pRGBData+(height-i-1)*width*3+j*6+5) = R2<0 ? 0 : R2;
                    *(pRGBData+(height-i-1)*width*3+j*6+4) = G2<0 ? 0 : G2;
                    *(pRGBData+(height-i-1)*width*3+j*6+3) = B2<0 ? 0 : B2;
                }
            }
        }
        else
        {
            for (int i=0; i<height; ++i)
            {
                for (int j=0; j<width/2; ++j)
                {
                    Y1 = *(pYUVData+i*width*2+j*4);
                    U1 = *(pYUVData+i*width*2+j*4+1);
                    Y2 = *(pYUVData+i*width*2+j*4+2);
                    V1 = *(pYUVData+i*width*2+j*4+3);
                    C1 = Y1-16;
                    C2 = Y2-16;
                    D1 = U1-128;
                    E1 = V1-128;
                    R1 = ((298*C1 + 409*E1 + 128)>>8>255 ? 255 : (298*C1 + 409*E1 + 128)>>8);
                    G1 = ((298*C1 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C1 - 100*D1 - 208*E1 + 128)>>8);   
                    B1 = ((298*C1+516*D1 +128)>>8>255 ? 255 : (298*C1+516*D1 +128)>>8);   
                    R2 = ((298*C2 + 409*E1 + 128)>>8>255 ? 255 : (298*C2 + 409*E1 + 128)>>8);
                    G2 = ((298*C2 - 100*D1 - 208*E1 + 128)>>8>255 ? 255 : (298*C2 - 100*D1 - 208*E1 + 128)>>8);
                    B2 = ((298*C2 + 516*D1 +128)>>8>255 ? 255 : (298*C2 + 516*D1 +128)>>8);   
                    *(pRGBData+(height-i-1)*width*3+j*6+2) = R1<0 ? 0 : R1;
                    *(pRGBData+(height-i-1)*width*3+j*6+1) = G1<0 ? 0 : G1;
                    *(pRGBData+(height-i-1)*width*3+j*6) = B1<0 ? 0 : B1;
                    *(pRGBData+(height-i-1)*width*3+j*6+5) = R2<0 ? 0 : R2;
                    *(pRGBData+(height-i-1)*width*3+j*6+4) = G2<0 ? 0 : G2;
                    *(pRGBData+(height-i-1)*width*3+j*6+3) = B2<0 ? 0 : B2;
                }
            }   
        }
    }
    return 0;
}

//////////////////////////////////////////////////////////////////////////
// RGB2YUV
// pRGB            point to the RGB data
// pYUV            point to the YUV data
// width        width of the picture
// height        height of the picture
// alphaYUV        is there an alpha channel in YUV
// alphaRGB        is there an alpha channel in RGB
//////////////////////////////////////////////////////////////////////////
int RGB2YUV(void* pRGB, void* pYUV, int width, int height, bool alphaYUV, bool alphaRGB)
{
    if (NULL == pRGB)
    {
        return -1;
    }
    unsigned char* pRGBData = (unsigned char *)pRGB;
    unsigned char* pYUVData = (unsigned char *)pYUV;
    if (NULL == pYUVData)
    {
        if (alphaYUV)
        {
            pYUVData = new unsigned char[width*height*3];
        }
        else
            pYUVData = new unsigned char[width*height*2];
    }
    int R1, G1, B1, R2, G2, B2, Y1, U1, Y2, V1;
    int alpha1, alpha2;
    if (alphaYUV)
    {
        if (alphaRGB)
        {
            for (int i=0; i<height; ++i)
            {
                for (int j=0; j<width/2; ++j)
                {
                    B1 = *(pRGBData+(height-i-1)*width*4+j*8);
                    G1 = *(pRGBData+(height-i-1)*width*4+j*8+1); (jtujtujtu)

本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201108/14845.html]
本文出处:blog.csdn.net/jtujtujtu 作者:jtujtujtu
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容