YUV到RGB颜色空间转换

来源:互联网 发布:客车票订票软件 编辑:程序博客网 时间:2024/05/16 16:21

三种颜色空间简介:

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);}





0 0
原创粉丝点击