首页 > 编程知识 正文

rgb转yuv公式,rgb转换hls公式

时间:2023-05-05 12:43:25 阅读:9137 作者:3963

另一方面,前言本次试验内容是将256*256、4:2:0采样的yuv图像转换为rgb格式。 老师提供了rgb2yuv的源代码,分析后发现源代码已经极其优雅高效,命名方式合理,内存分配适中,采用查找表的方法,在空间上改变时间责任度。 因此,这次以直接源代码为基础,进行了一些变更,得到了逆变换。

二、由公式推导出1.rG b2yuv在电视系统中红、绿、蓝称为三基色,分别用(R e )、G e )、gb )表示。 电视监视器上的各色光用这三种颜色的荧光体调制。

亮度方程:Y=0.2990R+0.5870G+0.1140B

从这里得到的东西:

Y0.2990R+0.5870G+0.1140B

U = B Y 0.2990 R 0.5870 G + 0.8860 B

V = R Y 0.7010 R 0.5870 G 0.1140 B

2.yuv2rgb从上述公式进行逆变换,可以得到以下内容。

转换后的最终形式如下

R = (298 Y+411 V - 57376) / 256

G = (298 Y - 101 U - 211 V + 35168) / 256

B = (298 Y + 519 U - 71200) / 256

三、代码实现1 .读取图像YUVfile=fopen(YUVfilename,' rb ' ); if(YUVfile==null ) printf(cannotfindYUVfile(n ); 退出(1; } else { printf (theinputyuvfileis % s (n ),yuvFileName ); }/* opentherawfile */RGB file=fopen (RGB filename,' wb ' ); if(RGBfile==null ) printf(cannotfindRGBfile(n ); 退出(1; } else { printf (' theoutputrgbfileis % sn ',RGB文件名称); }/* getanoutputbufferforaframe */RGB buf=(u _ int8_ t * ) malloc ) framewidth*frameheight*3);/* gettheinputbuffersforaframe */ybuf=(u _ int8_ t * ) malloc (帧宽度*帧高度); Ubuf=(u_int8_t* ) malloc ) )框架宽度*框架高度)/4 ); vbuf=(u_int8_t* ) malloc ) )框架宽度*框架高度)/4 ); fread(ybuf,1,帧宽*帧高,YUV文件); fread(Ubuf,1,帧宽*帧高/4,YUV文件); fread(vbuf,1,frameWidth * frameHeight/4,yuvFile ) )这次使用的是c语言,但rgb和yuv的读取思路与上次基本一致。 通过限制每次读取的大小,将文件保存到每个预先分配了空间的buffer中。

2.yuv转换为rgb注意事项:使用YUVviewerPlus (如下图所示)打开rgb文件时,图像将被识别为bmp图像,打开后上下翻转。 但是,这次实验直接使用上次自己写的python文件打开rgb图像,所以不需要反转图像。

if (! flip(else ) for ) intI=0; i x_dim; I ) for(intj=0; j y_dim; j () {g=b 1; r=b 2; int b_tmp、g_tmp、r_tmp; b_tmp=() YUV RGB 298 [ * y ] YUV RGB 519 [ * u ]-71200 )/256 ); g_tmp=(YUVRGB298(*y ) yuvrgbf101 ) ) u ) yuvrgbf211(*v ) 35168 ) )/256 ); r _ tmp=(YUV RGB 298 [ * y ] YUV RGB 411 [ * v ]-57376 )/256 ); if(b_tmp0) b_tmp=0; if(b_tmp255 ) b_tmp=255; * b=(未指定char ) b_tmp; if(g_tmp0) g_tmp=0; if(g_tmp255 ) g_tmp=255; * g=(未指定char ) g_tmp; if(r_tmp0) r_tmp=0; if(r_tmp255 ) r_tmp=255; *r=(unsign

ed char)r_tmp;b += 3;y++;if (i % 2 == 0 && j == 0) //奇数行开头{u -= y_dim / 2;v -= y_dim / 2;k -= y_dim / 2;}if (j % 2 != 0)//偶数列{u++;v++;k++;}}}}

代码关键解读:

a) 使用查找表 void InitLookupTable(){int i;for (i = 0; i < 256; i++) YUVRGB298[i] = (float)298 * i;for (i = 0; i < 256; i++) YUVRGB411[i] = (float)411 * i;for (i = 0; i < 256; i++) YUVRGBF101[i] = (float)-101 * i;for (i = 0; i < 256; i++) YUVRGBF211[i] = (float)-211 * i;for (i = 0; i < 256; i++) YUVRGB519[i] = (float)519 * i;}

在进行运算之前,提前将可能的取值(0-255)全部计算,并将结果保存在数组中。如此在实际运算中直接查找数组提取结果值就可以了,大大提升了代码效率,是一种空间换取时间的做法。
在日后编写代码中也要常记这个tip。

b) 数值溢出

若是直接将运算结果赋值给rbg指针,将会是下图结果。

(在运算上图时有纰漏,误写了算法的公式导致天空色彩有误)

可以看到图像出现了很多饱和度较高,色彩一致的斑点。这是由于在计算后数值可能低于0或高于255,若是直接赋值给unsigned char类型变量会导致数值溢出。故先赋值给int类型变量,做一个溢出判定。

int b_tmp, g_tmp, r_tmp;b_tmp = ((YUVRGB298[*y] + YUVRGB519[*u] - 71200) / 256);g_tmp = ((YUVRGB298[*y] + YUVRGBF101[*u] + YUVRGBF211[*v] + 35168) / 256);r_tmp = ((YUVRGB298[*y] + YUVRGB411[*v] - 57376) / 256);if (b_tmp < 0) b_tmp = 0;if (b_tmp > 255) b_tmp = 255;*b = (unsigned char)b_tmp;if (g_tmp < 0) g_tmp = 0;if (g_tmp > 255) g_tmp = 255;*g = (unsigned char)g_tmp;if (r_tmp < 0) r_tmp = 0;if (r_tmp > 255) r_tmp = 255;*r = (unsigned char)r_tmp; c) 指针移动

此实验yuv图像为4:2:0格式,采样点如下图:

在rgb2yuv代码中,需要对运算后的u,v的buffer进行下采样,将256256的空间转化为128128的尺寸,代码如下:

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;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;}}

而在yuv2rgb时,需要将128128的u,v buffer上采样为256256。但为了代码的简洁高效,没有这样做。而是直接利用指针的移动达到此目的。

if (i % 2 == 0 && j == 0) //奇数行开头{u -= y_dim / 2;v -= y_dim / 2;k -= y_dim / 2;}if (j % 2 != 0)//偶数列{u++;v++;k++;}

在横向,每当偶数列时u,v向下移动一个;
在纵向,每当到达奇数行开头时,u,v往回移动128个,重新遍历一遍本行数值。

最终结果

原图转换后四、误差分析

虽然输出图像肉眼看起来无异,但在计算过程中,有以下几个环节会产生误差:

1.采样。在rgb图像yuv图像过程中,由于4:2:0的采样格式,u,v像素值变为原来的1/4,损失了大量信息。当再由yuv图像转为rgb时,信息量已经不是完整的了。 2.YUV与RGB色彩空间并不重合,在色彩空间变换时存在溢出。 3.在浮点运算时产生误差。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。