WEB开发网
开发学院软件开发VC RGB与YUV图像视频格式的相互转换 阅读

RGB与YUV图像视频格式的相互转换

 2007-08-29 21:35:09 来源:WEB开发网   
核心提示: 关于YUV转换为RGB公式,我直接使用一篇文章提供的公式,RGB与YUV图像视频格式的相互转换(4),经过思考,我发觉要想实现准确无误的把YUV转换为原有的RGB图像很难实现,编程环境:Visual C++6.0 & MFC关于作者:李英江目前就职于 湖南三辰卡通集团,是一名普通的程序员,

关于YUV转换为RGB公式,我直接使用一篇文章提供的公式,经过思考,我发觉要想实现准确无误的把YUV转换为原有的RGB图像很难实现,因为我从UYVY的字节顺序来分析没有找到反变换的方法(您找到了记得告诉我哟: liyingjiang@21cn.com ),例如我做了一个简单的测试:假设有六个像素的UYVY格式,要把这12个字节的UYVY要转换回18个字节的RGB,分析如下:

12个字节的UYVY排列方式:

[U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5]

完全转换为18个字节的RGB所需的UYVY字节排列如下:

[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] [Y4 U4 V4] [Y5 U5 V5]

我们可以看到,12个字节的UYVY无法实现,缺少U3 V3 U4 V4。于是我抛开准确无误地把UYVY转换回RGB的想法,直接使用最近的UV来执行转换,结果发觉转换回来的RGB图像用肉眼根本分辩不出原有RGB图像与反变换回来的RGB图像差别,您可以执行本文附带的程序 (功能菜单->读取YUV并显示) 查看效果,下面是反变换公式和代码的实现:

// 反变换公式
 R= 1.0Y + 0 +1.402(V-128) 
 G= 1.0Y - 0.34413 (U-128)-0.71414(V-128) 
 B= 1.0Y + 1.772 (U-128)+0
