一道字符串算法优化,求助

luvi88 2009-11-26 04:36:18
请教一下大家(32位字长的pc机环境):
#define WIDTH 320
#define HEIGHT 240
#define BYTES 3

对一个char s[WIDTH*HEIGHT*BYTES]的线性数据空间,
BYTES为最小处理单位,320*240为VIDEO的宽度和高度,也是LCD像素点个数。因为从摄像头获取到的是24位的RGB色彩,所以每3字节表示一个像素的色彩,深度为24位,现要把它转换为16位,2 字节的rgb格式(5:6:5)。

/* 包含在.h文件中的片段 */
typedef struct st_video_color_pixel_24{
unsigned char blue;
unsigned char green;
unsigned char red;
} COLOR24_T;
#define color_24to16(color) ((short)(((color.blue>>3))|((color.green>>2)<<5)|((color.red>>3)<<11)))

/* 包含在.c文件中的片段 */
unsigned short pbuf[WIDTH*HEIGHT];
COLOR24_T color;
...

for(row=0; row<HEIGHT; row++){
for(col=0; col<WIDTH; col++){
strncpy((char *)&color, (const char *)(pvideo_buf+row*WIDTH*BYTES+col*BYTES), sizeof(COLOR24_T));
pbuf[row*WIDTH+col] = (unsigned short)color_24to16(color);
}
}

按这种常规处理方案,需要处理WIDTH*HEIGHT次,对每一个BYTES字节的24位RGB色彩,转换为2字节16位的565格式的数据,这段代码效率很低,还有3字节的RGB色彩跨4字节边界问题。大家有没有好的算法,优化一下这个数据处理过程。谢了!


...全文
246 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
luvi88 2009-12-03
  • 打赏
  • 举报
回复
谢谢大家这么热心,确实改进了不少。也学到了不少东西。
把这种问题使用离散数学的思想,比如矩阵压缩算法,也有提到的。
但没有深入解释。
不过我想这种规范的矩阵,确实可以用数学的思想去解决,但要有算法高手
出来贡献下思想了。
cao_jialian 2009-11-30
  • 打赏
  • 举报
回复
建议:
定义一个三字节的位段结构及它的指针变量
用这个指针变量的遍历(++运算)指向每一个源象素(将二维的--对应二重循环--改造成一维的线性操作且地址运算更快些)
不要strncpy操作(它只是做了个数据移动)
而直接对源象素做移位操作并存储在16位目标处
好象一重循环中只用一条语句就能搞掂。
赵4老师 2009-11-30
  • 打赏
  • 举报
回复
编译生成Release版本并确认打开速度优化
z569362161 2009-11-30
  • 打赏
  • 举报
回复
还是用指针吧
red-fly 2009-11-30
  • 打赏
  • 举报
回复
看了以上的回复,还是学习了不少,程序才想到,程序的效率,总是有办法提高的,只不过看有没有想到,呵呵

/* 包含在.c文件中的片段 */
unsigned short pbuf[WIDTH*HEIGHT];
COLOR24_T *pcolor;
...
unsigned char *pszVideo = pvideo_buf;
unsigned char *pszVLast = pvideo_buf; // 记录每一行的位置,以后不用每行乘了
unsigned long lBytesLine = (WIDTH * 3 + 3)/4 * 4; // 一次性算好一行的长度,后面就不用每次再去乘了

for(row=0; row <HEIGHT; row++){
for(col=0; col <WIDTH; col++){
pcolor = (COLOR24_T*)pszVLast; // 不要用拷贝,直接附值,加快操作速度
pbuf += 1; // 用加法来更新偏移量
pbuf = (unsigned short)color_24to16(*color); // 直接附值,不要每次都用乘法
pszVideo += 3; // 不要用乘,而是换成加法
}
pszVLast += lBytesLine; // 采用加法,比乘法更快
}
Steven_0610 2009-11-30
  • 打赏
  • 举报
回复
学习
wumy_ld 2009-11-29
  • 打赏
  • 举报
回复
循环展开提高效率的前提是展开后的各表达式没有关联,显然上述循环不满足这个条件。
bfdeh 2009-11-29
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 kissoflife 的回复:]
循环展开提高效率的前提是展开后的各表达式没有关联,显然上述循环不满足这个条件。
[/Quote]说得是。那这样行不?
    for(i = 0; i < LENGTH/LOOPDEEP;)
{
pbuf[index_16+1] = color_24to16(pvideo_buf + i);
pbuf[index_16+2] = color_24to16(pvideo_buf + i + BYTES);
pbuf[index_16+3] = color_24to16(pvideo_buf + i + 2*BYTES);
pbuf[index_16+4] = color_24to16(pvideo_buf + i + 3*BYTES);
index_16 += 4;
i += 4*BYTES;
}
coolness 2009-11-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ssssaaaa_aa 的回复:]
建议用"递归算法"处理;

[/Quote]
递归算法好处是代码看起来很简洁,但是递归的效率相对比较低。可以尝试采用矩阵压缩的算法。
bfdeh 2009-11-28
  • 打赏
  • 举报
