数据压缩:yuv2rgb并通过rgb2yuv进行验证

来源:互联网 发布:sony 刷机软件 编辑:程序博客网 时间:2024/05/19 03:24

由电视原理可知RGB与YUV的关系:

Y=0.2990*R+0.5870*G+0.1140*B

R-Y=0.7010*R-0.5870*G-0.1140*B

B-Y=-0.2990*R-0.5870*G+0.8860*B

归一化后:

U=-0.1684*R-0.3316*G+0.5*B

V=0.5*R-0.4187*G-0.0813*b

则 R=Y+(R-Y)= Y + 1.4075 *(V-128)
    G = Y+(G-Y)=Y-0.3455*(U-128)-0.7169(V-128)
    B =Y+(B-Y)= Y + 1.779 *(U-128)

存储格式:

RGB24格式的图像采用打包存储方法:即一个像素点的数据连续存放,且存储顺序并非字面顺序,而是:BGRBGRBGR..........

YUV420则是分别存储,现存储所有的Y分量,然后是U分量、V分量。

数据量:

RGB24用24位来表示一个像素,分量用8位表示,取值范围是0~255.一帧RGB所占用的空间为:width*height*3

YUV420中Y是灰度图像,U、V分量的高度和宽度分别是Y分量的一半,则一帧YUV所占内存的大小为:weight*height*3/2.

实现流程:先实现YUV向RGB的转换,再对YUV进行上采样(RGB到YUV则是下采样)

yuv2rgb的部分代码(在之前给定的rgb2yuv的基础上修改得来):

 

#include "stdlib.h"#include "yuv2rgb.h"static float YUVRGB14075[256];static float YUVRGB03455[256], YUVRGB07169[256];static float YUVRGB1779[256];int YUV2RGB (int x_dim, int y_dim,  void *y_in, void *u_in, void *v_in,void *bmp, int flip){static int init_done = 0;long i, j, size;unsigned char *r, *g, *b;float r_temp,g_temp,b_temp;unsigned char *y, *u, *v;unsigned char  *u_buffer, *v_buffer;unsigned char *sub_y_buf,*sub_u_buf, *sub_v_buf;  if (init_done == 0)    {        InitLookupTable();//运行查找表子程序        init_done = 1;    }// check to see if x_dim and y_dim are divisible by 2,查看是否可以被2整除if ((x_dim % 2) || (y_dim % 2)) return 1;//如果不能被2 整除,则return1size = x_dim * y_dim;// allocate memorysub_y_buf = (unsigned char *)y_in;sub_u_buf = (unsigned char *)u_in;sub_v_buf = (unsigned char *)v_in;u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));//分配指定字节的内存空间v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));if (!(u_buffer && v_buffer)){if (u_buffer) free(u_buffer);//如果其中任何一个没有分配内存空间,就释放if (v_buffer) free(v_buffer);return 2;}b = (unsigned char *)bmp;//b指向bmp文件的首地址的指针y = sub_y_buf;u = sub_u_buf;v = sub_v_buf;// 倒序if (!flip) {/*for (j = 0; j < y_dim; j ++){y = y_buffer + (y_dim - j - 1) * x_dim;u = u_buffer + (y_dim - j - 1) * x_dim;v = v_buffer + (y_dim - j - 1) * x_dim;for (i = 0; i < x_dim; i ++) {g = b + 1;r = b + 2;*y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);*u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);*v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);b += 3;y ++;u ++;v ++;}}*///倒序} else {for (j = 0; j < y_dim; j++)//行{for (i = 0; i < x_dim; i++)//列{g = b + 1;//顺序为BGRBGRBGR.....r = b + 2;r_temp= ((*y)+ YUVRGB14075[*v] );//计算rgbg_temp= ((*y)-YUVRGB03455[*u] - YUVRGB07169[*v] );b_temp= ((*y) + YUVRGB1779[*u] );//判断计算结果是否在0-255范围内(8)if(r_temp>255)*r=(unsigned char)(255);else if(r_temp<0)*r=(unsigned char)(0);else *r=(unsigned char)(r_temp);if(g_temp>255)*g=(unsigned char)(255);else if(g_temp<0)*g=(unsigned char)(0);else *g=(unsigned char)(g_temp);if(b_temp>255)*b=(unsigned char)(255);else if(b_temp<0)*b=(unsigned char)(0);else *b=(unsigned char)(b_temp);b += 3;y ++;u =sub_u_buf+(j/2)*x_dim/2+i/2;v =sub_v_buf+(j/2)*x_dim/2+i/2;}}}return 0;}// 上采样/*for (j = 0; j < y_dim/2; j ++){psu = sub_u_buf + j * x_dim / 2;//行指针psv = sub_v_buf + j * x_dim / 2;pu1 = u_buffer + 2 * j * x_dim;//u_buffer内存空间,2* j * x_dim代表隔两行取一行pu2 = u_buffer + (2 * j + 1) * x_dim;//指向(取样的)下一行pv1 = v_buffer + 2 * j * x_dim;pv2 = v_buffer + (2 * j + 1) * x_dim;for (i = 0; i < x_dim/2; i ++){*psu = (*pu1 + *(pu1+1) + *pu2 + *(pu2+1)) / 4;//每四个取一个*psv = (*pv1 + *(pv1+1) + *pv2 + *(pv2+1)) / 4;psu ++;psv ++;pu1 += 2;pu2 += 2;pv1 += 2;pv2 += 2;}}free(u_buffer);//释放内存空间free(v_buffer);return 0;}*/void InitLookupTable()//查找表{int i;for (i = 0; i < 256; i++) YUVRGB14075[i] = (float)1.4075 * (i-128);for (i = 0; i < 256; i++) YUVRGB03455[i] = (float)0.3455 * (i-128);for (i = 0; i < 256; i++) YUVRGB07169[i] = (float)0.7169 * (i-128);for (i = 0; i < 256; i++) YUVRGB1779[i] = (float)1.779 * (i-128);}   


