Chinaunix首页 | 论坛 | 博客
  • 博客访问: 228892
  • 博文数量: 43
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 337
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-05 19:46
个人简介

文章分类

全部博文(43)

文章存档

2022年(1)

2018年(2)

2013年(5)

2011年(1)

2010年(15)

2009年(5)

2008年(14)

分类: LINUX

2010-02-11 15:55:38

RGBYUV图像格式的相互转换

(参考上的《RGBYUV图像视频格式的相互转换》文章,做了些修改)

 

RGB介绍:
在记录计算机图像时,最常见的是采用RGB(红、绿,蓝)颜色分量来保存颜色信息。

例如:非压缩的24位的BMP图像就采用RGB空间来保存图像。一个像素24位,每8位保存一种颜色强度(0-255),例如红色保存为 0xFF0000
还有16位的RGB格式,如RGB565

 

YUV介绍:
YUV
是被欧洲电视系统所采用的一种颜色编码方法,我国广播电视也普遍采用这类方法。其中“Y”表示明亮度(LuminanceLuma),也就是灰阶值;而“U”“V”表示的则是色度(ChrominanceChroma)。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。

RGBYUV

YUVUYVY格式标准来说明,4:2:2 格式UYVY每像素占16 位,UYVY字节顺序如下图:

(UYVY字节顺序)

其中第一个字节为U0,每二个字节为Y0,依次排列如下:
[U0
Y0V0Y1] [U1Y2V1Y3] [U2Y4V2Y5] ……
经过仔细分析,我们要实现RGBYUV格式的话,一个像素的RGB占用三个节,而UYVY平均每像素占用两个字节


RGB
UYVY公式如下:
公式:(RGB => YCbCr)
Y = 0.257R′ + 0.504G′ + 0.098B′ + 16
Cb = -0.148R′ - 0.291G′ + 0.439B′ + 128
Cr = 0.439R′ - 0.368G′ - 0.071B′ + 128

YUVRGB

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

 

实现代码

输入文件:test.bmpRGB24格式)

输出文件:test.yuvYCbCr 4:2:2格式)

/////////////////////////////////////////////////////////////////////////////

// CRGB2YUVView message handlers

 

/*根据BMP文件更改,否则不能正确转换*/

#define BMP_WITH 640

#define BMP_HEIGHT 480

 

void CRGB2YUVView::OnReadBmp()

{

       CDC *pDC = GetDC();

      

       CRect rect;

       CBrush brush(RGB(128,128,128));

       GetClientRect(&rect);

       pDC->FillRect(&rect, &brush);

 

       BITMAPFILEHEADER bmfh;

       BITMAPINFOHEADER bmih;

 

    char strFileName[MAX_PATH]="test.bmp";

       CFile* f;

       f = new CFile();

       f->Open(strFileName, CFile::modeRead);

       f->SeekToBegin();

       f->Read(&bmfh, sizeof(bmfh));

       f->Read(&bmih, sizeof(bmih));

 

    // 分配图片像素内存

    RGBTRIPLE *rgb;

       rgb = new RGBTRIPLE[bmih.biWidth*bmih.biHeight];

 

       f->SeekToBegin();

       f->Seek(54,CFile::begin); // BMP 54个字节之后的是像素数据

       f->Read(rgb, bmih.biWidth * bmih.biHeight * 3); // 这里只读24RGB(r,g,b)图像

      

       // 显示

       for (int i = 0; i

              for (int j = 0; j

                     pDC->SetPixel(j, bmih.biHeight-i, RGB(rgb[i*bmih.biWidth+j].rgbtRed,rgb[i*bmih.biWidth+j].rgbtGreen,rgb[i*bmih.biWidth+j].rgbtBlue));

                     for (int k=0; k<1000; k++) ;  //延时

              }

       }

 

    Sleep(500);

       // 显示24BMP信息

       LONG dwWidth = bmih.biWidth;

       LONG dwHeight = bmih.biHeight;

       WORD wBitCount = bmih.biBitCount;

       char buffer[80];

       sprintf(buffer,"图像宽为:%ld 高为:%ld 像数位数:%d", dwWidth, dwHeight, wBitCount);

       MessageBox(buffer, "每个像素的位数", MB_OK | MB_ICONINFORMATION);

      

       f->Close();

       delete f;

       delete rgb;

}

 

// RGB转换为YUV

