Autor Beitrag
Timbo
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 166



BeitragVerfasst: Di 24.02.04 15:47 
moin zusammen,

habe einen einfachen bildschirmschoner mit einem übergang geprogt, wo jpg angezeigt werden.
das anzeigen der bilder ist schnell genung, und die bilder sollen ja eh eine zeit lang stehen bleiben.
aber der übergang (ein bild faded in das andere) ist mir nicht schnell genug. kann ich an meinem code noch was verbessern?
der übergang funktioniert wie folgt:
bild1 rgb(100 150 100) bild2(200 100 200) dann wird mit einer vorher festgelegten anzahl von schritten die werte verändert: 120 140 120 / 140 130 140 / usw.

countFade sind die gesamtschritte und akt ist der aktuelle schritt (von 1 bis countFade)
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
function Fade(var bildFade:tbitmap; bild1, bild2:tbitmap; akt:Integer):integer;
var x,y:integer;
    p1, p2, p3:pbytearray;
    tx, ty, tz:integer;
    xmal3: Integer;
begin
 for y:=0 to screenHeight-1 do begin
  p1:=bild1.ScanLine[y];
  p2:=bild2.ScanLine[y];
  p3:=bildFade.ScanLine[y];
  for x:=0 to screenWidth-1 do begin
   xmal3:= x*3;
   if p1[xmal3]< p2[xmal3] then p3[xmal3]:=round(((abs(p1[xmal3]-p2[xmal3]))/countFade)* akt)+ p1[xmal3]
     else p3[xmal3]:=p1[xmal3] - round(((abs(p1[xmal3]-p2[xmal3]))/countFade)* akt);
   if p1[xmal3+1]< p2[xmal3+1then p3[xmal3+1]:=round(((abs(p1[xmal3+1]-p2[xmal3+1]))/countFade)* akt)+ p1[xmal3+1]
     else p3[xmal3+1]:=p1[xmal3+1] - round(((abs(p1[xmal3+1]-p2[xmal3+1]))/countFade)* akt);
   if p1[xmal3+2]< p2[xmal3+2then p3[xmal3+2]:=round(((abs(p1[xmal3+2]-p2[xmal3+2]))/countFade)* akt)+ p1[xmal3+2]
     else p3[xmal3+2]:=p1[xmal3+2] - round(((abs(p1[xmal3+2]-p2[xmal3+2]))/countFade)* akt);
  end;
 end;
end;


aufruf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  while (i <= countFade) AND not (stoppAni) do begin
    Fade(bildFade, bild1, bild2, i);
    Image1.Picture.Bitmap:= bildFade;
    Application.ProcessMessages;
    inc(i);
  end;


habe schon versucht abwechselnt jede zweite zeile zu berechnen, aber das konnte man dann auch sehen.

vielen dank.
tim.


Zuletzt bearbeitet von Timbo am Di 24.02.04 19:43, insgesamt 1-mal bearbeitet
thebe
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 128

WinXP Home
D6 Enterprise
BeitragVerfasst: Di 24.02.04 17:02 
Du verwendest für jede Zeile die Du bearbeitest nochmal die ScanLine Funktion, was Du gar nicht brauchst. Auch ScanLine braucht seine Zeit, besonders wenn Du die Funktion 639 - 1023 mal unnütz aufrufst.

ScanLine kopiert die Pointerdaten des Bildes von Zeile y bis Zeile 1 in dein Array (sprich wenn Du die letzte Zeile per Scanline rüberkopierst, dann kopiert Delphi die Pointer Daten des gesamten Bildes in dein Array), daß kannst Du ausnutzen sodaß Du nur EINMAL ScanLine pro Bild verwenden musst.

Wenn Du z.b. mit Bild1.ScanLine[ScreenHeight-1] alle Daten in das Array einlädst, sieht das im Array wie folgt aus:

{Pointer zu Pixel 1, Zeile Screenheight; ...... ; Pointer zu Pixel ScreenWidth, Zeile Screenheight ; Pointer zu Pixel 1, Zeile Screenheight-1 ; ..... ; Pointer zu Pixel ScreenWidth, Zeile Screenheigth-1; ... }

=> Einmal per p1 := Bild1.ScanLine[ScreenHeight-1] einladen und dann per
p1^[((heigth-y)*width)+x] := *bla irgendeinFarbwert* drauf zugreifen

Heigth muss ScreenHeight-1 sein, Width muss ScreenWidth sein (ohne -1)
x und y gehen von 0 bis ScreenHeigth-1 / ScreenWidth-1

Das sollte Dir nen gehörigen Geschwindigkeitsvorteil geben.

MfG

- Thebe
Keldorn
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 2266
Erhaltene Danke: 4

Vista
D6 Prof, D 2005 Pro, D2007 Pro, DelphiXE2 Pro
BeitragVerfasst: Di 24.02.04 19:18 
@thebe:
Bist du dir da sicher? Meines wissens nach sind die scanlines auf 4 Bytes ausgerichtet. Wenn du eine pf24bit-Bitmap hast und Pech mit der Breite hast, wirst du wahrscheinlich nicht das richtige Pixel erwischen.

hier wird eine andere Lösung gezeigt:
www.efg2.com/Lab/Ima...ine.htm#Optimization
(auch mal die Kommentare lesen, da steht das mit der ausrichtung auch nochmal drin)

@Timbo:
ich würd noch
- versuchen das "/countFade* akt" in einer Variablen außerhalb der schleife zu berechnen
- mal das round durch trunc zu ersetzen
- mir ist nicht ganz klar, was du mit dem if p1[xmal3]< p2[xmal3] bezweckst.
- Bist du dir mit dem inc(y); sicher?
- Ich denke aber, daß du die größte Zeit vielleicht hier verlierst
Zitat:

Image1.Picture.Bitmap:= bildFade;

Da steckt viel mehr dahinter als ein einfaches Zeichnen. Probier hier mal ein Paintbox statt einem Image und zeichne hier deine Bitmap rein. (onpaint ereignis der paintbox nicht vergessen, sonst siehst du nix, wenn z.B. die Form minimiert wird oder ein anderes fenster drübergelegt wird).

Würd mich interessieren, was rauskommt :)

Mfg Frank

_________________
Lükes Grundlage der Programmierung: Es wird nicht funktionieren.
(Murphy)
Timbo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 166



BeitragVerfasst: Di 24.02.04 19:55 
das inc(y); war natürlich schwachsinn, hatte ich hier vergessen zu korrigieren, habe es jetzt rausgenommen. war ein überbleibsel, von optimierungsversuchen.

@thebe:
das mit dem scanline werde ich mal versuchen.

@Keldorn:
deine tipps hören sich auch gut an werde das alles mal testen.
mit p1[xmal3]< p2[xmal3] prüfe ich ob ich den berechneten wert auf pix1 addieren oder subtraieren muss. ich will ja von p1 den übergang zu p2 machen.
beispiel: p1 50 p2 100 dann muss ich immer auf p1 addieren
p1 200 p2 100 nun von p1 subtraieren.
Timbo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 166



BeitragVerfasst: Di 24.02.04 21:04 
konnte den vergleich auch rausschmeissen, nur mal ein bisschen nachdenken... :roll:

der faktor wir nun ein mal berechnet:

faktor:= akt/countFade;

und die drei werte berechnen sich so:
ausblenden Delphi-Quelltext
1:
2:
3:
p3[xmal3]:=round((p2[xmal3]-p1[xmal3])* faktor)+ p1[xmal3];
p3[xmal3+1]:=round((p2[xmal3+1]-p1[xmal3+1])* faktor)+ p1[xmal3+1];
p3[xmal3+2]:=round((p2[xmal3+2]-p1[xmal3+2])* faktor)+ p1[xmal3+2];


trunc hat das ganze sehr viel langsamer gemacht im gegensatz zu round, komisch.

nun schau ich mir nochmal die zuweisung des bildmaps an.
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Di 24.02.04 21:43 
@Timbo:

ich hab deine procedure Fade(...) die du oben gepostet hast verbessert. Nach meiner messung um etwa 20%.

Hier der code:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure Fade(bildFade, bild1, bild2: TBitmap; akt: Integer);
Type
  TRGB = Packed Record b, g, r: Byte End;
var
  x: Integer;
  p1, p2, p3: ^TRGB;
begin
  p1:=bild1.ScanLine[bild1.Height-1];
  p2:=bild2.ScanLine[bild1.Height-1];
  p3:=bildFade.ScanLine[bild1.Height-1];
  for x:=1 to bild1.Height*bild1.Width do begin
    p3.r:=p1.r + Round((p2.r-p1.r) / countFade * akt);
    p3.g:=p1.g + Round((p2.g-p1.g) / countFade * akt);
    p3.b:=p1.b + Round((p2.b-p1.b) / countFade * akt);
    Inc(p1);
    Inc(p2);
    Inc(p3);
  end;
end;


Mfg
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Di 24.02.04 22:08 
und hier der andere teil, sollte auch nochmal etwa 10% bringen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  Image1.Picture.Bitmap:= bildFade; 
  while (i <= countFade) AND not (stoppAni) do begin 
    Fade(Image1.Picture.Bitmap, bild1, bild2, i); 
    Image1.Repaint;
    Application.ProcessMessages; 
    inc(i); 
  end;
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Di 24.02.04 23:41 
Ach mir ist nochwas eingefallen *g Und zwar bringt das nochmals etwa 15% geschwindigkeitszuwachs 8) (insgesamt schätze ich mal so um die 40% !)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure Fade(bildFade, bild1, bild2: TBitmap; akt: Integer);
Type
  TRGB = Packed Record b, g, r: Byte End;
