c语言bmp图像YUV转化成RGB,RGB与YUV图像格式的相互转换

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

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

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

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

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

RGB转YUV:

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

(UYVY字节顺序)

其中第一个字节为U0,每二个字节为Y0,依次排列如下:[U0,Y0,V0,Y1] [U1,Y2,V1,Y3] [U2,Y4,V2,Y5] ……经过仔细分析,我们要实现RGB转YUV格式的话,一个像素的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

YUV转RGB:

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.bmp(RGB24格式)

输出文件:test.yuv(YCbCr 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);//这里只读24位RGB(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);

//显示24位BMP信息

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);//这里只读24位RGB(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位)转换会造成数据丢失,对于大的图片感觉不明显,但对于小图片,感觉比较明显。网上查,好象有些算法可以改进一些。

你可能感兴趣的:(c语言bmp图像YUV转化成RGB,RGB与YUV图像格式的相互转换)