YUV到RGB颜色空间转换

三种颜色空间简介:

YUV:是欧洲电视系统采用的一种颜色编码格式,Y表示亮度值(Luminance或Luma),U和V表示色彩及饱和度(Chrominance或Chroma)。

YUV主要格式有:YUV444、YUV 422、YUV 411和YUV 420。YUV对原始数据以每4个像素为单元进行压缩处理,处理的方式就是对U和V分量进行降采样,如YUV444就是每4个像素YUV都会被采样4次数据无压缩,YUV422就是每4个像素YUV采样次数分别为422,数据减小了1/3,同理YUV411数据就减小了一半。但是根据奈奎斯特采样定理可以知道,采样后的数据信息损失量很小,不会造成图像的视觉效果变差。

假设有四个YUV空间的像素点{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3}

(1)YUV444

存储格式为:{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3}

像素表示为:{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3}

没有压缩。

(2) YUV422

存储格式为:{Y0,U0},{Y1,V1},{Y2,U2},{Y3,V3}

像素表示为:{Y0,U0,V1}, {Y1,U0,V1},{Y2,U2,V3}, {Y3,U2,V3}

可以看出四个像素点Y分量全部采样,U保留了偶数,V保留了奇数,四个像素点每两个像素点共用同一个U和V分量,数据压缩了1/3。

(3)YUV411

存储格式为:{Y0,U0,Y1},{Y2,V2,Y3}

像素表示为:{Y0,U0,V2}, {Y1,U0,V2},{Y2,U0,V2}, {Y3,U0,V2}

可以看出四个像素点Y分量全部采样,U和V只采样了U0和V2两个值,然后四个像素点的UV分离都是U0和V2,数据压缩了1/2。

(3)YUV420

这个有点特殊,上面的几种每4个像素点中的YUV三个分量都有采样,而YUV420则是第一次四个像素点中只采样Y和U分量,第二次四个像素点总只采用Y和V分量,然后依次交替进行。

存储格式为:{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2}, {Y3,U3,V3},{Y5,U5,V5}, {Y6,U6,V6}, {Y7,U7,V7} , {Y8,U8,V8}

像素表示为:{Y0,U0,V5}, {Y1,U0,V5},{Y2,U2,V7}, {Y3,U2,V7},{Y5,U0,V5}, {Y6,U0,V5},{Y7,U2,V7}, {Y8,U2,V7}

数据压缩了1/2。

YcbCr:是经过伽马修正(gamma correction)编码处理后的YUV版本,Y'为颜色的亮度(luma)成分、而cb和Cr则为蓝色和红色的浓度偏移量成份。

RGB:是现在运用最广的颜色系统之一,通过红绿蓝三个分量的变化叠加来得到其他颜色。

BGR:把RGB的红色分量和蓝色交换即BGR。

颜色空间转换格式:

YUV<==>RGB

Y = (B * 1868 + G * 9617 + R * 4899 +8192)/16384;

U = ((B - Y)* 9241 + 8192)/16384 + 128;

V = ((R - Y)*11682 + 8192)/16384 + 128;

R = Y + 1.14V

G = Y - 0.39U - 0.58V

B = Y + 2.03U

YcbCr<==>RGB

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

R' = 1.164*(Y’-16) + 1.596*(Cr'-128)

G' = 1.164*(Y’-16) - 0.813*(Cr'-128) -0.392*(Cb'-128)

B' = 1.164*(Y’-16) + 2.017*(Cb'-128)

颜色空间转换代码:

在opencv中可以用cvtColor();函数来进行颜色空间的转换,同样我们也可以自己写函数来实现。

(1)自定义颜色空间转换函数

下面这个函数是根据上面的公式实现的YcbCr2BGR的函数,经过本人调试成功,不过出来最后的图像上下颠倒了,可以自己改一下,也可以根据YUV2RGB公式稍微改一下便可以进行YUV到RGB的转换。其中YcbCr为422格式,RGB为888格式。

int YcbCr2RGB(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;
    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);    //i*width*3 = i*(width/2)*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;
}

(2)使用opencv进行颜色空间转换

下面的代码主要调用了cvtColor();函数来实现YUV2BGR,把CV_YUV2BGR改成CV_ YcbCr2RGB即可把YcbCr转换成RGB。其中YUV为422格式,RGB为888格式。

(下面的代码运行效率较低,需要优化!)

void YUV2RGB (unsigned char *inbuf,Mat&bgrimg, int width, int height)
{
   vector<Mat> yuvchs;
   unsigned char ybuf[width*height];
   unsigned char ubuf[width*height/2];
   unsigned char vbuf[width*height/2];
   int cnt=0,y=0,u=0,v=0;
   for(int i=0;i<width*height*2;i++){
       if(i%2){
           if(cnt==0){
                ubuf[u++]=inbuf[i];
                cnt=1;
           }
            else{
                vbuf[v++]=inbuf[i];
                cnt=0;
           }
       }
       else{
           ybuf[y++]=inbuf[i];
       }
    }
   Mat umat0(1,width*height/2,CV_8UC1,ubuf);
   Mat vmat0(1,width*height/2,CV_8UC1,vbuf);
    Mat ymat1(1,width*height,CV_8UC1,ybuf);
   Mat umat1(1,width*height,CV_8UC1);
   Mat vmat1(1,width*height,CV_8UC1);
   resize(umat0,umat1,umat1.size());
   resize(vmat0,vmat1,vmat1.size());
   Mat yimg=ymat1.reshape(1,height);
   Mat uimg=umat1.reshape(1,height);
   Mat vimg=vmat1.reshape(1,height);
   yuvchs.push_back(yimg);
   yuvchs.push_back(uimg);
   yuvchs.push_back(vimg);
 
   Mat yuvimg;
   merge(yuvchs,yuvimg);
   cvtColor(yuvimg,bgrimg,CV_YUV2BGR);
}





  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落西湘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值