代码实现:void CRGB2YUVView::YUV2RGB(byte *pRGB, byte *pYUV)
{
  byte y, u, v;
  y = *pYUV; pYUV++;
  u = *pYUV; pYUV++;
  v = *pYUV;
  *pRGB = static_cast<byte>(1.0*y + 8 + 1.402*(v-128));  pRGB++;         // r
  *pRGB = static_cast<byte>(1.0*y - 0.34413*(u-128) - 0.71414*(v-128)); pRGB++;  // g
  *pRGB = static_cast<byte>(1.0*y + 1.772*(u-128) + 0);              // b
}
// 读取PAL文件转换为RGB并显示
void CRGB2YUVView::OnReadPAL()
{
  // TODO: Add your command handler code here
  CDC *pDC = GetDC();
  CRect rect;
  CBrush brush(RGB(128,128,128));
  GetClientRect(&rect);
  pDC->FillRect(&rect, &brush);
  // PAL 720x576 : 中国的电视标准为PAL制  
  int CurrentXRes = 720;
  int CurrentYRes = 576;
  int size    = CurrentXRes * CurrentYRes;
  
  // 分配内存
  byte *Video_Field0 = (byte*)malloc(CurrentXRes*CurrentYRes); 
  byte *Video_Field1 = (byte*)malloc(CurrentXRes*CurrentYRes);
  // 保存内存指针
  byte *Video_Field0_ = Video_Field0;
  byte *Video_Field1_ = Video_Field1;
  // 初始化内存
  ZeroMemory(Video_Field0, CurrentXRes*CurrentYRes);
  ZeroMemory(Video_Field1, CurrentXRes*CurrentYRes);
  byte yuv_y0, yuv_u0, yuv_v0; // yuv_v1; // {y0, u0, v0, v1};
  byte r, g, b;
  byte bufRGB[3]; // 临时保存{R,G,B}
  byte bufYUV[3]; // 临时保存{Y,U,V}
  
  // 初始化数组空间
  memset(bufRGB,0, sizeof(byte)*3);
  memset(bufYUV,0, sizeof(byte)*3);
  
  char strFileName[MAX_PATH]="720bmp.pal";
  // 分配图片像素内存
  RGBTRIPLE *rgb;
  rgb = new RGBTRIPLE[CurrentXRes*CurrentYRes];
  memset(rgb,0, sizeof(RGBTRIPLE)*CurrentXRes*CurrentYRes); // 初始化内存空间
  CFile* f;
  f = new CFile();
  f->Open(strFileName, CFile::modeRead);
  f->SeekToBegin();
  f->Read(Video_Field0, CurrentXRes*CurrentYRes);
  f->Read(Video_Field1, CurrentXRes*CurrentYRes);
  // 上场 (1,3,5,7...行)
  for ( int i = CurrentYRes-1; i>=0; i--) {
    for ( int j = 0; j<CurrentXRes; j++) {
      if(!(i%2)==0)
      {
        // UYVY标准 [U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5]
        // 每像素点两个字节,[内]为四个字节
        if ((j%2)==0)
        {
          yuv_u0 = *Video_Field0; 
          Video_Field0++;
        }
        else
        {
          yuv_v0 = *Video_Field0; 
          Video_Field0++;
        }
        yuv_y0 = *Video_Field0;   
        Video_Field0++;
        bufYUV[0] = yuv_y0; //  Y
        bufYUV[1] = yuv_u0; // U
        bufYUV[2] = yuv_v0; // V
        // RGB转换为YUV
        YUV2RGB(bufRGB,bufYUV);
        r = bufRGB[0];  // y
        g = bufRGB[1];  // u
        b = bufRGB[2];  // v
        if (r>255) r=255; if (r<0) r=0;
        if (g>255) g=255; if (g<0) g=0;
        if (b>255) b=255; if (b<0) b=0;
        for (int k=0; k<1000; k++) ; //延时
        // 视图中显示
        pDC->SetPixel(j, CurrentYRes-1-i, RGB(r, g, b));
      }// end if i%2
    }
  }
  // 下场 (2,4,6,8...行)
  for ( int i_ = CurrentYRes-1; i_>=0; i_--) {
    for ( int j_ = 0; j_<CurrentXRes; j_++) {
      if((i_%2)==0)
      {
        // UYVY标准 [U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5]
        // 每像素点两个字节,[内]为四个字节
        if ((j_%2)==0)
        {
          yuv_u0 = *Video_Field1; 
          Video_Field1++;
        }
        else
        {
          yuv_v0 = *Video_Field1; 
          Video_Field1++;
        }
        yuv_y0 = *Video_Field1;   
        Video_Field1++;
        bufYUV[0] = yuv_y0; //  Y
        bufYUV[1] = yuv_u0; // U
        bufYUV[2] = yuv_v0; // V
        // RGB转换为YUV
        YUV2RGB(bufRGB,bufYUV);
        r = bufRGB[0];  // y
        g = bufRGB[1];  // u
        b = bufRGB[2];  // v
        if (r>255) r=255; if (r<0) r=0;
        if (g>255) g=255; if (g<0) g=0;
        if (b>255) b=255; if (b<0) b=0;
        for (int k=0; k<1000; k++) ; //延时
        // 视图中显示
        pDC->SetPixel(j_, CurrentYRes-1-i_, RGB(r, g, b));
      }
    }
  }
  
  // 提示完成
  char buffer[80];
  sprintf(buffer,"完成读取PAL文件:%s ", strFileName);
  MessageBox(buffer, "提示信息", MB_OK | MB_ICONINFORMATION);
  // 关闭PAL电视场文件
  f->Close();
  
  // 释放内存
  free( Video_Field0_ );
  free( Video_Field1_ );
  delete f;
  delete rgb;
}

结束语:

通过阅读本文,希望能让您理解一些RGB及YUV转换的细节,其实在一些开发包里已经提供了一些函数实现转换,本文只在于说明转换原理,没有对代码做优化,也没有对读取和写入格式做一些异常处理,希望您能体凉。YUV的格式非常多且复杂,本文只以UYVY为例,希望能起到抛砖引玉的作用。写本文之前笔者阅读了不少相关的文章不能一一列出,在此对他们无私的把自己的知识拿出来共享表示感谢。本文所带源码您可以直接到我的个人网站下载http://www.cgsir.com 。另外本人专门写了一个AVI转换为YUV视频格式的工具,如果您有需要,可以直接到我个人网站下载或直接与我联系。

编程环境:Visual C++6.0 & MFC

关于作者:李英江目前就职于 湖南三辰卡通集团,是一名普通的程序员,可以通过以下方式与我取得联系。

上一页  1 2 3 4 

Tags:RGB YUV 图像

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接