部分main.cpp代码:

/* get an output buffer for a frame */rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);//内存空间/* get the input buffers for a frame */yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL){printf("no enought memory\n");exit(1);}//读文件fread(yBuf, 1, frameWidth * frameHeight , yuvFile);fread(uBuf, 1, frameWidth * frameHeight/4 , yuvFile);fread(vBuf, 1, frameWidth * frameHeight/4 , yuvFile);if(YUV2RGB(frameWidth, frameHeight,  yBuf, uBuf, vBuf,rgbBuf, flip)){printf("error");return 0;}if(fwrite(rgbBuf, 1, frameWidth * frameHeight*3, rgbFile)){printf("\r...%d", ++videoFramesWritten);printf("\n%u %ux%u video frames written\n",videoFramesWritten, frameWidth, frameHeight);}/* cleanup */if (rgbFile)        fclose(rgbFile);    if (yuvFile)        fclose(yuvFile);if (rgbBuf)        free(rgbBuf);    if (yBuf)        free(yBuf);    if (uBuf)        free(uBuf);    if (vBuf)        free(vBuf);return(0);

实验中出现的问题:

1.


将yuv文件转成rgb图像后,理论上应与原图像的大小(192kB)一致,但实际比原图像要大(248kB),后将参数修改后便可正常显示。


错误参数如下:


2 修改参数后又发现新的错误,即yuv转rgb,再转yuv后图像与原图像色差较大


经参考rgb2yuv文件的代码后,发现应该是U和V指针有误,反复修改后得如下结果:

u =sub_u_buf+(j/2)*x_dim/2+i/2;
v =sub_v_buf+(j/2)*x_dim/2+i/2;

3为进行rgb像素取值是否在0~255之间的判断,但并未觉察出较大的差异,在浏览了网上的部分代码后,增加了该部分判断。

(未判断)                                                                                               (判断)

其他文件的测试:


第一幅为176x144,后两幅为352x288,所选文件均为多帧,处理后仅有1帧

0 0
原创粉丝点击