Autor |
Beitrag |
Spaceguide
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Mi 22.06.05 14:17
Hat jemand einen schnellen FF, der korrekt arbeitet? Ich habe schon den schnellen von
www.student.kuleuven...22/CG/floodfill.html implementiert, aber ich kriege ihn öfters bei bestimmten Mustern zum Versagen. Von einem Implementierungsfehler meinerseits gehe ich nicht aus, habe alles schon 100x durchgecheckt.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 22.06.05 17:37
Ich liebe meine Glaskugel ... nur leider ist die Nutzungszeit pro Woche auf einen Moment begrenzt.
Könntest Du also bitte etwas von deinem Source zur Fehlersuche bereitstellen?
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Heiko
      
Beiträge: 3169
Erhaltene Danke: 11
|
Verfasst: Mi 22.06.05 17:44
@Spaceguide: Ich habe einen FireFox der schnell und ohne Fehler läuft. Du meinst sicherlich eine funktioniernde FF-Komponente die du brauchst, oder sehe ich das falsch?
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 22.06.05 18:05
Heiko: FF=FloodFill (nicht FireFox)
|
|
Heiko
      
Beiträge: 3169
Erhaltene Danke: 11
|
Verfasst: Mi 22.06.05 18:16
Aso, sry  . FF ist bei mir immer FireFox  .
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Mi 22.06.05 20:22
Flood-Fill steht doch in der Überschrift, da gehe ich dann davon aus, dass man im Kontext FF auch als Flood-Fill sieht.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 22.06.05 20:31
@Spaceguide: Benötigst Du noch Hilfe oder möchtest Du hier weiter OT diskutieren?
Für ersteres wäre eine Umsetzung meines Postings sinnvoll.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Mi 22.06.05 20:37
@BenBE: Wie gesagt, ich bin sehr sicher, dass meine Übersetzung nach Delphi fehlerfrei ist und dass der Fehler im Algorithmus selbst liegt. Der Algo liegt in C in der oben genannten Seite vor.
Hier meine Implementierung:
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:
| push(x, y);
while pop(x, y) do begin y1 := y; while CanVisit(x,y1) and (y1>=0) do Dec(y1); Inc(y1);
spanLeft := false; spanRight := false;
while CanVisit(x,y1) and (y1<Height) do begin AA.SetValueFast(x,y1,255); visited[x+y1*width]:=1;
if (not spanLeft) and (x>0) and CanVisit(x-1,y1) then begin Push(x - 1, y1); spanLeft := true; end else if(spanLeft) and (x>0) and (not CanVisit(x-1,y1)) then begin spanLeft := false; end;
if (not spanRight) and (x<Width-1) and CanVisit(x+1,y1) then begin Push(x + 1, y1); spanRight := true; end else if (spanRight) and (x<Width-1) and (not CanVisit(x+1,y1)) then begin spanRight := false; end;
Inc(y1); end;
end; |
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 22.06.05 20:52
Ich hab vor langer Zeit mal ein eigenes FloodFill geschrieben, jedoch auf GetPixel- und Line- Basis. Falls ich es irgendwo finde werde ich es nachher auf Delphi portieren und hier posten. Jedoch wird das dann über Canvas.Pixel laufen. Die Optimierung überlass ich dann dir... Falls ihr in der Zwischenzeit nicht schon eine Lösung findet...
Übrigens: Ich weiss nicht, ob du das gelesen hast:
Dein Link oben: | Do not copy/translate any of the content of this tutorial to a site/book/whatever without my permission. |
//Edit:
Hier kommt der nicht-optimierte Port. Das Optimieren überlass ich dir.
Die Unterprozedur FloodLine greift (via isValid) nur auf die Scanline y, y-1 und y+1 zu. Dort kannst du das Pixels[] durch etwas Schnelleres ersetzen. TStack ist aus der Unit Contnrs. Ist wohl nicht das schnellste. Statt TStack könntest du auch ein statisches Array nehmen. Der Stack hat ohnehin nie mehr als 100 Einträge. Ausser bei sehr komplizierten Bildern geht's vielleicht mal auf 200...
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: 120: 121: 122:
| procedure FloodFill(const Canvas: TCanvas; const x0, y0, minx, miny, maxx, maxy: Integer; const Color: TColor); var Stack: TStack; initialColor: TColor;
function isValid(const x,y: Integer): Boolean; begin Result := (x>=minx) and (y>=miny) and (x<=maxx) and (y<=maxy) and (Canvas.Pixels[x,y] = initialColor); end;
procedure SetFlag(const x, y: Integer); begin Stack.Push(Pointer(x+y shl 16)); end;
procedure FloodLine(const x, y: Integer); var x1, x2: Integer; G1, G2, F1, F2: Boolean; begin if not isValid(x,y) then exit; if isValid(x,y-1) then begin F1 := True; SetFlag(x,y-1); end else F1 := False; if isValid(x,y+1) then begin F2 := True; SetFlag(x,y+1); end else F2 := False; x1 := x-1; G1 := F1; G2 := F2; while isValid(x1,y) do begin if isValid(x1,y-1) then begin if not G1 then begin SetFlag(x1,y-1); G1 := True; end; end else G1 := False; if isValid(x1,y+1) then begin if not G2 then begin SetFlag(x1,y+1); G2 := True; end; end else G2 := False; dec(x1); end; x2 := x+1; G1 := F1; G2 := F2; while isValid(x2,y) do begin if isValid(x2,y-1) then begin if not G1 then begin SetFlag(x2,y-1); G1 := True; end; end else G1 := False; if isValid(x2,y+1) then begin if not G2 then begin SetFlag(x2,y+1); G2 := True; end; end else G2 := False; inc(x2); end; with Canvas do begin MoveTo(x1+1,y); LineTo(x2,y); end; end;
var x, y: Integer; Temp: DWord; begin Assert(minx>=0); Assert(miny>=0); Assert(maxx<1 shl 16); Assert(maxy<1 shl 16);
initialColor := Canvas.Pixels[x0,y0]; if initialColor = Color then exit; Canvas.Pen.Color := Color; Stack := TStack.Create; try FloodLine(x0,y0); while Stack.Count > 0 do begin Temp := DWord(Stack.Pop); x := Temp and (1 shl 16 - 1); y := Temp shr 16; FloodLine(x,y); end; finally Stack.Free; end; end; |
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 23.06.05 02:21
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Do 23.06.05 11:35
Hab meinen FloodFill jetzt doch noch ein wenig optimiert (Scanlines, etc.). Bei grösseren Flächen ist mein Algorithmus bis zu 15 mal schneller als Canvas.FloodFill.
//Edit: Kleiner Fehler in der Source korrigiert
Einloggen, um Attachments anzusehen!
Zuletzt bearbeitet von delfiphan am Do 23.06.05 11:53, insgesamt 1-mal bearbeitet
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 23.06.05 11:51
15 mal? Das ist schon beachtlich. Wie läuft Canvas.Floodfill eigentlich ab? Wird der von Windows bearbeitet oder an den Grafikkartentreiber geschickt und dann eventuell von der GPU übernommen?
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Do 23.06.05 11:58
15 ist der grösste von mir beobachtete Wert (wird bei mir erreicht, wenn ich in der Demo (siehe oben) am linken Rand etwa in der Mitte klicke).
Bei kleinen Flächen ist mein Algorithmus "nur" ca. 3-5 mal schneller.
Canvas.FloodFill geht über die gdi32.dll. Was die genau macht, weiss ich nicht. Aber über die GPU geht die Library wohl kaum 
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 23.06.05 12:24
Grafikkarten haben ja seit zig Jahren schon 2D-Beschleunigerfunktionen, womit das Zeichnen von Fenstern, Menüs und Knöpfen beschleunigt wird. Ich frage mich nur, ob auch alle Befehle auf die Canvas davon profitieren. Kann man ja mal ausprobieren, indem man bei Problembehebung die Beschleunigung abschaltet und dann die Geschwindigkeit misst.
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Fr 24.06.05 21:34
Hallo!
Eventuell hilft dieser Link auch noch weiter, der mir vorhin zugetragen wurde.  Im Kapitel 5a werden auch Floodfill-Algorithmen teils mit Implementierung besprochen. Hier besonders interessant dürfte die auf Seite 17 besprochene Saatfüll-Methode sein, die davor besprochenen Methoden sind dazu da, wenn das umschließende Polygon bekannt ist.
Sollte das schon der hier besprochene Algorithmus sein, möge man mir das nachsehen. So sehr habe ich mich dann in den Algorithmus doch nicht reingedacht.
Grüße
Christian
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Sa 25.06.05 12:21
Coole Zusammenfassungen! Mein Algorithmus ist zwar eine Eigenkonstruktion, funktioniert aber ziemlich ähnlich. Der Unterschied sehe ich darin, dass mein Algorithmus versucht, pro Zeile eine möglichst lange horizontale Linie reinzulegen, in der Zusammenfassung ist's eher punktbasiert.
Ein Vorteil meines Algorithmus ist, dass der Stack (weil linienbasiert) nie sehr gross werden kann, und deswegen auch nicht viel Rekursionsaufrufe nötig sind. (Ein Rekursionsschritt ist dann aber natürlich aufwändiger, jedoch ist die Zahl der Rekursionsaufrufe tiefer (und somit der Stack kleiner))
Bei meinem linienbasierten Verfahren muss man pro Pixel nur ca. 3 andere Pixel lesen (neues Pixel, Pixel drüber und Pixel drunter). Bei Canvas.FloodFill bzw. auch in der Zusammenfassung müssen 4 bzw. 5 Pixel gelesen werden. Deswegen ist die Komplexität dieser Algorithmen grundlegend höher.
IMHO ist das der Grund, wieso mein Algorithmus bei kleinen Flächen ca. 3-4 mal, und bei grossen Flächen sogar bis zu 15 mal schneller ist (kein linearer Zusammenhang).
|
|
|