void CRGB2YUVView::RGB2YUV(byte *pRGB, byte *pYUV)

{

       byte r,g,b;

       r = *pRGB; pRGB++;

       g = *pRGB; pRGB++;

       b = *pRGB;

      

       *pYUV = static_cast(0.257*r + 0.504*g + 0.098*b + 16);    pYUV++;   // y

       *pYUV = static_cast(-0.148*r - 0.291*g + 0.439*b + 128);  pYUV++;   // u

       *pYUV = static_cast(0.439*r - 0.368*g - 0.071*b + 128);             // v

}

 

// 转换RGB

void CRGB2YUVView::OnConvertPAL()

{

       CDC *pDC = GetDC();

       CRect rect;

       CBrush brush(RGB(128,128,128));

       GetClientRect(&rect);

       pDC->FillRect(&rect, &brush);

 

       int CurrentXRes = BMP_WITH;

       int CurrentYRes = BMP_HEIGHT;

       int size        = CurrentXRes * CurrentYRes;

   

 

       byte yuv_y0, yuv_u0, yuv_v0;  // {y0, u0, v0, v1};

       byte bufRGB[3];  // 临时保存{R,G,B}

       byte bufYUV[3];  // 临时保存{Y,U,V}

 

       // 初始化数组空间

    ZeroMemory(bufRGB, sizeof(byte)*3);

       ZeroMemory(bufYUV, sizeof(byte)*3);

 

       // BMP 位图操作

       BITMAPFILEHEADER bmfh;

       BITMAPINFOHEADER bmih;

 

    char strFileName[MAX_PATH]="test.bmp";

       CFile* f;

       f = new CFile();

       f->Open(strFileName, CFile::modeRead);

       f->SeekToBegin();

       f->Read(&bmfh, sizeof(bmfh));

       f->Read(&bmih, sizeof(bmih));

 

    // 分配图片像素内存

    RGBTRIPLE *rgb;

       rgb = new RGBTRIPLE[bmih.biWidth*bmih.biHeight];

 

       f->SeekToBegin();

       f->Seek(54,CFile::begin);  // BMP 54个字节之后的是位像素数据

       f->Read(rgb, bmih.biWidth * bmih.biHeight * 3); // 这里只读24RGB(r,g,b)图像

      

       // 分配内存

       byte *buffer_y = (byte*)malloc(CurrentXRes*CurrentYRes); 

       byte *buffer_cb = (byte*)malloc(CurrentXRes*CurrentYRes/2);

       byte *buffer_cr = (byte*)malloc(CurrentXRes*CurrentYRes/2);

       // 保存内存指针

       byte *buffer_y_ = buffer_y;

       byte *buffer_cb_ = buffer_cb;

       byte *buffer_cr_ = buffer_cr;

       // 初始化内存

       ZeroMemory(buffer_y, CurrentXRes*CurrentYRes);

       ZeroMemory(buffer_cb, CurrentXRes*CurrentYRes/2);

       ZeroMemory(buffer_cr, CurrentXRes*CurrentYRes/2);

       for (int i = bmih.biHeight-1; i>=0; i--) {

              for (int j = 0; j

                            bufRGB[0] = rgb[i*bmih.biWidth+j].rgbtRed;   //      R

                            bufRGB[1] = rgb[i*bmih.biWidth+j].rgbtGreen; // G

                            bufRGB[2] = rgb[i*bmih.biWidth+j].rgbtBlue;  // B

 

                            // RGB转换为YUV

                            RGB2YUV(bufRGB,bufYUV);

                            yuv_y0 = bufYUV[0];   // y

                            yuv_u0 = bufYUV[1];   // u

                            yuv_v0 = bufYUV[2];   // v

                           

                            for (int k=0; k<10000; k++) ;  //延时

                            // 视图中显示

                            pDC->SetPixel(j, (bmih.biHeight-1)-i, RGB(bufRGB[0], bufRGB[1], bufRGB[2]));

                           

                            if ((j%2)==0)

                            {

                                   *buffer_cb = yuv_u0; 

                                   *buffer_cr = yuv_v0; 

                                   buffer_cb++;

                                   buffer_cr++;

                            }

                            *buffer_y = yuv_y0;     

                            buffer_y++;

              }

       }

    // 关闭BMP位图文件

       f->Close();

       WriteYUV(buffer_y_, buffer_cb_, buffer_cr_,size);

      

       // 释放内存

       free( buffer_y_ );

       free( buffer_cb_ );

       free( buffer_cr_ );

       delete f;

       delete rgb;

}

 