回复
关于跨4字节的问题我实在想不到好的办法,不知道参考strlen的实现会不会有用,我感觉好像用不上。
bfdeh 2009-11-28
  • 打赏
  • 举报
回复
kissoflife的意见很不错,我把他的整理一下,再补充点我自己的看法

#define LOOPDEEP 4
#define LENGTH (WIDTH * HEIGHT * BYTES)
#typedef unsigned char UINT8;
#typedef unsigned int UINT32;
//这个宏定义不知道括号配对没有,LZ自己再检查一下。之所以转换为UINT8是因为LZ之前的定义
//是char s[],有符号,有符号数右移行为是不确定的(符号位的问题)
#define color_24to16(pch) ((short)\
(*((UINT8*)pch) >> 3)|\
((*((UINT8*)pch + 1)>>2) <<5)|\
((*((UINT8*)pch + 2)>>3) <<11))
UINT32 index_16 = 0;
UINT32 i;

//如果LZ对效率要求比较苛刻的话,可以考虑像下面这样展开循环,不过这样可读性稍微差一点,
//kissoflife原来的代码可读性更好,LZ视情况自己选择吧。
//注意一点,如果LENGTH不是LOOPDEEP的整数倍的话,余下的LENGTH%OOPDEEP部分需要单独处理,
//因为这里正好LENGTH%OOPDEEP==0,所以我就没有单独处理这部分了
for(i = 0; i < LENGTH/LOOPDEEP;)
{
pbuf[index_16++] = color_24to16(pvideo_buf + i);//将24位颜色转换为16位
i += BYTES;
pbuf[index_16++] = color_24to16(pvideo_buf + i);//将24位颜色转换为16位
i += BYTES;
pbuf[index_16++] = color_24to16(pvideo_buf + i);//将24位颜色转换为16位
i += BYTES;
pbuf[index_16++] = color_24to16(pvideo_buf + i);//将24位颜色转换为16位
i += BYTES;
}

总结一下:
1、有符号数右移行为时不确定的
2、尽可能使用无符号数,在大多数机器上无符号数比有符号数更容易处理
3、适当展开循环可以提高效率
wumy_ld 2009-11-28
  • 打赏
  • 举报
回复
抱歉,宏定义少了一个括号:
#define color_24to16(pch) ((short)(((*(pch) >> 3))|((*(pch + 1)>>2) <<5)|((*(pch + 2)>>3) <<11)))
wumy_ld 2009-11-28
  • 打赏
  • 举报
回复
循环有点小问题,纠正为:
#define color_24to16(pch) ((short)(((*pch >> 3))|((*(pch + 1)>>2) <<5)|((*(pch + 2)>>3) <<11)))

int length = WIDTH * HEIGHT * BYTES; // 数组总长度
int index_16 = 0;
int i;

for(i = 0; i < length; i += BYTES, index_16++)
{
pbuf[index_16] = color_24to16(pvideo_buf + i);//将24位颜色转换为16位
}
wumy_ld 2009-11-28
  • 打赏
  • 举报
回复
效率低下的原因有以下几点:
1、使用超过一维的数组;
2、使用嵌套循环;
3、频繁执行拷贝操作;
4、频繁执行乘法操作。
解决上述问题的解法如下:
#define color_24to16(pch) ((short)(((*pch >> 3))|((*(pch + 1)>>2) <<5)|((*(pch + 2)>>3) <<11)))

int length = WIDTH * HEIGHT * BYTES; // 数组总长度
int index_24 = 0;
int index_16 = 0;
int i;

for(i = 0; i < length; i++)
{
pbuf[index_16++] = color_24to16(pvideo_buf + index_24);//将24位颜色转换为16位

index_24 += BYTES; // 调整源计数器
}
james_hw 2009-11-27
  • 打赏
  • 举报
回复
哎,最简单的提高效率方法都不用,
(const char *)(pvideo_buf+row*WIDTH*BYTES+col*BYTES)
这句想想能不能用指针实现,不用每次都计算一次偏移量

lyj7015 2009-11-27
  • 打赏
  • 举报
回复
头晕了!需要休息!
ma100 2009-11-27
  • 打赏
  • 举报
回复
pvideo_buf+row*WIDTH*BYTES+col*BYTES
改为 pvideo_buf
然后把pvideo_buf += 3;
下面的pbuf[row*WIDTH+col] 也同理
另外用 memcpy 替换strncpy
luvi88 2009-11-26
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ssssaaaa_aa 的回复:]
建议用"递归算法"处理;

[/Quote]

递归的效率应该更低
ssssaaaa_aa 2009-11-26
  • 打赏
  • 举报
回复
建议用"递归算法"处理;
jiayucunyan 2009-11-26
  • 打赏
  • 举报
回复
初步的想法,好像可以对pbuf采用矩阵压缩的方法。
这样,相同像素的元素不必重复执行color_24to16函数
是否能够提高效率,还需要实际试一下。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