Autor Beitrag
Spaceguide
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 22.06.05 18:05 
user profile iconHeiko: FF=FloodFill (nicht FireFox)
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Mi 22.06.05 18:16 
Aso, sry :oops: . FF ist bei mir immer FireFox ;).
Spaceguide Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: 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:

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:
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>=0do Dec(y1);
   Inc(y1);

   spanLeft := false;
   spanRight := false;

   while CanVisit(x,y1) and (y1<Height) do
   begin
    AA.SetValueFast(x,y1,255); //Ausgabe
    visited[x+y1*width]:=1;

    if (not spanLeft) and (x>0and CanVisit(x-1,y1) then
    begin
     Push(x - 1, y1);
     spanLeft := true;
    end
    else
    if(spanLeft) and (x>0and (not CanVisit(x-1,y1)) then
    begin
     spanLeft := false;
    end;

    if (not spanRight) and (x<Width-1and CanVisit(x+1,y1) then
    begin
     Push(x + 1, y1);
     spanRight := true;
    end
    else
    if (spanRight) and (x<Width-1and (not CanVisit(x+1,y1)) then
    begin
     spanRight := false;
    end;

    Inc(y1);
   end;

  end;
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: 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...

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:
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;
 //  Punktbasiert statt linienbasiert: hier SetColor(x,y);
   if isValid(x,y-1then
   begin
    F1 := True;
    SetFlag(x,y-1);
   end else
    F1 := False;
   if isValid(x,y+1then
   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-1then
    begin
     if not G1 then
     begin
      SetFlag(x1,y-1);
      G1 := True;
     end;
    end else
     G1 := False;
    if isValid(x1,y+1then
    begin
     if not G2 then
     begin
      SetFlag(x1,y+1);
      G2 := True;
     end;
    end else
     G2 := False;
 //  Punktbasiert statt linienbasiert: hier SetColor(x1,y);
    dec(x1);
   end;
   x2 := x+1;
   G1 := F1;
   G2 := F2;
   while isValid(x2,y) do
   begin
    if isValid(x2,y-1then
    begin
     if not G1 then
     begin
      SetFlag(x2,y-1);
      G1 := True;
     end;
    end else
     G1 := False;
    if isValid(x2,y+1then
    begin
     if not G2 then
     begin
      SetFlag(x2,y+1);
      G2 := True;
     end;
    end else
     G2 := False;
 //  Punktbasiert statt linienbasiert: hier SetColor(x2,y);
    inc(x2);
   end;
   with Canvas do
   begin
    MoveTo(x1+1,y);
    LineTo(x2,y); // bis und ohne x2
   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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: Do 23.06.05 02:21 
Funktioniert, thanks.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: 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.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Fr 24.06.05 21:34 
Hallo!

Eventuell hilft dieser Link auch noch weiter, der mir vorhin zugetragen wurde. :les: 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. :gruebel:

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: 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).