织梦CMS - 轻松建站从此开始!

罗索

如何让你的软件飞起来

jackyhwei 发布于 2010-03-31 22:43 点击:次 
将RGB彩色图像转换成黑白图像:Y = 0.299 * R + 0.587 * G + 0.114 * B。下面以由RGB转YUV的公式,Y = 0.299 * R + 0.587 * G + 0.114 * B,开始一步步讲述如何优化coding;
TAG:

/* <<如何让你的软件飞起来 >>
* 将RGB彩色图像转换成黑白图像
* Y = 0.299 * R + 0.587 * G + 0.114 * B;
* 图像尺寸640x480x24
* RGB图像已按RGBRGB的方式存在内存中
*/
下面以由RGB转YUV的公式,Y = 0.299 * R + 0.587 * G + 0.114 * B,开始一步步讲述如何
优化coding;
/**************** header define ************/
#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] //计算后的结果

由于编译器处理1维数组的效率要高过2维数组,
这里将原本为2D的RGB数据换成一维数组。

/************* original code *************/

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

这是最简单的实现,采用了大量的浮点运算,
速度极其慢。

1.将浮点预算改成定点运算
/********** float to int ************/
Y = 0.299 * R + 0.587 * G + 0.114 * B
Y=D+E+F
D=0.299 * R=299 * R /1000
E=0.587 * G=587 * R /1000
F=0.114 * B=114 * R /1000

Void calc_lum()
{int I;
for(i=0;i<IMGSIZE;i++)
{int r,g,b;
r=1224*in[i].r/1000;
g=2404*in[i].g/1000;
b=467*in[i].b/1000;
out[i]=r+g+b;
}
}

将浮点预算改成定点运算,速度翻一番。

2.将乘法、除法改为移位
/********** division to shift ************/

Y = 0.299 * R + 0.587 * G + 0.114 * B
Y=D+E+F
D=0.299 * R=299 * R /1000 = 1224 * R / 4096
E=0.587 * G=587 * G /1000 = 2404 * G / 4096
F=0.114 * B=114 * B /1000 = 476 * B / 4096
Y= (1224 * R + 2404 * G + 476 * B) / 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%

3.查表法
/*********** table search *************/

Int D[256],E[256],F[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;
}
}

RGB取值范围:0-255,可以将数值预先计算好,
存在3个一维数组里面,采用查表的方法,
读取RGB数值。

4.并行运算

/*********** two 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];
g=E[in[i].g];
b=F[in[i].b]; //查表
y=r+g+b;
out[i]=y;

r1=D[in[i+1].r];
g1=E[in[i+1].g];
b1=F[in[i+1].b]; //查表
y1=r1+g1+b1;
out[i+1]=y1;
}
}

CPU内部有两个ALU,则可以同时计算两个像素值。

/******** usigned short | inline **************/

unsigned short D[256],E[256],F[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;
}
}

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]; g=E[in[i].g]; b=F[in[i].b]; //查表
y=r+g+b;
out[i]=y;
r1=D[in[i+1].r]; g1=E[in[i+1].g]; b1=F[in[i+1].b]; //查表
y1=r1+g1+b1;
out[i+1]=y1;
}
}
将函数声明为inline,这样编译器就会将其嵌入到母函数中,
可以减少CPU调用子函数所产生的开销。

5.cache

/**********************/

把查表的数据放置在CPU的高速数据CACHE里面

6. ASM

/**********************/

•把函数calc_lum()用汇编语言来

(秩名)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201003/8944.html]
本文出处:网络博客 作者:秩名
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容