最近在项目的过程中需要用到 YUV 的 Y通道数据,但是原始数据图像为RGB格式,所以自己写了一个RGB2YUV的程序,并且进行优化,对此总结如下。
RGB2YUV 原理
RGB及YUV是两种不同的颜色空间,具体可以换算关系如下:
根据该换算关系,我们直接可以得到Y通道数据。
程序1
void rgb2yuv2(unsigned char *R,unsigned char *G,unsigned char *B,unsigned char *Y,int len)
{
//这里应有对指针的有效性判断,此处略
for(int i=len;i!=0;i--){
*Y++ = *R*0.299 + *G*0.587 + *B*0.114;
R++;B++;G++;
}
}
优化思路
不过这里涉及大量的浮点数运算,使得程序运行十分缓慢,为了加速,我们可以采用查表法及定点运算进行优化。
1、查表法
因为R/G/B通道的系数都已经固定了,只要预先求出[0..255]这些数值乘以系数对应的数值,在读取到对应R通道数据时,可以通过查表形式获取。
2、定点运算
由于系数均为小数点3位数,我们可以 先乘以299再除以1000 达到 乘以0.299 的目的。
同时,为了简化乘法,采用移位操作,向右移位10bit,则表示除以1024,对应的,我们只要在生成 查表数值 的时候,乘以1024即可。
综合1、2,我们可以先将:
对于R通道,[0..255] 乘以 0.299,再乘以1024,得到 256个对应的数值。G/B通道也采取类似操作。
在计算Y通道时,取出R/G/B通道对应的数值,求和并右移10位,得到最终数据。
程序2
int array[256];
// 生成各个通道对应的数值,并保存至表格
void genArray(float factor){ // factor是对应通道的系数。
int i=0;
for(i=0;i<256;i++){
array[i]=(int)(factor*i*1024+0.5);
}
}
// RGB转YUV
void rgb2yuv(unsigned char *R,unsigned char *G,unsigned char *B,unsigned char *Y,int len)
{
//这里应有对指针的有效性判断,此处略
for(int i=len;i!=0;i--){
*Y++ = (RT[*R++]+GT[*G++]+BT[*B++])>>10;
}
}
经验证,实际得到的图像与程序1得到的图像类似,误差为±1