Autor |
Beitrag |
Der_Neue
Hält's aus hier
Beiträge: 12
Win XP Prof
D7 Ent, D2005 Per
|
Verfasst: Mo 20.11.06 23:50
Ich habe grad mein Programm fertig geschrieben. Es sollte eigentlich eine Animation des Übergangs von Bild zu Bild werden. Der praktische Wert des Programms ist ja unwichtig  .
Das Programm funktioniert an sich, aber es dauert ca. 5-10 Sekunden um einen Schritt weiter zu kommmen. Kann man das irgendwie beschleunigen?
Der Code für einen Schritt (Die komplette Source hänge ich auch als Datei an):
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: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60:
| procedure TForm1.Button1Click(Sender: TObject); var i, i2 : integer; begin for i := 0 to image1.Width do for i2 := 0 to image1.Height do begin if (GetRValue(image1.canvas.Pixels[i,i2])) < (GetRValue(image2.canvas.Pixels[i,i2])) then begin R := GetRValue(image1.canvas.Pixels[i,i2]); G := GetGValue(image1.canvas.Pixels[i,i2]); B := GetBValue(image1.canvas.Pixels[i,i2]); R := R + Schritte; image1.Canvas.Pixels[i,i2] := rgb(r,g,b); end else begin R := GetRValue(image1.canvas.Pixels[i,i2]); G := GetGValue(image1.canvas.Pixels[i,i2]); B := GetBValue(image1.canvas.Pixels[i,i2]); R := R - Schritte; image1.Canvas.Pixels[i,i2] := rgb(r,g,b); end; if (GetGValue(image1.canvas.Pixels[i,i2])) < (GetGValue(image2.canvas.Pixels[i,i2])) then begin R := GetRValue(image1.canvas.Pixels[i,i2]); G := GetGValue(image1.canvas.Pixels[i,i2]); B := GetBValue(image1.canvas.Pixels[i,i2]); G := G + Schritte; image1.Canvas.Pixels[i,i2] := rgb(r,g,b); end else begin R := GetRValue(image1.canvas.Pixels[i,i2]); G := GetGValue(image1.canvas.Pixels[i,i2]); B := GetBValue(image1.canvas.Pixels[i,i2]); G := G - Schritte; image1.Canvas.Pixels[i,i2] := rgb(r,g,b); end; if (GetBValue(image1.canvas.Pixels[i,i2])) < (GetBValue(image2.canvas.Pixels[i,i2])) then begin R := GetRValue(image1.canvas.Pixels[i,i2]); G := GetGValue(image1.canvas.Pixels[i,i2]); B := GetBValue(image1.canvas.Pixels[i,i2]); B := B + Schritte; image1.Canvas.Pixels[i,i2] := rgb(r,g,b); end else begin R := GetRValue(image1.canvas.Pixels[i,i2]); G := GetGValue(image1.canvas.Pixels[i,i2]); B := GetBValue(image1.canvas.Pixels[i,i2]); B := B - Schritte; image1.Canvas.Pixels[i,i2] := rgb(r,g,b); end; end; end; |
EDIT: Schritte ist eine Konstante, die bei mir meistens den Wert 10 hat.
Einloggen, um Attachments anzusehen!
|
|
Coder
      
