欢迎访问 生活随笔!

凯发ag旗舰厅登录网址下载

当前位置: 凯发ag旗舰厅登录网址下载 > > 编程问答 >内容正文

编程问答

rgb2yuv -凯发ag旗舰厅登录网址下载

发布时间:2025/1/21 编程问答 5 豆豆
凯发ag旗舰厅登录网址下载 收集整理的这篇文章主要介绍了 rgb2yuv 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

1.rgb2yuv422p

 

代码的运算速度取决于以下几个方面

1、 算法本身的复杂度,比如mpeg比jpeg复杂,jpeg比bmp图片的编码复杂。

2、 cpu自身的速度和设计架构

3、 cpu的总线带宽

4、 您自己代码的写法

将rgb格式的彩色图像先转换成yuv图像。

图像转换的公式如下:

y = 0.299 * r 0.587 * g 0.114 * b;

图像尺寸640*480*24bit,rgb图像已经按照rgbrgb顺序排列的格式,放在内存里面了。

以下是输入和输出的定义:

#define xsize 640

#define ysize 480

#define imgsize xsize * ysize

typedef struct rgb

{

unsigned char r;

unsigned char g;

unsigned char b;

}rgb;

struct rgb in[imgsize]; //需要计算的原始数据

unsigned char out[imgsize]; //计算后的结果

 

第一个优化

优化原则:图像是一个2d数组,我用一个一维数组来存储。编译器处理一维数组的效率要高过二维数组。

 

先写一个代码:

y = 0.299 * r 0.587 * g 0.114 * b;

void calc_lum()

{

int i;

for(i = 0; i < imgsize; i )

{

double r,g,b,y;

unsigned char yy;

r = in[i].r;

g = in[i].g;

b = in[i].b;

y = 0.299 * r 0.587 * g 0.114 * b;

yy = y;

out[i] = yy;

}

}

这大概是能想得出来的最简单的写法了,实在看不出有什么毛病,好了,编译一下跑一跑吧。

第一次试跑

这个代码分别用vc6.0和gcc编译,生成2个版本,分别在pc上和我的embedded system上面跑。

速度多少?

在pc上,由于存在硬件浮点处理器,cpu频率也够高,计算速度为20秒。

我的embedded system,没有以上2个优势,浮点操作被编译器分解成了整数运算,运算速度为120秒左右。

 

去掉浮点运算

上面这个代码还没有跑,我已经知道会很慢了,因为这其中有大量的浮点运算。只要能不用浮点运算,一定能快很多。

 

y = 0.299 * r 0.587 * g 0.114 * b;

这个公式怎么能用定点的整数运算替代呢?

0.299 * r可以如何化简?

y = 0.299 * r 0.587 * g 0.114 * b;

y = d e f;

d = 0.299 * r;

e = 0.587 * g;

f = 0.114 * b;

我们就先简化算式d吧!

rgb的取值范围都是0~255,都是整数,只是这个系数比较麻烦,不过这个系数可以表示为:0.299 = 299 / 1000;

所以 d = ( r * 299) / 1000;

y = (r * 299 g * 587 b * 114) / 1000;

 

这一下,能快多少呢?

embedded system上的速度为45秒;

pc上的速度为2秒;

0.299 * r可以如何化简

y = 0.299 * r 0.587 * g 0.114 * b;

y = (r * 299 g * 587 b * 114) / 1000;

这个式子好像还有点复杂,可以再砍掉一个除法运算。

前面的算式d可以这样写:

0.299=299/1000=1224/4096

所以 d = (r * 1224) / 4096

y=(r*1224)/4096 (g*2404)/4096 (b*467)/4096

再简化为:

y=(r*1224 g*2404 b*467)/4096

这里的/4096除法,因为它是2的n次方,所以可以用移位操作替代,往右移位12bit就是把某个数除以4096了。

 

void calc_lum()