var
  i: Integer;
  p1, p2, p3: ^TRGB;
  LUT: Array[-255..255Of SmallInt;
begin
  For i:=Low(LUT) To High(LUT) Do
    LUT[i]:=Round((i) / countFade * akt);   
  p1:=bild1.ScanLine[bild1.Height-1];
  p2:=bild2.ScanLine[bild1.Height-1];
  p3:=bildFade.ScanLine[bild1.Height-1];
  for i:=1 to bild1.Height*bild1.Width do begin
    p3.r:=p1.r + LUT[p2.r-p1.r];
    p3.g:=p1.g + LUT[p2.g-p1.g];
    p3.b:=p1.b + LUT[p2.b-p1.b];
    Inc(p1);
    Inc(p2);
    Inc(p3);
  end;
end;


aufruf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  Image1.Picture.Bitmap:= bildFade;  
  while (i <= countFade) AND not (stoppAni) do begin  
    Fade(Image1.Picture.Bitmap, bild1, bild2, i);  
    Image1.Repaint; 
    Application.ProcessMessages;  
    inc(i);  
  end;


mfg
thebe
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 128

WinXP Home
D6 Enterprise
BeitragVerfasst: Mi 25.02.04 09:19 
Zitat:
@thebe:
Bist du dir da sicher? Meines wissens nach sind die scanlines auf 4 Bytes ausgerichtet. Wenn du eine pf24bit-Bitmap hast und Pech mit der Breite hast, wirst du wahrscheinlich nicht das richtige Pixel erwischen.


Lies bitte den Code den ich gepostet hab. Er kopiert die Scanlines in ein PByteArray und greift dann nur auf auf die jeweiligen Werte in meinem Code zu ( p1^[((heigth-y)*width)+x] ). Und der Code funzt BTW, meine Programme verwenden den genauso.
Timbo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 166



BeitragVerfasst: Mi 25.02.04 12:13 
@Phantom1:
ich habe zum vergleichen der berechnung des bildes Image1.Picture.Bitmap:= bildFade; auskommentiert. also das berechnete bild wird nicht mehr angezeigt, aber die rechnung läuft ganz normal.

der erste quellcode von dir lief bei mir nicht schneller, aber der zweite läuft mehr als doppelt so schnell wow...

nun muss ich nur noch die darstellung des bildes optimieren.

habe das ausprobiert:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Image1.Picture.Bitmap:= bildFade;   
  while (i <= countFade) AND not (stoppAni) do begin   
    Fade(Image1.Picture.Bitmap, bild1, bild2, i);   
    Image1.Repaint;  
    Application.ProcessMessages;   
    inc(i);   
  end;


aber bei mir läft das schneller:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Image1.Picture.Bitmap:= bildFade;   
  while (i <= countFade) AND not (stoppAni) do begin   
    Fade(bildFade, bild1, bild2, i);   
    Image1.Picture.Bitmap:= bildFade;  
    Application.ProcessMessages;   
    inc(i);   
  end;


weil hier brauch ich komischerweise nicht repaint aufrufen.

im moment sieht es so aus:
1/5 der zeit berechnung des bildes
4/5 der zeit darstellung des bildes (wobei diese zeit wohl auch von der grafikkarte mit abhängt)

werde nun mal den vorschlag von Keldorn verfolgen.

vielen dank schon mal an alle.
Timbo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 166



BeitragVerfasst: Mi 25.02.04 12:35 
nun mit paintbox:

ist noch ein bißchen schneller
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
while (i <= countFade) AND not (stoppAni) do begin
    Fade(bildFade, bild1, bild2, i);
    BitBlt(PaintBox1.Canvas.Handle, 00, screenWidth, screenHeight,
             bildFade.Canvas.Handle, 00, SrcCopy);
    Application.ProcessMessages; 
    inc(i);
end;
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Mi 25.02.04 14:31 
Hab noch ein Tipp: arbeite mit 32bit Farbtiefe, ist meist schneller! (bei mir waren es sogar 15%)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
  bild1.pixelformat:=pf32bit;
  bild2.pixelformat:=pf32bit;
  bildFade.pixelformat:=pf32bit;
  while (i <= countFade) AND not (stoppAni) do begin 
    Fade(bildFade, bild1, bild2, i); 
    BitBlt(PaintBox1.Canvas.Handle, 00, screenWidth, screenHeight, 
             bildFade.Canvas.Handle, 00, SrcCopy); 
    Application.ProcessMessages;  
    inc(i); 
end;


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure Fade(bildFade, bild1, bild2: TBitmap; akt: Integer); 
Type 
  TRGB = Packed Record b, g, r, a: Byte End
var 
  i: Integer; 
  p1, p2, p3: ^TRGB; 
  LUT: Array[-255..255Of Integer; // LookUp-Table
begin 
  For i:=Low(LUT) To High(LUT) Do 
    LUT[i]:=Round((i) / countFade * akt);    
  p1:=bild1.ScanLine[bild1.Height-1]; 
  p2:=bild2.ScanLine[bild1.Height-1]; 
  p3:=bildFade.ScanLine[bild1.Height-1]; 
  for i:=1 to bild1.Height*bild1.Width do begin 
    p3.r:=p1.r + LUT[p2.r-p1.r]; 
    p3.g:=p1.g + LUT[p2.g-p1.g]; 
    p3.b:=p1.b + LUT[p2.b-p1.b]; 
    Inc(p1); 
    Inc(p2); 
    Inc(p3); 
  end
end;
obbschtkuche
Gast
Erhaltene Danke: 1



BeitragVerfasst: Mi 25.02.04 18:49 
Und jetzt könntest du den LUT noch global definieren und nur einmal berechnen lassen.
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Mi 25.02.04 20:27 
@obbschtkuche: so einfach ist das leider nicht, da wir hier zwei unbekannte variabeln haben, dh wir müssten ein mehrdimensionales array verwenden und erheblich mehr werte im vorraus berechnen, um genau zu sein wären es genauso viele wie jetzt im moment, es würde also in diesem fall nix bringen.

Ich habe aber noch eine Idee und ich hätte nicht gedacht das das soviel ausmacht (es ist jetzt etwa 4mal so schnell !)

hier der code, erstmal brauchen wir eine globale variable:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
Type
  TRGB = Packed Record b, g, r, a: Byte End;
  TRGBs = Packed Record b, g, r: SmallInt End;

var
  diff: Array of TRGBs;


ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
procedure Getdiff(bild1, bild2: TBitmap);
var
  i: Integer;
  p1, p2: ^TRGB;
begin
  p1:=bild1.ScanLine[bild1.Height-1];
  p2:=bild2.ScanLine[bild1.Height-1];
  for i:=0 to bild1.Height*bild1.Width-1 do begin
    diff[i].r:=p2.r-p1.r;
    diff[i].g:=p2.g-p1.g;
    diff[i].b:=p2.b-p1.b;
    Inc(p1);
    Inc(p2);
  end;
end;

procedure Fade(bildFade, bild1: TBitmap; akt: Integer);
var
  i: Integer;
  p1, p3: ^TRGB;
  LUT: Array[-255..255Of Integer; // LookUp-Table
begin
  For i:=Low(LUT) To High(LUT) Do
    LUT[i]:=Round(i / countFade * akt);
  p1:=bild1.ScanLine[bild1.Height-1];
  p3:=bildFade.ScanLine[bild1.Height-1];
  for i:=0 to bild1.Height*bild1.Width-1 do begin
    p3.r:=p1.r+LUT[diff[i].r];
    p3.g:=p1.g+LUT[diff[i].g];
    p3.b:=p1.b+LUT[diff[i].b];
    Inc(p1);
    Inc(p3);
  end;
end;


Der aufruf sieht wie folgt aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
  bild1.pixelformat:=pf32bit; 
  bild2.pixelformat:=pf32bit; 
  bildFade.pixelformat:=pf32bit; 
  SetLength(diff,bild1.Height*bild1.Width);
  Getdiff(bild1, bild2);
  while (i <= countFade) AND not (stoppAni) do begin  
    Fade(bildFade, bild1, i);  
    BitBlt(PaintBox1.Canvas.Handle, 00, screenWidth, screenHeight,  
             bildFade.Canvas.Handle, 00, SrcCopy);  
    Application.ProcessMessages;   
    inc(i);  
end;
obbschtkuche
Gast
Erhaltene Danke: 1



BeitragVerfasst: Fr 27.02.04 16:48 
Phantom1 hat folgendes geschrieben:
@obbschtkuche: so einfach ist das leider nicht, da wir hier zwei unbekannte variabeln haben, dh wir müssten ein mehrdimensionales array verwenden und erheblich mehr werte im vorraus berechnen, um genau zu sein wären es genauso viele wie jetzt im moment, es würde also in diesem fall nix bringen.


Wenn mehrere Bilder gefadet werden (Wie es hier den Anschein hat), bringt es sehr wohl was. Es braucht zwar mehr Speicher, aber ein Paar KB (Je nach dem in wie vielen Schritte das Bild gefadet wird) wird man wohl noch berappen können :P
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Fr 27.02.04 17:56 
obbschtkuche hat folgendes geschrieben:
Phantom1 hat folgendes geschrieben:
@obbschtkuche: so einfach ist das leider nicht, da wir hier zwei unbekannte variabeln haben, dh wir müssten ein mehrdimensionales array verwenden und erheblich mehr werte im vorraus berechnen, um genau zu sein wären es genauso viele wie jetzt im moment, es würde also in diesem fall nix bringen.


Wenn mehrere Bilder gefadet werden (Wie es hier den Anschein hat), bringt es sehr wohl was. Es braucht zwar mehr Speicher, aber ein Paar KB (Je nach dem in wie vielen Schritte das Bild gefadet wird) wird man wohl noch berappen können :P


Dann zeig doch mal wie du es gemacht hättest, weil ich habe keine möglichkeit gefunden das sinnvoll umzusetzen.
obbschtkuche
Gast
Erhaltene Danke: 1



BeitragVerfasst: Fr 27.02.04 19:02 
Für 20 Schritte würde ich das in der Art machen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
type
 TLUT: Array[0..19, -255..255of Integer;

...

var
 LUT: TLUT;
 i,j: integer;

...

initialization
 for i := 0 to 19 do
  for j := -255 to 255 do
   LUT[i,j] := round(j / 20 * (i+1))
end.


Oder hab ich jetzt was falsch verstanden? :roll:
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Fr 27.02.04 20:45 
@obbschtkuche:

Und wo ist da jetzt der vorteil? du berechnest 20mal die LUT, das ist bei meinem Code genauso (bei 20 durchgängen). :wink:

Verstehst du jetzt was ich meine? außerdem kostet es nichtmal 1 millisekunde, selbst wenn ich 100mal die LUT berechne
obbschtkuche
Gast
Erhaltene Danke: 1



BeitragVerfasst: Fr 27.02.04 21:21 
Verstehst du mich nicht? :roll: Bei einem Bildschirmschoner wird nicht nur ein Bild gefadet und dann ist schluss, sondern in der Regel folgen mehrere Übergänge aufeinander. Dadurch muss nur einmal am Anfang der LUT berechnet werden und danach können die Werte daraus genommen werden.
Phantom1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 390



BeitragVerfasst: Fr 27.02.04 21:34 
Achso ja, daran hatte ich jetzt nicht gedacht. Aber eigentlich kann man das eh vernachlässigen, denn wie gesagt sebst 100 mal die LUT berechnen kostet nichtmal 1 millisekunde. Wir sollten uns daher auf die wirklichen Geschwindigkeitsbremsen konzentrieren.