Beiträge: 1383
Erhaltene Danke: 1
WinXP
D2005 PE
|
Verfasst: Di 21.11.06 00:07
Hi
Es dauert so lange weil die jeden Pixel einzelln färbst.
Benutz mal die Methode Canvas.FloodFill.
Damit kannst du eine einfarbige Fläche umfärben.
Das sollte dann schneller gehen.
MfG
|
|
Der_Neue 
Hält's aus hier
Beiträge: 12
Win XP Prof
D7 Ent, D2005 Per
|
Verfasst: Di 21.11.06 00:11
@Coder
Ja, ich weiß. Das ist auch so beabsichtigt. Die Bilder sind nur simple Beispiele. Eigentlich wollte ich das mit Fotos usw. machen.
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: Di 21.11.06 00:22
Hallo,
schneller gehts mit (Bitmap.)Scanline. Mit Pixels kannst du das total vergessen, dass steht glaub auch in der Hilfe, dass das zu langsam ist!
Gruß Hape!
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Di 21.11.06 10:10
Hallo,
Du berechnest den Übergang etwas seltsam, naemlich degressiv und nicht linear, da Du das Ausgangsbild ständig veränderst.
Aber egal, ich hab es mal in ein neues image hineingerechnet.
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: 35: 36: 37:
| procedure TForm1.Button1Click(Sender: TObject); var y,x,step : integer; Anteil : double; R0,G0,B0 : integer; dR,dG,dB : integer; Farbpunkt : TCOlor;
begin image4.Picture.Assign(image1.picture); For step := 1 to Schritte-1 do begin Anteil := step/schritte; image4.update; form1.update; Form1.Label1.Caption:= IntToStr(sizeOf(Image4.canvas.Pixels[0,0])); for y := 0 to image1.Height do for x := 0 to image1.Width do begin FarbPunkt :=image1.canvas.Pixels[x,y]; R0 := GetRValue(FarbPunkt); G0 := GetGValue(FarbPunkt); B0 := GetBValue(FarbPunkt);
FarbPunkt :=image2.canvas.Pixels[x,y]; R := Round((GetRValue(FarbPunkt)-R0)*Anteil)+R0; G := Round((GetGValue(FarbPunkt)-G0)*Anteil)+G0; B := Round((GetBValue(FarbPunkt)-B0)*Anteil)+B0;
image4.Canvas.Pixels[x,y] := rgb(r,g,b); end; end; image4.Picture.Assign(image2.picture); end; |
Wie Du siehst berechnet man in dieser Version jedes Pixel von image1 und image2 Schritte-fach.
Ein leichterer Zugriff wäre also das Speichern der RGB Werte von Image1 und der Differenzwerte in seperaten Feld.
Statt round kann man mit integer werten und shift arbeiten.(1/3 = *(round(1/3*1024) shr 10)
Gruss Horst
Moderiert von Gausi: Code- durch Delphi-Tags ersetzt
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Di 21.11.06 11:35
@Der_Neue
So wie du das machst macht es keiner. Das ist zwar theoretisch möglich und vor allem ist es leicht, aber es dauert extrem lange. Um ein Pixel mal zu ändern ist es ok, aber nicht um ein Bild zu bearbeiten. Besser, aber etwas komplizierter ist TBitmap.ScanLine. Hier wird eine ganze Zeile einem Zeiger zugewiesen. Du kannst dann innerhalb der Zeile direkt auf die Werte zugreifen. Das ist schnell.
Hier ein Beispiel aus der Hilfedatei:
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:
| procedure TForm1.Button1Click(Sender: TObject);
var x,y : integer; BitMap : TBitMap; P : PByteArray; begin BitMap := TBitMap.create; try BitMap.LoadFromFile('C:\Programme\Borland\Delphi 3\Images\Splash\256color\factory.bmp'); for y := 0 to BitMap.height -1 do begin P := BitMap.ScanLine[y]; for x := 0 to BitMap.width -1 do P[x] := Random(65000); end;
canvas.draw(0,0,BitMap); finally BitMap.free; end; end; |
Auf y kannst du nicht direkt zugreifen. Das mußt du erst zuweisen. Auf x kannst du dann direkt zuweisen.
Das ist eine einfache Variante um mit ScanLine zu arbeiten. Wenn du willst, dann kannst du auch direkt auf einzelne RGB Farben zugreifen. Das muß man dan etwas anders machen, geht aber genauso einfach.
_________________ Popov
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Di 21.11.06 22:38
Hallo,
es ging um einen linearen Übergang.
Ich habe ein Image4 hinzugefügt und herumexperimentiert aber scanline funktioniert beim schreiben irgendwie nicht so richtig. Es wird überhaupt nichts geändert, wenn ich byteweise wegschreibe, was beim einlesen ja funktioniert ???
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: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119:
| unit farbani;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;
type TForm1 = class(TForm) Image1: TImage; Image2: TImage; Button1: TButton; Image4: TImage; Label1: TLabel; procedure Button1Click(Sender: TObject); private public end;
tLinInt = packed record R0,G0,B0,alpha0 :byte; dR,dG,dB,dA :smallint; end;
var Form1: TForm1; test : TColor; R,G,B : byte; const Schritte = 33; implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); var DummyFeld : array of tLinINt; P :pByte; pa : pBytearray; i,y,x,step : integer; Anteil : integer; Farbpunkt : TCOlor;
begin setlength(DummyFeld,image1.Width*image1.height); i := 0; for y := image1.Height-1 downto 0 do begin p := image1.Picture.Bitmap.ScanLine[y]; for x := 0 to image1.Width-1 do with DummyFeld[i] do begin B0 := p^;inc(p); G0 := p^;inc(p); R0 := p^;inc(p);
inc(i) end; end; i := 0; for y := image1.Height-1 downto 0 do begin p := image2.Picture.Bitmap.ScanLine[y]; for x := 0 to image1.Width-1 do with DummyFeld[i] do begin dB := p^-B0;inc(p); dG := p^-G0;inc(p); dR := p^-R0;inc(p); inc(i) end; end; image4.Picture.Assign(image1.picture);
For step := 1 to Schritte-1 do begin image4.update;
Anteil := round((1 shl 16)/schritte * step); i := 0; for y := image1.Height-1 downto 0 do begin p := image4.Picture.Bitmap.ScanLine[y]; for x := 0 to image1.Width-1 do begin With DummyFeld[i] do begin B := dB*Anteil shr 16+B0; G := dG*Anteil shr 16+G0; R := dR*Anteil shr 16+R0; end; image4.Canvas.Pixels[x,y]:=r +g shl 8+b shl 16; inc(i); end; end; end;
image4.Picture.Assign(image2.picture);
setlength(DummyFeld,0); end;
end. |
Gruss Horst
Moderiert von raziel: Code- durch Delphi-Tags ersetzt
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Mi 22.11.06 19:24
Hallo,
ich habe mich extremn gewundert, wie es sein kann, das Programm so lahm ist.
Scheinbar ist scanline bei Timage etwas merkwürdig gestaltet.
Anbei eine geänderte Version, in der zuerst in ein Bitmap gerechnet wird und dieses dann anschliessend komplett in das image4 kopiert wird. Bei mir ca. 6 sec für 1000 Schritte also 130 fps, das müsste auch für verwöhnte Ansprüche genügen.
Es funktioniert nur bei 32-Bit Farbauflösung.
Gruss Horst
P.S. Keine Monsterdatei 
Einloggen, um Attachments anzusehen!
|
|
DaKirsche
      
Beiträge: 187
Win XP Pro, SuSe Linux 7.3 - 10.2, Win 2k3 Server, Win 2000, Win NT 4.0
Delphi 2006 Pro, Java, HTML, SQL, PHP, CSS
|
Verfasst: Mi 22.11.06 20:44
Hey....
wenn du jetzt noch in die FormCreate doublebuffered:=True; setzt, dann flackert es auch nicht mehr^^
_________________ Die simpelsten Fehler sind meist die Schwersten...
|
|
|