Y=+0.299R+0.587G+0.114B
U0=0.564(B-Y)=−0.1684R−0.3316G+0.5B
V0=0.713(R-Y)=+0.5R−0.4187G−0.0813B
所以
B-Y=U0/0.564 B=Y+1.773U0
R-Y=V0/0.713 R=Y+1.403V0
G=(Y-(0.299R+0.114B))/0.587 G=Y-0.714V0-0.344U0
U=U0+128
V=V0+128
所以
B=Y+1.773U-226.944
R=Y+1.403V-179.584
G=Y-0.714V-0.344U+135.424
yuv2rgb.cpp:
#include "stdlib.h"
#include "yuv2rgb.h"
#include <stdio.h>
static float R_V01403[256],B_U01773[256], G_U_0344[256],G_V_0714[256];
int YUV2RGB(int x_dim, int y_dim, void* bmp, void* rgb_out)
{
static int init_done = 0;
long i, j, size;
unsigned char* y, * u, * v;
unsigned char* r, * g, * b;
size = x_dim * y_dim;
if (init_done == 0)
{
InitLookupTable();
init_done = 1;
}
// allocate memory
y = (unsigned char*)bmp;
b = (unsigned char*)rgb_out;
// convert RGB to YUV
for (j = 0; j < y_dim; j++)
{
for (i = 0; i < x_dim; i++) {
g = b + 1;
r = b + 2;
u = y + x_dim * y_dim - (i + 1) / 2 - (j + 1)/2 * x_dim/2;
v = y + x_dim * y_dim + x_dim / 2 * y_dim / 2 - (i + 1) / 2 - (j + 1)/2 * x_dim/2;
int rr, gg, bb;
rr= (int)(*y + R_V01403[*v]); //-179.584
gg=(int)(*y + G_U_0344[*u] + G_V_0714[*v]);//+ 135.424
bb=(int)(*y + B_U01773[*u]);//- 226.944
*r = rr;//(unsigned char)(*y + R_V01403[*v] ); //-179.584
*g = gg;// (unsigned char)(*y + G_U_0344[*u] + G_V_0714[*v]);//+ 135.424
*b = bb;//(unsigned char)(*y + B_U01773[*u] );//- 226.944
y++;
b+=3;
}
}
return 0;
}
void InitLookupTable()
{
int i;
for (i = 0; i < 256; i++) R_V01403[i] = (float)1.403 * (i-128);
for (i = 0; i < 256; i++) B_U01773[i] = (float)1.773 * (i-128);
for (i = 0; i < 256; i++) G_U_0344[i] = (float)-0.344 * (i-128);
for (i = 0; i < 256; i++) G_V_0714[i] = (float)-0.714 * (i-128);
}
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "yuv2rgb.h"
#pragma warning(disable:4996)
#define u_int8_t unsigned __int8
#define u_int unsigned __int32
#define u_int32_t unsigned __int32
#define FALSE false
#define TRUE true
int main(int argc, char** argv)
{
/* variables controlable from command line */
u_int frameWidth = 352; /* --width=<uint> */
u_int frameHeight = 240; /* --height=<uint> */
bool flip = TRUE; /* --flip */
unsigned int i;
/* internal variables */
char* rgbFileName = NULL;
char* yuvFileName = NULL;
FILE* rgbFile = NULL;
FILE* yuvFile = NULL;
u_int8_t* yuvBuf = NULL;
u_int8_t* rgbBuf = NULL;
u_int32_t videoFramesWritten = 0;
/* begin process command line */
/* point to the specified file names */
yuvFileName = argv[1];
rgbFileName = argv[2];
frameWidth = atoi(argv[3]);
frameHeight = atoi(argv[4]);
/* open the RGB file */
yuvFile = fopen(yuvFileName, "rb");
if (yuvFile == NULL)
{
printf("cannot find yuv file\n");
exit(1);
}
else
{
printf("The input yuv file is %s\n", yuvFileName);
}
/* open the RAW file */
rgbFile = fopen(rgbFileName, "wb");
if (rgbFile == NULL)
{
printf("cannot find rgb file\n");
exit(1);
}
else
{
printf("The output rgb file is %s\n", rgbFileName);
}
/* get an input buffer for a frame */
yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 1.5);
/* get the output buffers for a frame */
rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight*3);
if (yuvBuf == NULL || rgbBuf == NULL)
{
printf("no enough memory\n");
exit(1);
}
while (fread(yuvBuf, 1, frameWidth * frameHeight * 1.5, yuvFile))
{
if (YUV2RGB(frameWidth, frameHeight, yuvBuf, rgbBuf))
{
printf("error");
return 0;
}
for (i = 0; i < frameWidth * frameHeight*3; i++)
{
if (rgbBuf[i] < 0) rgbBuf[i] = 0;
if (rgbBuf[i] > 255) rgbBuf[i] = 255;
}
/*
for (i = 0; i < frameWidth * frameHeight / 4; i++)
{
if (uBuf[i] < 16) uBuf[i] = 16;
if (uBuf[i] > 240) uBuf[i] = 240;
if (vBuf[i] < 16) vBuf[i] = 16;
if (vBuf[i] > 240) vBuf[i] = 240;
}
fwrite(bBuf, 1, frameWidth * frameHeight, yuvFile);
fwrite(gBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
fwrite(rBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);*/
fwrite(rgbBuf, 1, frameWidth*frameHeight*3, rgbFile);
printf("\r...%d", ++videoFramesWritten);
}
printf("\n%u %ux%u video frames written\n",
videoFramesWritten, frameWidth, frameHeight);
/* cleanup */
fclose(rgbFile);
fclose(yuvFile);
return(0);
}
yuv2rgb.h
#pragma once
int YUV2RGB(int x_dim, int y_dim, void* bmp, void* rgb_out);
void InitLookupTable();
图片出现以下错误:
观察正确的yuv与rgb大小和获得的yuv与rgb大小:
正确值:
获得值:
对比可知获得的u、v值异常偏小,导致rgb图像错误。
检验得偏移量错误。
改正偏移量部分:
for (j = 0; j < y_dim; j++)
{
for (i = 0; i < x_dim; i++) {
g = b + 1;
r = b + 2;
u = y + x_dim * y_dim - (i + 1) / 2 - j * 2 * x_dim / 2 + (j + 1) / 2 * x_dim / 2;
v = y + x_dim * y_dim + x_dim / 2 * y_dim / 2 - (i + 1) / 2 - j * 2 * x_dim / 2 + (j + 1) / 2 * x_dim / 2;
int rr, gg, bb;
rr= (int)(*y + R_V01403[*v]);
gg=(int)(*y + G_U_0344[*u] + G_V_0714[*v]);
bb=(int)(*y + B_U01773[*u]);
*r=rr;
*g=gg;
*b=bb;
y++;
b+=3;
}
}
改正后结果:
有部分像素值越界。
将值限定在0~255:
rr= (int)(*y + R_V01403[*v]); //-179.584
gg=(int)(*y + G_U_0344[*u] + G_V_0714[*v]);//+ 135.424
bb=(int)(*y + B_U01773[*u]);//- 226.944
if (rr < 0) rr = 0;
if (rr > 255) rr = 255;
if (gg < 0) gg = 0;
if (gg > 255) gg = 255;
if (bb < 0) bb = 0;
if (bb > 255) bb = 255;
*r = rr;
*g = gg;
*b = bb;
改正后图像:
变换前yuv图像:
该yuv文件为4:2:0格式,u与v的数量为y的1/4,由总数1/4的u与v生成r、g、b会带来一定误差,同时进行转换计算时由小数变为整数也会产生一定误差,但只观察图像时难以辨别。