第一次在大富翁论坛上提问,就成为热点,我好高兴!最重要的是认识了不少高手。 (111分)

  • 主题发起人 主题发起人 wwolf
  • 开始时间 开始时间
W

wwolf

Unregistered / Unconfirmed
GUEST, unregistred user!
怎样才能在第一时间知道屏幕中有变化?
我原本的设计思路是这样的:
1.用Bitblt抓屏到一个DIB中,将此DIB和上一幅XOR。
2.将XOR后的异或图分块。
3.用Scanline对每块的像素进行比较。
4.如果有某一像素的色值不是黑色则表示此小块有变动。
5.如果是都黑色,则表示此小块没有变动。
6.继续从第3步开始,直到所有小块比较完毕。
7.Sleep(15)延时15毫秒后,继续第1步开始。

抓屏的代码是:
QueryPerformanceFrequency(count);//得到震荡频率
QueryPerformanceCounter(First);//取得已震荡次数
Fullscreen.PixelFormat :=pf16bit;//当前屏幕是800*600 16位色
bitblt(Fullscreen.Canvas.Handle,0,0,800,600,SCRDC,0,0,SRCCopy);//要35ms
Fullscreen.PixelFormat :=pf8bit;//如果有此句,则要多花 68ms
QueryPerformanceCounter(last);//取得已震荡次数
//将(Last-First)/Count即得经过的时间

我觉得这样抓屏所花的时间太长了,DFW上有不少人说用DirectDraw方式更快。
但我没试过,理论上说应该是会快很多,但到底有多快?谁有具体实现的代码能给我参考
一下吗?还有,如果要将图转为256色,有更好更快的方法吗?
还有,哪位高手能说说我这样做,思路对吗,或者说说更好的思路。
拜托各位啦!!各位路过的朋友,即来之,则帮个忙提一下。谢谢!!
 
认识可以,不过你这个问题太复杂了,搞不了
 
Delphi里确实有办法将16位色转为8位色,
但是转换之后,你认为你还能“准确”地判断屏幕是否变化了吗?
而且,你如何考虑鼠标呢?

呵呵。
 
坏蟑螂 说的对,转为8位后的结果可能是不稳定的,可以在
比较后再转(或者都不转化)。
 
是不是搞監控的?
 
只是学学而已
 
用钩子不就解决了吗?
 
把图形写到MemoryStream中,逐字节地比较。
 
为什么非要判断变化呢,判不判断都已经考屏啦
 
判断一下是为了当图块不变时,就不传送了。
 
分块的想法应该来说是可行的,至于比较的算法,我觉得完全可以采用逐字节比较的办法:
var
Jpg1, Jpg2: TMemoryStream;
S1, S2: array of Byte;
I: Integer;
B: Cardinal;
begin
B := GetTickCount;
Jpg1 := TMemoryStream.Create;
Jpg2 := TMemoryStream.Create;
Image1.Picture.Graphic.SaveToStream(Jpg1);
Jpg2.LoadFromStream(Jpg1);
SetLength(S1, Jpg1.Size);
Move(Jpg1.Memory^, S1[0], Jpg1.Size);
SetLength(S2, Jpg2.Size);
Move(Jpg2.Memory^, S2[0], Jpg2.Size);
for I := 0 to Jpg1.Size - 1 do
begin
if S1 <> S2 then
begin
ShowMessage('asdf');
break;
end;
end;
Jpg1.Free;
Jpg2.Free;
ShowMessage(IntToStr(GetTickCount - B));
我在Image1里调用了一个894,018字节的BMP,结果显示用时60毫秒
说明这个操作是不耗时的!

to 坏蟑螂:
用BitBlt是抓不到鼠标的,所以抓图软件据我所知鼠标都是后来用GetCursorPos后画上去的。:)

to Toylin:
抓屏幕速度是飞快的,主要问题是如何解决网络传输及CPU占用率的问题。 :)
 
xianjun, 我的观点跟你一样啊。谢谢你帮我实现。
 
TO:xianjun
你的方法太慢了。
用Scanline得到指针进行比较的话只要6毫秒左右(800*600:48万次)
 
没用过ScanLine,能更快当然更好了。 :)
 
哪道没有高手来回答吗??我一直以为DFW上的高手比CSDN上的高手要多要好。可是,为什么.....
 
>>MemoryStream的方法太慢了
我认为:你若有心,对此算法进行优化,绝不会比SCANLINE慢。
 
用scanline得到的数据是不是可以一次比较一行???
 
to:卷起千堆雪tyn
你说一行一行的扫描是指一次比较一行吗???我不太明白。
还有,可能我的题目太长了,没人爱看,其实我想知道的是:
1.关于用DirectDraw方法抓屏(就是从显存中得到数据)的具体代码或方法。
2.按我这样做(等于是查询法),是否有更好的方法。比如"中断法"。:)
 
procedure TForm1.BitBtn1Click(Sender: TObject);
var
Jpg1, Jpg2: TMemoryStream;
S1, S2: PByte;
I: Integer;
Count,First,Last:Int64;
begin
//350K的JPG文件,如果在这里开始记时,需时8毫秒。
Jpg1 := TMemoryStream.Create;
Jpg2 := TMemoryStream.Create;
TJPEGImage(Image1.Picture.Graphic).SaveToStream(Jpg1);
TJPEGImage(Image2.Picture.Graphic).SaveToStream(Jpg2);
//350K的JPG文件,如果在这里开始记时,需时3毫秒。
QueryPerformanceFrequency(count);//得到震荡频率
QueryPerformanceCounter(First);//取得已震荡次数
S1:=Jpg1.Memory;
S2:=Jpg2.Memory;
for I := 0 to Jpg1.Size - 1 do
begin
if Byte(S1^) <> Byte(S2^) then
begin
ShowMessage('asdf');
break;
end;
Inc(s1);
Inc(s2);
end;
Jpg1.Free;
Jpg2.Free;
QueryPerformanceCounter(last);//取得已震荡次数
ShowMessage(FloatToStr((Last-First)/Count));
end;

end.
 
一个想法,据我所知,windows 的redraw事件
就是刷新变化的了窗体,所以我认为ms一定有个api可以作这间事
不过这个api可能没有公开
 
后退
顶部