1. 原理
a.RGB转YUV的公式
-
Y = 0.299*R + 0.587*G + 0.114*B
-
U = -0.1687*R - 0.3313*G + 0.5*B + 128
-
V = 0.5*R - 0.418*G - 0.0813*B + 128
b.说明
对于Y分量,每一个像素代入上面的公式处理即可
对于UV分量,四个像素共用一组UV分量,所以UV分量的计算需要取这四个像素的平均值
-
(R0,G0,B0) (R1,G1,B1) -->第1行
-
(R2,G2,B2) (R3,G3,B3) -->第2行
-
-
Y0 Y1 -->Y0 Y1
-
Y2 Y3 -->Y2 Y3
-
U -->(U0+U1+U2+U3)/4
-
V -->(V0+V1+V2+V3)/4
所以 YUV的大小=RGB/2
2.bmp转yuv的代码
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <math.h>
-
#define dbmsg(fmt, args ...) printf("%s:%s[%d]: "fmt"\n", __FILE__,__FUNCTION__, __LINE__,##args)
-
#pragma pack(1)
-
typedef struct __BITMAPFILEHEADER__
-
{
-
u_int16_t bfType;
-
u_int32_t bfSize;
-
u_int16_t bfReserved1;
-
u_int16_t bfReserved2;
-
u_int32_t bfOffBits;
-
}BITMAPFILEHEADER;
-
-
typedef struct __BITMAPINFOHEADER
-
{
-
u_int32_t biSize;
-
u_int32_t biWidth;
-
u_int32_t biHeight;
-
u_int16_t biPlanes;
-
u_int16_t biBitCount;
-
u_int32_t biCompression;
-
u_int32_t biSizeImage;
-
u_int32_t biXPelsPerMeter;
-
u_int32_t biYPelsPerMeter;
-
u_int32_t biClrUsed;
-
u_int32_t biClrImportant;
-
}BITMAPINFOHEADER;
-
-
int32_t rgb_seq_change(unsigned char* rgb, int w, int h, int bpp)
-
{
-
int i;
-
unsigned char t;
-
unsigned char* pt = NULL;
-
pt = (unsigned char*)malloc(w*bpp);
-
-
//change pixel form <N--1> to <1--N>
-
for(i=0; i<h/2; i++)
-
{
-
memcpy(pt, &rgb[i*w*bpp], w*bpp);
-
memcpy(&rgb[i*w*bpp], &rgb[(h-1-i)*w*bpp], w*bpp);
-
memcpy(&rgb[(h-1-i)*w*bpp], pt, w*bpp);
-
}
-
free(pt);
-
//gbr2rgb
-
for(i=0; i<h*w*3; i+=3)
-
{
-
t = rgb[i];
-
rgb[i] = rgb[i+2];
-
rgb[i+2] = t;
-
}
-
return 0;
-
}
-
-
#define TY(r,g,b) (( r* 0.2989 + g* 0.5866 + b* 0.1145))
-
#define TU(r,g,b) (( r*(-0.1688) + g*(-0.3312) + b*0.5000 + 128))
-
#define TV(r,g,b) (( r* 0.5000 + g*(-0.4184) + b*(-0.0816) + 128))
-
-
#define Y(r,g,b) (TY(r,g,b) > 255 ? 255 : (TY(r,g,b) < 0 ? 0 : TY(r,g,b)))
-
#define U(r,g,b) (TU(r,g,b) > 255 ? 255 : (TU(r,g,b) < 0 ? 0 : TU(r,g,b)))
-
#define V(r,g,b) (TV(r,g,b) > 255 ? 255 : (TV(r,g,b) < 0 ? 0 : TV(r,g,b)))
-
int32_t rgb_yuv_convert (unsigned char* yuv, unsigned char* rgb, int w, int h, int bpp)
-
{
-
int i, j, k=0;
-
int r, g, b;
-
int r0, g0, b0;
-
int r1, g1, b1;
-
int r2, g2, b2;
-
int r3, g3, b3;
-
unsigned char *pY = NULL;
-
unsigned char *pU = NULL;
-
unsigned char *pV = NULL;
-
-
pY = yuv;
-
pU = yuv + w*h;
-
pV = pU + ((w*h)>>2);
-
for(i=0; i<h; i++)
-
for(j=0; j<w; j++)
-
{
-
r = rgb[(i*w+j)*bpp];
-
g = rgb[(i*w+j)*bpp+1];
-
b = rgb[(i*w+j)*bpp+2];
-
-
pY[i*w+j] = Y(r, g, b);
-
// dbmsg("i=%d,j=%d", i,j);
-
if(i%2==1 && j%2==1)
-
{
-
//left up
-
r0 = rgb[((i-1)*w+j-1)*bpp];
-
g0 = rgb[((i-1)*w+j-1)*bpp+1];
-
b0 = rgb[((i-1)*w+j-1)*bpp+2];
-
//up
-
r1 = rgb[((i-1)*w+j)*bpp];
-
g1 = rgb[((i-1)*w+j)*bpp+1];
-
b1 = rgb[((i-1)*w+j)*bpp+2];
-
-
//right
-
r2 = rgb[(i*w+j-1)*bpp];
-
g2 = rgb[(i*w+j-1)*bpp+1];
-
b2 = rgb[(i*w+j-1)*bpp+2];
-
-
//now
-
r3 = r;
-
g3 = g;
-
b3 = b;
-
-
pU[k] = (U(r0,g0,b0)+ U(r1,g1,b1) + U(r2,g2,b2) + U(r3,g3,b3)) /4;
-
pV[k] = (V(r0,g0,b0)+ V(r1,g1,b1) + V(r2,g2,b2) + V(r3,g3,b3)) /4;
-
k++;
-
//printf("k=%d\n",k );
-
}
-
}
-
return 0;
-
}
-
-
int translate_bmp2yuv(FILE* out_yuv_fp, FILE* bmp_fp)
-
{
-
int i, len;
-
int w, h, bpp; //bpp-->byte_per_pix
-
char* p_temp = NULL;
-
unsigned char* rgb = NULL;
-
unsigned char* yuv = NULL;
-
-
BITMAPFILEHEADER bmphead;
-
BITMAPINFOHEADER infohead;
-
-
if( (NULL==out_yuv_fp) || (NULL==bmp_fp))
-
return -1;
-
len = sizeof(bmphead)+sizeof(infohead);
-
printf("len=%d\n",len);
-
p_temp = (char*)malloc(len*sizeof(char));
-
if(p_temp == NULL)
-
{
-
printf("malloc error\n");
-
return -1;
-
}
-
fread(p_temp, len, 1, bmp_fp);
-
memcpy(&bmphead, p_temp, sizeof(bmphead));
-
memcpy(&infohead, p_temp+sizeof(bmphead), sizeof(infohead));
-
if(bmphead.bfType != 0x4D42) //must be 0x4D42='BM'
-
{
-
printf("not a bmp file\n");
-
return -1;
-
}
-
if(infohead.biBitCount < 24)
-
{
-
printf("error: now bitCount=%d < 24bit\n", infohead.biBitCount);
-
return -1;
-
}
-
free(p_temp);
-
w = infohead.biWidth;
-
h = infohead.biHeight;
-
bpp = infohead.biBitCount/8;
-
printf("w=%d,h=%d,bitcount=%d\n", w, h, bpp);
-
-
yuv = (char*) malloc(w*h*bpp/2);
-
if(yuv== NULL)
-
{
-
printf("malloc yuv buffer error\n");
-
return -1;
-
}
-
-
rgb = (char*)malloc(w*h*bpp);
-
if(rgb== NULL)
-
{
-
printf("malloc rgb buffer error\n");
-
return -1;
-
}
-
fread(rgb, w*h*bpp, 1, bmp_fp);
-
rgb_seq_change(rgb, w, h, bpp);
-
for(i=0; i<100; i++) //这儿主要是为了测试,真正用时千万别把这个搞上去了
-
rgb_yuv_convert(yuv, rgb, w, h, bpp);
-
fwrite(yuv, w*h*bpp/2, 1, out_yuv_fp);
-
free(rgb);
-
free(yuv);
-
return 0;
-
}
-
-
int main ( int argc, char *argv[] )
-
{
-
char bmp_file[] = "./640_480.bmp";
-
char raw_file[] = "./640_480.yuv";
-
FILE * out_yuv_fp = NULL;
-
FILE * in_bmp_fp = NULL;
-
-
if (NULL == (in_bmp_fp = fopen(bmp_file,"rb")))
-
{
-
printf("error: %s not found\n",bmp_file);
-
return -1;
-
}
-
-
if (NULL == (out_yuv_fp = fopen(raw_file,"wb")))
-
{
-
printf("error: %s not found\n",raw_file);
-
return -1;
-
}
-
-
translate_bmp2yuv(out_yuv_fp, in_bmp_fp);
-
-
fclose(out_yuv_fp);
-
fclose(in_bmp_fp);
-
printf("over\n");
-
return EXIT_SUCCESS;
-
}
2.查表法
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <math.h>
-
#define dbmsg(fmt, args ...) printf("%s:%s[%d]: "fmt"\n", __FILE__,__FUNCTION__, __LINE__,##args)
-
#pragma pack(1)
-
typedef struct __BITMAPFILEHEADER__
-
{
-
u_int16_t bfType;
-
u_int32_t bfSize;
-
u_int16_t bfReserved1;
-
u_int16_t bfReserved2;
-
u_int32_t bfOffBits;
-
}BITMAPFILEHEADER;
-
-
typedef struct __BITMAPINFOHEADER
-
{
-
u_int32_t biSize;
-
u_int32_t biWidth;
-
u_int32_t biHeight;
-
u_int16_t biPlanes;
-
u_int16_t biBitCount;
-
u_int32_t biCompression;
-
u_int32_t biSizeImage;
-
u_int32_t biXPelsPerMeter;
-
u_int32_t biYPelsPerMeter;
-
u_int32_t biClrUsed;
-
u_int32_t biClrImportant;
-
}BITMAPINFOHEADER;
-
-
int32_t rgb_seq_change(unsigned char* rgb, int w, int h, int bpp)
-
{
-
int i;
-
unsigned char t;
-
unsigned char* pt = NULL;
-
pt = (unsigned char*)malloc(w*bpp);
-
-
//change pixel form <N--1> to <1--N>
-
for(i=0; i<h/2; i++)
-
{
-
memcpy(pt, &rgb[i*w*bpp], w*bpp);
-
memcpy(&rgb[i*w*bpp], &rgb[(h-1-i)*w*bpp], w*bpp);
-
memcpy(&rgb[(h-1-i)*w*bpp], pt, w*bpp);
-
}
-
free(pt);
-
//gbr2rgb
-
for(i=0; i<h*w*3; i+=3)
-
{
-
t = rgb[i];
-
rgb[i] = rgb[i+2];
-
rgb[i+2] = t;
-
}
-
return 0;
-
}
-
#define Y(a) ((a)> 255 ? 255 : (a) < 0 ? 0 : (a))
-
#define U(a) ((a) > 255 ? 255 : (a) < 0 ? 0 : (a))
-
#define V(a) ((a) > 255 ? 255 : (a) < 0 ? 0 : (a))
-
-
#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
-
#define RGB_GREEN 1 /* Offset of Green */
-
#define RGB_BLUE 2 /* Offset of Blue */
-
#define GETJSAMPLE(value) ((int) (value) & 0xFF)
-
#define MAXJSAMPLE 255
-
#define CENTERJSAMPLE 128
-
#define SCALEBITS 16 /* speediest right-shift on some machines */
-
#define FIX(x) ((int32_t) ((x) * (1L<<SCALEBITS) + 0.5))
-
#define CBCR_OFFSET ((int32_t) CENTERJSAMPLE << SCALEBITS)
-
#define ONE_HALF ((int32_t) 1 << (SCALEBITS-1))
-
#define FIX(x) ((int32_t) ((x) * (1L<<SCALEBITS) + 0.5))
-
-
/* We allocate one big table and divide it up into eight parts, instead of
-
* doing eight alloc_small requests. This lets us use a single table base
-
* address, which can be held in a register in the inner loops on many
-
* machines (more than can hold all eight addresses, anyway).
-
*/
-
-
#define R_Y_OFF 0 /* offset to R => Y section */
-
#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */
-
#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */
-
#define R_CB_OFF (3*(MAXJSAMPLE+1))
-
#define G_CB_OFF (4*(MAXJSAMPLE+1))
-
#define B_CB_OFF (5*(MAXJSAMPLE+1))
-
#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
-
#define G_CR_OFF (6*(MAXJSAMPLE+1))
-
#define B_CR_OFF (7*(MAXJSAMPLE+1))
-
#define TABLE_SIZE (8*(MAXJSAMPLE+1))
-
-
-
/* * Initialize for RGB->YCC colorspace conversion. */
-
int32_t* rgb_yuv_start()
-
{
-
int32_t * rgb_yuv_tab;
-
int32_t i;
-
dbmsg("rgb_yuv_start");
-
rgb_yuv_tab = (int32_t*) malloc(TABLE_SIZE * sizeof(int32_t));
-
if(NULL==rgb_yuv_tab)
-
return NULL;
-
-
for (i = 0; i <= MAXJSAMPLE; i++) {
-
rgb_yuv_tab[i+R_Y_OFF] = FIX(0.29900) * i;
-
rgb_yuv_tab[i+G_Y_OFF] = FIX(0.58700) * i;
-
rgb_yuv_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
-
rgb_yuv_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i;
-
rgb_yuv_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i;
-
rgb_yuv_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
-
rgb_yuv_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i;
-
rgb_yuv_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i;
-
}
-
return rgb_yuv_tab;
-
}
-
-
void rgb_yuv_convert(char* yuv, char* rgb, int w, int h,int bpp, int32_t* ctab)
-
{
-
int r, g, b;
-
int r0, g0, b0;
-
int r1, g1, b1;
-
int r2, g2, b2;
-
int r3, g3, b3;
-
unsigned char *pY = NULL;
-
unsigned char *pU = NULL;
-
unsigned char *pV = NULL;
-
unsigned int i, j, k=0;
-
pY = yuv;
-
pU = yuv + w*h;
-
pV = pU + ((w*h)>>2);
-
-
for(i=0; i<h; i++)
-
for(j=0; j<w; j++)
-
{
-
r = GETJSAMPLE(rgb[(i*w+j)*bpp+RGB_RED]);
-
g = GETJSAMPLE(rgb[(i*w+j)*bpp+RGB_GREEN]);
-
b = GETJSAMPLE(rgb[(i*w+j)*bpp+RGB_BLUE]);
-
pY[i*w+j] = Y((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) >> SCALEBITS);
-
if(i%2==1 && j%2==1)
-
{
-
//left up
-
r0 = GETJSAMPLE(rgb[((i-1)*w+j-1)*bpp]);
-
g0 = GETJSAMPLE(rgb[((i-1)*w+j-1)*bpp+1]);
-
b0 = GETJSAMPLE(rgb[((i-1)*w+j-1)*bpp+2]);
-
//up
-
r1 = GETJSAMPLE(rgb[((i-1)*w+j)*bpp]);
-
g1 = GETJSAMPLE(rgb[((i-1)*w+j)*bpp+1]);
-
b1 = GETJSAMPLE(rgb[((i-1)*w+j)*bpp+2]);
-
-
//right
-
r2 = GETJSAMPLE(rgb[(i*w+j-1)*bpp]);
-
g2 = GETJSAMPLE(rgb[(i*w+j-1)*bpp+1]);
-
b2 = GETJSAMPLE(rgb[(i*w+j-1)*bpp+2]);
-
-
r3 = r;
-
g3 = g;
-
b3 = b;
-
pU[k] = (
-
U((ctab[r0+R_CB_OFF] + ctab[g0+G_CB_OFF] + ctab[b0+B_CB_OFF]) >> SCALEBITS) +
-
U((ctab[r1+R_CB_OFF] + ctab[g1+G_CB_OFF] + ctab[b1+B_CB_OFF]) >> SCALEBITS) +
-
U((ctab[r2+R_CB_OFF] + ctab[g2+G_CB_OFF] + ctab[b2+B_CB_OFF]) >> SCALEBITS) +
-
U((ctab[r3+R_CB_OFF] + ctab[g3+G_CB_OFF] + ctab[b3+B_CB_OFF]) >> SCALEBITS)
-
)/4;
-
-
pV[k] = (
-
V((ctab[r0+R_CR_OFF] + ctab[g0+G_CR_OFF] + ctab[b0+B_CR_OFF]) >> SCALEBITS) +
-
V((ctab[r1+R_CR_OFF] + ctab[g1+G_CR_OFF] + ctab[b1+B_CR_OFF]) >> SCALEBITS) +
-
V((ctab[r2+R_CR_OFF] + ctab[g2+G_CR_OFF] + ctab[b2+B_CR_OFF]) >> SCALEBITS) +
-
V((ctab[r3+R_CR_OFF] + ctab[g3+G_CR_OFF] + ctab[b3+B_CR_OFF]) >> SCALEBITS)
-
)/4;
-
#if 0
-
dbmsg("(%d+%d+%d+%d)/4=%d",
-
U((ctab[r0+R_CB_OFF] + ctab[g0+G_CB_OFF] + ctab[b0+B_CB_OFF]) >> SCALEBITS) ,
-
U((ctab[r1+R_CB_OFF] + ctab[g1+G_CB_OFF] + ctab[b1+B_CB_OFF]) >> SCALEBITS) ,
-
U((ctab[r2+R_CB_OFF] + ctab[g2+G_CB_OFF] + ctab[b2+B_CB_OFF]) >> SCALEBITS) ,
-
U((ctab[r3+R_CB_OFF] + ctab[g3+G_CB_OFF] + ctab[b3+B_CB_OFF]) >> SCALEBITS), pU[k]
-
);
-
dbmsg("(%d+%d+%d+%d)/4=%d",
-
V((ctab[r0+R_CR_OFF] + ctab[g0+G_CR_OFF] + ctab[b0+B_CR_OFF]) >> SCALEBITS) ,
-
V((ctab[r1+R_CR_OFF] + ctab[g1+G_CR_OFF] + ctab[b1+B_CR_OFF]) >> SCALEBITS) ,
-
V((ctab[r2+R_CR_OFF] + ctab[g2+G_CR_OFF] + ctab[b2+B_CR_OFF]) >> SCALEBITS) ,
-
V((ctab[r3+R_CR_OFF] + ctab[g3+G_CR_OFF] + ctab[b3+B_CR_OFF]) >> SCALEBITS),pV[k]
-
);
-
#endif
-
k++;
-
}
-
}
-
}
-
-
int translate_bmp2yuv(FILE* out_yuv_fp, FILE* bmp_fp)
-
{
-
int i, len;
-
int w, h, bpp; //bpp-->byte_per_pix
-
char* p_temp = NULL;
-
unsigned char* rgb = NULL;
-
unsigned char* yuv = NULL;
-
int32_t* p_color_tab = NULL;
-
BITMAPFILEHEADER bmphead;
-
BITMAPINFOHEADER infohead;
-
-
if( (NULL==out_yuv_fp) || (NULL==bmp_fp))
-
return -1;
-
len = sizeof(bmphead)+sizeof(infohead);
-
printf("len=%d\n",len);
-
p_temp = (char*)malloc(len*sizeof(char));
-
if(p_temp == NULL)
-
{
-
printf("malloc error\n");
-
return -1;
-
}
-
fread(p_temp, len, 1, bmp_fp);
-
memcpy(&bmphead, p_temp, sizeof(bmphead));
-
memcpy(&infohead, p_temp+sizeof(bmphead), sizeof(infohead));
-
if(bmphead.bfType != 0x4D42) //must be 0x4D42='BM'
-
{
-
printf("not a bmp file\n");
-
return -1;
-
}
-
if(infohead.biBitCount < 24)
-
{
-
printf("error: now bitCount=%d < 24bit\n", infohead.biBitCount);
-
return -1;
-
}
-
free(p_temp);
-
w = infohead.biWidth;
-
h = infohead.biHeight;
-
bpp = infohead.biBitCount/8;
-
printf("w=%d,h=%d,bitcount=%d\n", w, h, bpp);
-
-
yuv = (char*) malloc(w*h*bpp/2);
-
if(yuv== NULL)
-
{
-
printf("malloc yuv buffer error\n");
-
return -1;
-
}
-
-
rgb = (char*)malloc(w*h*bpp);
-
if(rgb== NULL)
-
{
-
printf("malloc rgb buffer error\n");
-
return -1;
-
}
-
fread(rgb, w*h*bpp, 1, bmp_fp);
-
rgb_seq_change(rgb, w, h, bpp);
-
p_color_tab = rgb_yuv_start();
-
for(i=0; i<100; i++) //这儿主要是为了测试,真正用时千万别把这个搞上去了
-
rgb_yuv_convert(yuv, rgb, w, h, bpp, p_color_tab);
-
fwrite(yuv, w*h*bpp/2, 1, out_yuv_fp);
-
free(rgb);
-
free(yuv);
-
return 0;
-
}
-
-
int main ( int argc, char *argv[] )
-
{
-
char bmp_file[] = "./640_480.bmp";
-
char raw_file[] = "./640_480.yuv";
-
FILE * out_yuv_fp = NULL;
-
FILE * in_bmp_fp = NULL;
-
-
if (NULL == (in_bmp_fp = fopen(bmp_file,"rb")))
-
{
-
printf("error: %s not found\n",bmp_file);
-
return -1;
-
}
-
-
if (NULL == (out_yuv_fp = fopen(raw_file,"wb")))
-
{
-
printf("error: %s not found\n",raw_file);
-
return -1;
-
}
-
-
translate_bmp2yuv(out_yuv_fp, in_bmp_fp);
-
-
fclose(out_yuv_fp);
-
fclose(in_bmp_fp);
-
printf("over\n");
-
return EXIT_SUCCESS;
-
}
3. 测试
分别对两个rgb_yuv_convert进行测试,执行100次发现
-->直接转的耗时
real 0m2.183s
user 0m2.179s
sys 0m0.000s
-->查表法的耗时
real 0m0.679s
user 0m0.674s
sys 0m0.004s
发现查表法是有一定的提高。
阅读(1329) | 评论(0) | 转发(0) |