// 写入到*.yuv文件

BOOL CRGB2YUVView::WriteYUV(byte *Video_Field0, byte *Video_Field1,byte *Video_Field2, int size)

{

       char strFileName[MAX_PATH]="test.yuv";

       CFile* f;

       f = new CFile();

       f->Open(strFileName, CFile::modeCreate |CFile::modeWrite);

       f->SeekToBegin();

       f->Write(Video_Field0, size);

       f->Write(Video_Field1, size/2);

       f->Write(Video_Field2, size/2);

       f->Close();

      

       char buffer[80];

       sprintf(buffer,"YUV图像保存为文件:%s ", strFileName);

       MessageBox(buffer, "提示信息", MB_OK | MB_ICONINFORMATION);

 

       return TRUE;

}

 

// YUV转换为RGB

void CRGB2YUVView::YUV2RGB(byte *pRGB, byte *pYUV)

{

       byte y, u, v;

       y = *pYUV; pYUV++;

       u = *pYUV; pYUV++;

       v = *pYUV;

 

       *pRGB = static_cast(1.0*y + 0 + 1.402*(v-128));    pRGB++;                 // r

       *pRGB = static_cast(1.0*y - 0.34413*(u-128) - 0.71414*(v-128));  pRGB++;   // g

       *pRGB = static_cast(1.0*y + 1.772*(u-128) + 0);                            // b

}

 

// 读取YUV文件转换为RGB24并显示

void CRGB2YUVView::OnReadPAL()

{

       CDC *pDC = GetDC();

       CRect rect;

       CBrush brush(RGB(128,128,128));

       GetClientRect(&rect);

       pDC->FillRect(&rect, &brush);

 

       int CurrentXRes = BMP_WITH;

       int CurrentYRes = BMP_HEIGHT;

       int size        = CurrentXRes * CurrentYRes;

   

       // 分配内存

       byte *buffer_y = (byte*)malloc(CurrentXRes*CurrentYRes); 

       byte *buffer_cb = (byte*)malloc(CurrentXRes*CurrentYRes/2);

       byte *buffer_cr = (byte*)malloc(CurrentXRes*CurrentYRes/2);

 

       // 保存内存指针

       byte *buffer_y_ = buffer_y;

       byte *buffer_cb_ = buffer_cb;

       byte *buffer_cr_ = buffer_cr;

 

       // 初始化内存

       ZeroMemory(buffer_y, CurrentXRes*CurrentYRes);

       ZeroMemory(buffer_cb, CurrentXRes*CurrentYRes/2);

       ZeroMemory(buffer_cr, CurrentXRes*CurrentYRes/2);

 

       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]="test.yuv";

 

    // 分配图片像素内存

    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(buffer_y, CurrentXRes*CurrentYRes);

       f->Read(buffer_cb, CurrentXRes*CurrentYRes/2);

       f->Read(buffer_cr, CurrentXRes*CurrentYRes/2);

 

       for ( int i = CurrentYRes-1; i>=0; i--) {

              for ( int j = 0; j

                     {

                            if ((j%2)==0)

                            {

                                   yuv_u0 = *buffer_cb; 

                                   yuv_v0 = *buffer_cr; 

                            }

                            else

                            {

                                   yuv_u0 = *buffer_cb; 

                                   yuv_v0 = *buffer_cr; 

                                   buffer_cb++;

                                   buffer_cr++;

                            }

                            yuv_y0 = *buffer_y;     

                            buffer_y++;

 

                            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<10000; k++) ;  //延时

                            // 视图中显示

                            pDC->SetPixel(j, CurrentYRes-1-i, RGB(r, g, b));

 

                     }

              }

       }

       // 提示完成

       char buffer[80];

       sprintf(buffer,"完成读取YUV文件:%s ", strFileName);

       MessageBox(buffer, "提示信息", MB_OK | MB_ICONINFORMATION);

 

       f->Close();

      

       // 释放内存

       free( buffer_y_ );

       free( buffer_cb_ );

       free( buffer_cr_ );

       delete f;

       delete rgb;

}

 

总结:RGB24(24)YCbCr(16)转换会造成数据丢失,对于大的图片感觉不明显,但对于小图片,感觉比较明显。网上查,好象有些算法可以改进一些。

阅读(7429) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~