{

int i;

for(i = 0; i < imgsize; i )

{

int r,g,b,y;

r = 1224 * in[i].r;

g = 2404 * in[i].g;

b = 467 * in[i].b;

y = r g b;

y = y >> 12; //这里去掉了除法运算

out[i] = y;

}

}

这个代码编译后,又快了20%。

虽然快了不少,还是太慢了一些,20秒处理一幅图像,地球人都不能接受。

 

仔细端详一下这个式子!

y = 0.299 * r 0.587 * g 0.114 * b;

y=d e f;

d=0.299*r;

e=0.587*g;

f=0.114*b;

 

rgb的取值有文章可做,rgb的取值永远都大于等于0,小于等于255,我们能不能将d,e,f都预先计算好呢?然后用查表算法计算呢?

我们使用3个数组分别存放def的256种可能的取值,然后。。。

 

查表数组初始化

int d[256],f[256],e[256];

void table_init()

{

int i;

for(i=0;i<256;i )

{

d[i]=i*1224;

d[i]=d[i]>>12;

e[i]=i*2404;

e[i]=e[i]>>12;

f[i]=i*467;

f[i]=f[i]>>12;

}

}

void calc_lum()

{

int i;

for(i = 0; i < imgsize; i )

{

int r,g,b,y;

r = d[in[i].r];//查表

g = e[in[i].g];

b = f[in[i].b];

y = r g b;

out[i] = y;

}

}

 

这一次的成绩把我吓出一身冷汗,执行时间居然从30秒一下提高到了2秒!在pc上测试这段代码,眼皮还没眨一下,代码就执行完了。一下提高15倍,爽不爽?

继续优化
很多embedded system的32bit cpu,都至少有2个alu,能不能让2个alu都跑起来?

 

void calc_lum()

{

int i;

for(i = 0; i < imgsize; i = 2) //一次并行处理2个数据

{

int r,g,b,y,r1,g1,b1,y1;

r = d[in[i].r];//查表 //这里给第一个alu执行

g = e[in[i].g];

b = f[in[i].b];

y = r g b;

out[i] = y;

r1 = d[in[i 1].r];//查表 //这里给第二个alu执行

g1 = e[in[i 1].g];

b1 = f[in[i 1].b];

y = r1 g1 b1;

out[i 1] = y;

}

}

2个alu处理的数据不能有数据依赖,也就是说:某个alu的输入条件不能是别的alu的输出,这样才可以并行。

这次成绩是1秒。

 

查看这个代码

int d[256],f[256],e[256]; //查表数组

void table_init()

{

int i;

for(i=0;i<256;i )

{

d[i]=i*1224;

d[i]=d[i]>>12;

e[i]=i*2404;

e[i]=e[i]>>12;

f[i]=i*467;

f[i]=f[i]>>12;

}

}

到这里,似乎已经足够快了,但是我们反复实验,发现,还有办法再快!

可以将int d[256],f[256],e[256]; //查表数组

更改为

unsigned short d[256],f[256],e[256]; //查表数组

 

这是因为编译器处理int类型和处理unsigned short类型的效率不一样。

再改动

inline void calc_lum()

{

int i;

for(i = 0; i < imgsize; i = 2) //一次并行处理2个数据

{

int r,g,b,y,r1,g1,b1,y1;

r = d[in[i].r];//查表 //这里给第一个alu执行

g = e[in[i].g];

b = f[in[i].b];

y = r g b;

out[i] = y;

r1 = d[in[i 1].r];//查表 //这里给第二个alu执行

g1 = e[in[i 1].g];

b1 = f[in[i 1].b];

y = r1 g1 b1;

out[i 1] = y;

}

}

将函数声明为inline,这样编译器就会将其嵌入到母函数中,可以减少cpu调用子函数所产生的开销。

这次速度:0.5秒。

 

其实,我们还可以飞出地球的!

如果加上以下措施,应该还可以更快:

1、 把查表的数据放置在cpu的高速数据cache里面;

2、 把函数calc_lum()用汇编语言来写

 

其实,cpu的潜力是很大的

1、 不要抱怨你的cpu,记住一句话:“只要功率足够,砖头都能飞!”

