我有一个图像的平滑算法(柔化、锐化等)的例子,谁能帮优化一下?(200分)

  • 主题发起人 主题发起人 3cs
  • 开始时间 开始时间
3

3cs

Unregistered / Unconfirmed
GUEST, unregistred user!
例子如下:我用它作800*600的BMP图片的处理,速度太慢了 >80毫秒!
现在的要求是<15毫秒!谁能帮我,测试的机器(CPU1。2G,内存256) 只要能帮我优化到现在4-5倍的处理速度,200分马上奉上!
procedure bmpSmooth(mybitmap: tbitmap; smoothlevel: byte; x1,y1,x2,y2: integer);
var
p,p1,p2: pbytearray;
i,j: integer;
thew,theh: integer;
s1,s2,s3: integer;
rvalue: integer;
gvalue: integer;
bvalue: integer;
tmpbitmap: tbitmap;
maxnum,minnum: integer;
begin
tmpbitmap:=tbitmap.create;
tmpbitmap.assign(mybitmap);
with mybitmap do
begin
thew:=width;
theh:=height;
if (x1=x2) or (y1=y2) then
begin
x1:=2;
y1:=2;
x2:=thew-2;
y2:=theh-2;
end
else
begin
minnum:=min(y1,y2);
maxnum:=max(y1,y2);
y1:=minnum;
y2:=maxnum;
minnum:=min(x1,x2);
maxnum:=max(x1,x2);
x1:=minnum;
x2:=maxnum;
end;
if x1<2 then x1:=2;
if y1<2 then y1:=2;
if x2>thew-2 then x2:=thew-2;
if y2>theh-2 then y2:=theh-2;
for i:=y1 to y2 do
begin
p:=ScanLine;
p1:=tmpbitmap.scanline[i-1];
p2:=tmpbitmap.scanline[i+1];
for j:=x1 to x2 do
begin
s1:=j*3;
s2:=j*3+1;
s3:=j*3+2;
case smoothlevel of
1: begin // 轻微
rvalue:=(p[s3]*3+p[s3-3]+p[s3+3]+p1[s3]+p1[s3-3]+p1[s3+3]+
p2[s3]+p2[s3-3]+p2[s3+3]) div 11;
gvalue:=(p[s2]*3+p[s2-3]+p[s2+3]+p1[s2]+p1[s2-3]+p1[s2+3]+
p2[s2]+p2[s2-3]+p2[s2+3]) div 11;
bvalue:=(p[s1]*3+p[s1-3]+p[s1+3]+p1[s1]+p1[s1-3]+p1[s1+3]+
p2[s1]+p2[s1-3]+p2[s1+3]) div 11;
end;
2: begin // 普通
rvalue:=(p[s3]*2+p[s3-3]+p[s3+3]+p1[s3]+p1[s3-3]+p1[s3+3]+
p2[s3]+p2[s3-3]+p2[s3+3]) div 10;
gvalue:=(p[s2]*2+p[s2-3]+p[s2+3]+p1[s2]+p1[s2-3]+p1[s2+3]+
p2[s2]+p2[s2-3]+p2[s2+3]) div 10;
bvalue:=(p[s1]*2+p[s1-3]+p[s1+3]+p1[s1]+p1[s1-3]+p1[s1+3]+
p2[s1]+p2[s1-3]+p2[s1+3]) div 10;
end;
3: begin // 加强
rvalue:=(p[s3]+p[s3-3]+p[s3+3]+p1[s3]+p1[s3-3]+p1[s3+3]+
p2[s3]+p2[s3-3]+p2[s3+3]) div 9;
gvalue:=(p[s2]+p[s2-3]+p[s2+3]+p1[s2]+p1[s2-3]+p1[s2+3]+
p2[s2]+p2[s2-3]+p2[s2+3]) div 9;
bvalue:=(p[s1]+p[s1-3]+p[s1+3]+p1[s1]+p1[s1-3]+p1[s1+3]+
p2[s1]+p2[s1-3]+p2[s1+3]) div 9;
end;
else
begin
rvalue:=p[s3];
gvalue:=p[s2];
bvalue:=p[s1];
end;
end;
p[s3]:=rvalue;
p[s2]:=gvalue;
p[s1]:=bvalue;
end;
end;
end;
tmpbitmap.free;
end;
 
你的代码可以优化的地方不多了
1、获取 ScanLine 每次都调用 GetScanLine,不爽,建议一次获取两个 ScanLine 之间的差异以后偏移即可(对 tmpbitmap 和 mybitmap)。
2、因为存在多处 s2、s3 的 +1 之类的运算,建议代码中 s2 repalce 为 s1 + 1;s3 replace 为 s1 + 2。
3、bitmap 本质就是一块连续的内存区域(windows 的 bitmap 结构),既然需要模化的区域不一定是整块的,assign 整个缓存数据开辟的区域比较浪费,建议自己按需拷贝指定区域内容。(windows 中内存拷贝比较耗时)
 
to:LSUPER
你的建议,我都试了,但效果不明显.,和我要求的速度相差还很远!
有没有别的方法呀?
 
to:LSUPER
能不能给一个线性插值算法例子给我!
 
一楼回答是正解。
关于优化:
1,减少循环里的操作,可以提出去的尽量提出去,
2,少用昂贵的乘除法,能用加减代替的就用加减,
3,针对你这种情况,考虑差值,中心思想就是这一次一计算尽量用前几次的计算代替来减少计算量,自己递推下就知道了,呵呵。。
 
我优化了,但还是达不到要求,这不是人力所能为呀[:D]
GDI+看来也不过如此![:(]
用别的方法我解决了这个问题,但对GDI是真的失望了[:(]

分还在,来的朋友全有分,最好帮顶下![:D]
 
不太懂图像算法,
case smoothlevel of 移到循环外不行吗?
大概看了一下,两层循环应该是行了列的循环,改成一次处理一行行否。
 
把位图的PixelFormat属性设置为pf24bit试试。
 
说句实话,这个尺寸获得这个时间,你的CPU已经很强了。因为柔化等操作是与图片大小有
密切关系的,基本上最后的像素计算量是原图片的3到4倍(代码中的 scanline[i-1]scanline[i+1])。

深入优化的话,可以考虑建表,因为 rgbval 做的是四点平均,可以预先建表,直接由四点
像素值命中表中数据,三种平滑样例就要建三张表。不需要考虑SSE或者MMX优化,除非有现
成的代码(如 intel fast code),否则很难保证每台机器上都能获得好的效果。
 
to 小雨哥
你的贴<<忘掉代码 之 TGraphic>>让我看到了GDI与DirectDraw的一个完美结合,通过组件TDirectCanvas的建立,也能看出你对TSurface.Canvas的深入理解.
问题;我现在想知道是建立一个副Surface装载DIB图片流映射到主Surface速度快,还是建立内存流装载DIB图片流映射到主Surface的速度快呢?
我自己的感觉是后者要快的多,那为什么在DirectDraw中要引入Surface这个概念呢?能不能把你的理解说一下?谢谢!
 
对DirectDraw中的Surface有自己见解的都可以发表看法!来者都有分拿!
 
后退
顶部