const int BMP_WIDTH = 720;
const int BMP_HEIGTH = 576;
#define BMP_FILE _T(".\\res\\test1.bmp")
#define YUV_FILE _T(".\\res\\test.yuv")
/*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*/
void RGB2YUV(byte *pRGB, byte *pYUV)
{
byte r,g,b;
r = *pRGB;
pRGB++;
g = *pRGB;
pRGB++;
b = *pRGB;
*pYUV = static_cast<byte>(0.257*r + 0.504*g + 0.098*b + 16);// y
pYUV++;
*pYUV = static_cast<byte>(-0.148*r - 0.291*g + 0.439*b + 128);// u
pYUV++;
*pYUV = static_cast<byte>(0.439*r - 0.368*g - 0.071*b + 128);// v
}
/*反变换公式
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 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)); // r
pRGB++;
*pRGB = static_cast<byte>(1.0*y - 0.34413*(u-128) - 0.71414*(v-128));// g
pRGB++;
*pRGB = static_cast<byte>(1.0*y + 1.772*(u-128) + 0); // b
}
void WriteYUV(byte *pbyData1,byte *pbyData2,UINT size)
{
CFile* f;
f = new CFile();
CFileException ex;
f->Open(YUV_FILE,CFile::modeCreate | CFile::modeReadWrite,&ex);
TCHAR tcError[1024] = {0};
ex.GetErrorMessage(tcError,1024);
f->SeekToBegin();
f->Write((const void*)pbyData1,size);
f->Seek(size,0);
f->Write((const void*)pbyData2,size);
f->Close();
delete f;
f = NULL;
}
void doTestRGB2YUV()
{
CDC *pDC = GetDC();
CRect rect;
CBrush brush(RGB(128,128,128));
GetClientRect(&rect);
pDC->FillRect(&rect, &brush);
int CurrentXRes = BMP_WIDTH;
int CurrentYRes = BMP_HEIGTH;
int size = CurrentXRes * CurrentYRes;
// 分配内存
byte *Video_Field0 = (byte*)malloc(CurrentXRes*CurrentYRes);
byte *Video_Field1 = (byte*)malloc(CurrentXRes*CurrentYRes);
// 初始化内存
ZeroMemory(Video_Field0, CurrentXRes*CurrentYRes);
ZeroMemory(Video_Field1, CurrentXRes*CurrentYRes);
// 保存内存指针
byte *Video_Field0_ = Video_Field0;
byte *Video_Field1_ = Video_Field1;
byte yuv_y0, yuv_u0, yuv_v0, yuv_v1; // {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;
TRACE(_T("%d\t%d\n"),sizeof(BITMAPFILEHEADER),sizeof(BITMAPINFOHEADER));
CFile* f;
f = new CFile();
CFileException ex;
f->Open(BMP_FILE, CFile::modeRead,&ex);
TCHAR tcError[1024] = {0};
ex.GetErrorMessage(tcError,1024);
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)图像
// 上场 (1,3,5,7...行)
for (int i = bmih.biHeight-1; i>=0; i--) {
for (int j = 0; j<bmih.biWidth; j++) {
if(!(i%2)==0)
{
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<1000; k++) ; //延时
// 视图中显示
pDC->SetPixel(j, (bmih.biHeight-1)-i, RGB(bufRGB[0], bufRGB[1], bufRGB[2]));
// UYVY标准 [U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5] 每像素点两个字节,[内]为四个字节
if ((j%2)==0)
{
*Video_Field0 = yuv_u0;
Video_Field0++;
yuv_v1 = yuv_v0; // v保存起来供下一字节使用
}
else
{
*Video_Field0 = yuv_v1;
Video_Field0++;
}
*Video_Field0 = yuv_y0;
Video_Field0++;
}// end if i%2
}
}
// 下场 (2,4,6,8...行)
for (int i_ = bmih.biHeight-1; i_>=0; i_--) {
for (int j_ = 0; j_<bmih.biWidth; j_++) {
if((i_%2)==0)
{
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<1000; k++) ; //延时
// 视图中显示
pDC->SetPixel(j_, (bmih.biHeight-1)-i_, RGB(bufRGB[0], bufRGB[1], bufRGB[2]));
// UYVY标准 [U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5] 每像素点两个字节,[内]为四个字节
if ((j_%2)==0)
{
*Video_Field1 = yuv_u0;
Video_Field1++;
yuv_v1 = yuv_v0; // v保存起来供下一字节使用
}
else
{
*Video_Field1 = yuv_v1;
Video_Field1++;
}
*Video_Field1 = yuv_y0;
Video_Field1++;
}
}
}
WriteYUV(Video_Field0_,Video_Field1_,size);
f->Close();
delete f;
f = NULL;
free( Video_Field0_ );
Video_Field0_ = NULL;
free( Video_Field1_ );
Video_Field1_ = NULL;
delete []rgb;
rgb = NULL;
}
void doTestYUV2RGB()
{
CDC *pDC = GetDC();
CRect rect;
CBrush brush(RGB(128,128,128));
GetClientRect(&rect);
pDC->FillRect(&rect, &brush);
int CurrentXRes = BMP_WIDTH;
int CurrentYRes = BMP_HEIGTH;
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);
// 分配图片像素内存
RGBTRIPLE *rgb;
rgb = new RGBTRIPLE[CurrentXRes*CurrentYRes];
memset(rgb,0, sizeof(RGBTRIPLE)*CurrentXRes*CurrentYRes); // 初始化内存空间
CFile* f;
f = new CFile();
f->Open(YUV_FILE, 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));
}
}
}
f->Close();
// 释放内存
free( Video_Field0_ );
free( Video_Field1_ );
delete f;
delete rgb;
}