2、 同样的需求,写法不一样,速度可以从120秒变化为0.5秒,说明cpu的潜能是很大的!看你如何去挖掘。

3、 我想:要是microsoft的工程师都像我这样优化代码,我大概就可以用489跑windows xp了!

 

以上就是对《让你的软件飞起来》的摘录,下面,我将按照这位牛人的介绍,对rgb到ycbcr的转换算法做以总结。

 

y = 0.299r 0.587g 0.114b
u = -0.147r - 0.289g 0.436b
v = 0.615r - 0.515g - 0.100b

 

 

#deinfe size 256

#define xsize 640

#define ysize 480

#define imgsize xsize * ysize

typedef struct rgb

{

unsigned char r;

unsigned char g;

unsigned char b;

}rgb;

struct rgb in[imgsize]; //需要计算的原始数据

unsigned char out[imgsize * 3]; //计算后的结果

 

unsigned short y_r[size],y_g[size],y_b[size],u_r[size],u_g[size],u_b[size],v_r[size],v_g[size],v_b[size]; //查表数组

void table_init()

{

int i;

for(i = 0; i < size; i )

{

y_r[i] = (i * 1224) >> 12; //y对应的查表数组

y_g[i] = (i * 2404) >> 12;

y_b[i] = (i * 467) >> 12;

u_r[i] = (i * 602) >> 12; //u对应的查表数组

u_g[i] = (i * 1183) >> 12;

u_b[i] = (i * 1785) >> 12;

v_r[i] = (i * 2519) >> 12; //v对应的查表数组

v_g[i] = (i * 2109) >> 12;

v_b[i] = (i * 409) >> 12;

}

}

 

inline void calc_lum()

{

int i;

for(i = 0; i < imgsize; i = 2) //一次并行处理2个数据

{

out[i] = y_r[in[i].r] y_g[in[i].g] y_b[in[i].b]; //y

out[i imgsize] = u_b[in[i].b] - u_r[in[i].r] - u_g[in[i].g]; //u

out[i 2 * imgsize] = v_r[in[i].r] - v_g[in[i].g] - v_b[in[i].b]; //v

 

out[i 1] = y_r[in[i 1].r] y_g[in[i 1].g] y_b[in[i 1].b]; //y

out[i 1 imgsize] = u_b[in[i 1].b] - u_r[in[i 1].r] - u_g[in[i 1].g]; //u

out[i 1 2 * imgsize] = v_r[in[i 1].r] - v_g[in[i 1].g] - v_b[in[i 1].b]; //v

}

}

 

从公式中,我们关键要理解的一点是,uv / cbcr信号实际上就是蓝色差信号和红色差信号,进而言之,实际上一定程度上间接的代表了蓝色和红色的强度,理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。

        我们在数字电子多媒体领域所谈到的yuv格式,实际上准确的说,是以ycrcb色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族(包括 yuv444 / yuv422 / yuv420 / yuv420p等等)。并不是传统意义上用于pal制模拟电视的yuv模型。这些yuv模型的区别主要在于uv数据的采样方式和存储方式,这里就不详述。

        而在camera sensor中,最常用的yuv模型是 yuv422格式,因为它采用4个字节描述两个像素,能和rgb565模型比较好的兼容。有利于camera sensor和camera controller的软硬件接口设计。

 

http://blog.csdn.net/frankiewang008/article/details/6854616

 

 

http://hi.baidu.com/zymill/item/b09445aa563d02796cd4558b

http://wenku.baidu.com/link?url=j97xmvf-umfdngt8c4km3j1lue0bewdno23c10mjzs8aeimrtjtbo7zhj2zx6gawwynkabn0pdns_nd_mcncaik00niqutszypxvhqfc5ko百度文库位图信息

总结

以上是凯发ag旗舰厅登录网址下载为你收集整理的rgb2yuv的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发ag旗舰厅登录网址下载网站内容还不错,欢迎将凯发ag旗舰厅登录网址下载推荐给好友。

网站地图