高手来~关于画图的效率问题(500FPS)
http://www.delphi2007.net/DelphiMultimedia/html/delphi_20061018141036227.html
Timer_GetWave.Enabled:=false;
timestart:=now();
self.GroupBox_Draw.DoubleBuffered:=true;
for i:=0 to 500 do
begin
getdata();
drawdata();
// PB.Canvas.Draw(0,0,_DrawMap);
end;
timeend:=now();
self.LabelFPS.Caption:=inttostr(milliSecondsBetween(timestart,timeend));
-------------------------------------------------------------------------
用了双缓冲,以上代码的执行结果是1100毫秒.
如果我把PB.Canvas.Draw(0,0,_DrawMap);加上去,执行结果要9900毫秒,效率差了十倍.
请问有什么方法可以加上这句后效率不变化那么大~?
给个思路也好~~
对于占用大量计算时间的画图操作不能使用直接在PictureBox上画图的办法的,这样效率很低的,好久不做这方面的程序了,具体方法我说不清楚,你自己查,给你个思路。
第一步,计算需要的画图数据
第二步,在内存页(一般是bitmap对象)画出图形(这两步花费比较长的时间)
第三步,直接用显示组件(例如PictureBox)把画好的内存页直接调入,显示出来。
根据需要使用内存页的数量。
如果图形的计算与绘制本身就是要花很多时间,这个画图程序是没有办法降低画图时间的,但是使用上边的方法,可以消除绘画的过程(至少用户看不到),不会产生图形的闪烁。而且内存页的绘制时间本身也要比直接绘制显示还是要快。
好像要用到bitblt函数,如果组件不提供类似方法,就要用Windows API了。
我就是用TBitmap在内存画的啊~~然后发觉贴出来的时候,
PB.Canvas.Draw(0,0,_DrawMap);
特别耗时间~~~
不执行 PB.Canvas.Draw(0,0,_DrawMap);的话比执行快很多~
_DrawMap就是个Tbitmap
显示本来就耗时间啊,需要从内存到显存复制,就是直接用BitBlt也快不了多少。
如果不需要动画效果,全部画完之后再更新显示就可以了,否则单独用一个线程(定时器也可以)来更新,每秒更新个15-30次就够了,完全不需要象你现在这样每秒50几帧。
问题是公司需要.....
因为从波形采样频率很高....要是帧数低了就有可能错过某些采集来的重要信息.....
你不是都保存了吗?不显示也不会丢失吧。
不怕丢失,但得实时显示....
30FPS就是实时显示了。
你非要50FPS以上,没啥意义。
for i:=0 to 500 do
begin
getdata();
drawdata();
// PB.Canvas.Draw(0,0,_DrawMap);
end;
要求太高了,什么软件,如果真的是要求高效的制图,请使用DirectX,不要用原始方法。
DirectX~~~用不用装多什么开发工具~~~
没用过~~~~
能给个小例子看看吗~~?
要装DirectX开发包,例子我现在拿不出来,入门肯定也不容易,这个一般只有做3D游戏才需要,首先你弄清楚你的需求,不要乱来。
不知道你的具体需求,我只是讨论一下:
1)如果你采样的数据是历史增量数据,只需要在上面更新新的数据,而不需要整幅图重画吧。也就是你的DRAWDATA应该直接向PB的CANVAS上画,我想,如果新数据量应该不会很大吧。
2)如果新数据真的很大,就只能是使用DIRECTX了。
3)如果如你的程序给出的思路,那么也可以在显示的时候将一组合并成一帧来画吧。
opengl 可以看 nehe 入门例子做简单 还是可以的
另外teechart控件包有 封装 opengl chart
netfly(支点)说得对,可以考虑只重画变化了的部分,不用全部重画。
只是简单绘制2D图,用什么速度都差不多。并不是你用DirectX(准确地讲是用DirectX中的DirectDraw)或者OpenGL就能快多少。
如果你是显示一个连续变化的波形(因为你有Timer_GetWave这种命名),那么可以使用ScrollDC把前一幅图卷动一下(左到右或者右到左之类的),然后画上更新的部分就可以了。
谢谢各位!
现在问题解决了!说出来笑死人,郁闷了我好多天.....原来是给我用的那个笔记本电脑没显卡驱动
......
我写的东西是用在工业超声探伤上的波形显示.
procedure TForm1.Button1Click(Sender: TObject);
var
c1,t1,t2:int64;
t3:double;
begin
self.Button1.Enabled:=false;
QueryPerformanceFrequency(c1);
DrawCount:=0;
self.Button1.Enabled:=false;
QueryPerformanceCounter(t1);
while true do
begin
GetPoints;
Draw;
DrawCount:=DrawCount+1;
Form1.Edit1.Text:=IntToStr(DrawCount);
Application.ProcessMessages;
if DrawCount=500 then
begin
break;
end;
end;
QueryPerformanceCounter(t2);
t3:=(t2-t1)/c1*1000;
ShowMessage('实际经过时间'+FloatToStr(t3)+'毫秒');
self.Button1.Enabled:=true;
end;
//取得模拟数据
procedure GetPoints;
var
x:integer;
begin
//取得数据
for x:=0 to 511 do
begin
DrawPoints[x].X:=x;
DrawPoints[x].Y:=random(300);
end;
end;
//画图
procedure Draw;
begin
//画背景入缓存
Form1.Image1.Canvas.Brush.Color:=clBlack;
Form1.Image1.Canvas.FillRect(Rect(0,0,512,300));
//画波形入缓存
Form1.Image1.Canvas.Pen.Style:=psSolid;
Form1.Image1.Canvas.Pen.Color:=clGreen;
Form1.Image1.Canvas.Polyline(DrawPoints);
//画网格入缓存
Form1.Image1.Canvas.Pen.Style:=psDot;
Form1.Image1.Canvas.Pen.Color:=clRed;
Form1.Image1.Canvas.MoveTo(0,30);
Form1.Image1.Canvas.LineTo(511,30);
Form1.Image1.Canvas.MoveTo(0,60);
Form1.Image1.Canvas.LineTo(511,60);
Form1.Image1.Canvas.MoveTo(0,90);
Form1.Image1.Canvas.LineTo(511,90);
Form1.Image1.Canvas.MoveTo(0,120);
Form1.Image1.Canvas.LineTo(511,120);
Form1.Image1.Canvas.MoveTo(0,150);
Form1.Image1.Canvas.LineTo(511,150);
Form1.Image1.Canvas.MoveTo(0,180);
Form1.Image1.Canvas.LineTo(511,180);
Form1.Image1.Canvas.MoveTo(0,210);
Form1.Image1.Canvas.LineTo(511,210);
Form1.Image1.Canvas.MoveTo(0,240);
Form1.Image1.Canvas.LineTo(511,240);
Form1.Image1.Canvas.MoveTo(0,270);
Form1.Image1.Canvas.LineTo(511,270);
Form1.Image1.Canvas.MoveTo(51,0);
Form1.Image1.Canvas.LineTo(51,300);
Form1.Image1.Canvas.MoveTo(102,0);
Form1.Image1.Canvas.LineTo(102,300);
Form1.Image1.Canvas.MoveTo(153,0);
Form1.Image1.Canvas.LineTo(153,300);
Form1.Image1.Canvas.MoveTo(204,0);
Form1.Image1.Canvas.LineTo(204,300);
Form1.Image1.Canvas.MoveTo(255,0);
Form1.Image1.Canvas.LineTo(255,300);
Form1.Image1.Canvas.MoveTo(306,0);
Form1.Image1.Canvas.LineTo(306,300);
Form1.Image1.Canvas.MoveTo(357,0);
Form1.Image1.Canvas.LineTo(357,300);
Form1.Image1.Canvas.MoveTo(408,0);
Form1.Image1.Canvas.LineTo(408,300);
Form1.Image1.Canvas.MoveTo(459,0);
Form1.Image1.Canvas.LineTo(459,300);
Form1.Image1.Canvas.MoveTo(510,0);
Form1.Image1.Canvas.LineTo(510,300);
//画边框
Form1.Image1.Canvas.Pen.Style:=psSolid;
Form1.Image1.Canvas.MoveTo(0,0);
Form1.Image1.Canvas.LineTo(511,0);
Form1.Image1.Canvas.MoveTo(0,299);
Form1.Image1.Canvas.LineTo(511,299);
Form1.Image1.Canvas.MoveTo(0,0);
Form1.Image1.Canvas.LineTo(0,300);
Form1.Image1.Canvas.MoveTo(511,0);
Form1.Image1.Canvas.LineTo(511,300);
bitblt(Form1.Canvas.Handle,Form1.Image1.Left,Form1.Image1.Top,512,300,Form1.Image1.canvas.handle,0,0,srccopy);
end;
在公司我用的机器上运行是8000多毫秒,在同事的机器上是1000多...
另外发现一个问题,同样的这个程序,我在家里用delphi7编译的时候,不用用到btiblt,image1直接画直接显示画面不会闪烁,拿到公司这部机器编译后运行就很闪,得加上btiblt才不会闪,公司的环境是delphi6.....
不知是不是跟delphi的版本有关~~~~~
现在试不了~回家再重新试试~!
感觉用btiblt的速度比在Form里面开双缓冲速度快一半.
开心~~~~~知道是电脑的问题....不是我能力问题......
一开始还很郁闷和我一起新进公司的那个同事很轻松就能达到500FPS....早上才发觉是因为没显卡驱动的原因~~~松了口气~!