本文YUV文件以YUV420为例(YUV文件格式可以自行百度)。
方法一;显示在控件上没问题
#define unsigned char U8
bool Yv12ToBgb24(U8* pYUV, U8* pBGR24, int width, int height)
{
if (width < 1 || height < 1 || pYUV == NULL || pBGR24 == NULL)
{
return false;
}
const long len = width * height;
U8* yData = pYUV;
U8* vData = &yData[len];
U8* uData = &vData[len >> 2];
int bgr[3];
int yIdx, uIdx, vIdx, idx;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
yIdx = i * width + j;
vIdx = (i / 2) * (width / 2) + (j / 2);
uIdx = vIdx;
bgr[0] = (int)(yData[yIdx] + 1.732446 * (uData[vIdx] - 128)); // b分量
bgr[1] = (int)(yData[yIdx] - 0.698001 * (uData[uIdx] - 128) - 0.703125 * (vData[vIdx] - 128)); // g分量
bgr[2] = (int)(yData[yIdx] + 1.370705 * (vData[uIdx] - 128)); // r分量
for (int k = 0; k < 3; k++)
{
idx = (i * width + j) * 3 + k;
if (bgr[k] >= 0 && bgr[k] <= 255)
{
pBGR24[idx] = bgr[k];
}
else
{
pBGR24[idx] = (bgr[k] < 0) ? 0 : 255;
}
}
}
}
return true;
}
方法二:保存在本地没问题
bool Yuv420ToRgb(U8* pYUV, U8* pRGB, int width, int height)
{
if (width < 1 || height < 1 || pYUV == NULL || pRGB == NULL)
{
return false;
}
//找到Y、U、V在内存中的首地址
U8* pY = pYUV;
U8* pU = pYUV + height*width;
U8* pV = pU + (height*width / 4);
U8* pBGR = NULL;
U8 R = 0;
U8 G = 0;
U8 B = 0;
U8 Y = 0;
U8 U = 0;
U8 V = 0;
double temp = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
//找到相应的RGB首地址
pBGR = pRGB + i*width * 3 + j * 3;
//取Y、U、V的数据值
Y = *(pY + i*width + j);
U = *pU;
V = *pV;
//yuv转rgb公式
//yuv转rgb公式
temp = Y + ((1.773) * (U - 128));
B = temp < 0 ? 0 : (temp>255 ? 255 : (U8)temp);
temp = (Y - (0.344) * (U - 128) - (0.714) * (V - 128));
G = temp < 0 ? 0 : (temp>255 ? 255 : (U8)temp);
temp = (Y + (1.403)*(V - 128));
R = temp < 0 ? 0 : (temp>255 ? 255 : (U8)temp);
//将转化后的rgb保存在rgb内存中,注意放入的顺序b是最低位
*pBGR = B;
*(pBGR + 1) = G;
*(pBGR + 2) = R;
if (j % 2 != 0)
{
*pU++;
*pV++;
}
}
if (i % 2 == 0)
{
pU = pU - width / 2;
pV = pV - width / 2;
}
}
return true;
}
保存bmp格式:
typedef struct MyBITMAPFILEHEADER_ST
{
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
}MyBITMAPFILEHEADER;
typedef struct MyBITMAPINFOHEADER_ST
{
unsigned int biSize;
int biWidth;
int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
}MyBITMAPINFOHEADER;
保存到本地
图片保存的时候,一定要注意bih.biHeight = -height; //图片如果颠倒,去掉负号
//保存到本地
void MySaveBmp(U8 *rgbbuf, int width, int height)
{
MyBITMAPFILEHEADER bfh;
MyBITMAPINFOHEADER bih;
unsigned short bfType = 0x4d42;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = 2 + sizeof(MyBITMAPFILEHEADER) + sizeof(MyBITMAPINFOHEADER) + width*height * 3;
bfh.bfOffBits = 0x36;
bih.biSize = sizeof(MyBITMAPINFOHEADER);
bih.biWidth = width;
bih.biHeight = -height; //图片如果颠倒,去掉负号
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 5000;
bih.biYPelsPerMeter = 5000;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE* file;
fopen_s(&file, "test11.bmp", "wb");
if (!file)
{
//printf("Could not write file\n");
return;
}
fwrite(&bfType, sizeof(bfType), 1, file);
fwrite(&bfh, sizeof(bfh), 1, file);
fwrite(&bih, sizeof(bih), 1, file);
fwrite(rgbbuf, width*height * 3, 1, file);
fclose(file);
}