1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. Andy

Beiträge von Andy

  • Mini-PCs

    • Andy
    • 11. August 2018 um 09:12

    Hi,

    Zitat von Peter S. Taler

    auf welchem Kistchen läuft xp? Würde mich dringend interesieren!

    Zitat von Andy

    Ich habe in unserer Produktion ca. 15-20 NUC´s als Clients laufen, von XP bis Win10 läuft da alles drauf.

    Das sind mehrere verschieden alte Geräte, ich such dir am Montag mal die Artikel-/Bestell-/Typen-Nummern bzw. Bezeichnungen raus.

    Die XP-Kisten werden sukzessive gerade von unserer IT ausgetauscht.

    Ich würde liebend gern die tadellos mit XP und den "alten" Excel-versionen laufenden Kistchen behalten, aber wir bekommen leider die aus heutiger Sicht "völlig veraltete" Hardware von unserem Dealer nicht mehr :(

    Dass diese "völlig veraltete" Hardware aber incl. BS bulletproof und mit völlig ausreichender Geschwindigkeit gearbeitet hat, ist ja seitens IT-Infrastrukturspezialistenseits auch völlig unerheblich. Da MUSS das neueste vom neuen her, Hard- und Softwareseitig, und wenn es DANN klemmt, fängt das gequieke an..."Andy, die Scripte laufen nicht mehr (richtig), guck mal woran das liegt!" :Face::Glaskugel:

  • GaussKernel (z.B. für Gauß'sche Unschärfe)

    • Andy
    • 24. Juli 2018 um 06:37

    Hi, vor 7 ( ! ) Jahren hatten wir das doch schon mal^^

    Kantenglättung

    Der Link zu TheShadowAE´s Thread sollte dir das Ergebnis bringen!

    Schade, dass bei den Forensoftware - "Upgrades" die Links zu den Threads verloren gehen...ggf könnte ja mal jemand eruieren, woran das liegt, bzw. wie man an diese (verlinkten) Threads wieder herankommt.

  • Dualboot von 2 HDD

    • Andy
    • 23. Juli 2018 um 08:22

    Derartige "Versuche" über Software führten bei mir in der Vergangenheit zum gleichen Ergebnis wie hier im Thread, nämlich keinem stabilen!

    Mit drei Platten mit unterschiedlichen BS, die SICHER voreinander verborgen/getrennt sein mussten, hatte ich nur eine Lösung:

    Letztendlich war es mir aber egal, ob ich in irgendeinem Softwaremenü meine Bootreihenfolge und die sichtbaren Platten auswähle, oder direkt im BIOS! Ist dort eine Platte ausgehängt, dann ist das auch so, und viel besser, man kommt auch durch Softwaregetrickse definitiv nicht dran!

    Wollte ich an eine der "alten" Platten, dann habe ich im BIOS genau diese als Bootplatte ausgewählt. Und die anderen "abgeknipst".

    DAS funktioniert definitiv an jedem Computer mit jedem beliebigen Bootmanager und BS.

    Alternativ gibt es Hardware, das sind Schalter, die es erlauben, vor dem Booten die Platten einzeln auszuwählen. Bei mir kam diese Variante nicht in Frage, dazu musste ich zu selten "umschalten".

  • Flood Fill

    • Andy
    • 16. Juli 2018 um 20:14

    wzbw...höhö, **huuuusssttt**8o

    Ich bin jetzt kurz vorm ASM, soweit haste mich schon =O

    Vorerst aber nur eine "reale" Bitmap, mit bissl Takte zählen komme ich auf eine Laufzeit für ein FloodFill mit meiner Methode für eine Bitmap von 800x800 Pixeln von ca 0,2Sekunden. (plusminus eine Zehnerpotenz :o) )

    Annahme dabei der "worst case" mit cachemisses bei jedem Speicherzugriff :party:

    Du kannst ja mal deine Methode für die "reale Bitmap" umbauen, sollte ja nur die entsprechende READ/WRITE-Funktion für das Pixel sein

    Fast Flood Fill 800x800 reale Bitmap2.au3

  • Flood Fill

    • Andy
    • 15. Juli 2018 um 16:43

    btw, bei deiner 5x-Funktion ist noch irgendwo der Wurm drin, schau mal hier in die Ergebnisbitmap:

    Ich hab da mal einen 1 Pixel breiten "Kamm" in den unteren Teil eingebaut...

    Fast Flood Fill 80x80 Kamm.au3

  • Flood Fill

    • Andy
    • 15. Juli 2018 um 16:12

    s. mein EDIT2 im vorherigen Post, ändert aber nichts an der Tatsache...

    Zitat von Mars

    Irgendwas stimmt das auch mit den Writes nicht, die müssten alle gleich viele haben. Kannst du das Ergebnis reproduzieren?

    hmmmm, wirklich seltsam....jetzt passt es

    Code
    FF_ANDY1:  13886.484 ms
    Reads:  639896 (R/Px: 2976.26)
    Writes: 639758
    
    FF_ANDY2:  12416.901 ms
    Reads:  639896 (R/Px: 2976.26)
    Writes: 639758
    
    FF_ANDY3:  12722.756 ms
    Reads:  639896 (R/Px: 2976.26)
    Writes: 639758
    
    FF3:       9616.531 ms
    Reads:  1916914 (R/Px: 8915.88)
    Writes: 639758
    
    FF4X:      7483.462 ms
    Reads:  1279599 (R/Px: 5951.62)
    Writes: 639758
    
    FF5X:      4468.539 ms
    Reads:  644680 (R/Px: 2998.51)
    Writes: 639758
    Alles anzeigen
  • Flood Fill

    • Andy
    • 15. Juli 2018 um 10:06
    Zitat von Mars

    Die Rekursion kann man wahrscheinlich drinlassen

    AutoIt steigt (jedenfalls bei mir) schon bei relativ "kleinen" Floodfills aus. Genau aus diesem Grund ist die iterative Variante besser, da macht es auch nix, wenn eine Bitmap mal mit 10000x10000 Pixeln "gefloodfilled" werden muss.

    Zitat von Mars

    Mir geht es vorallem darum die Zeit zu überbieten, solange es noch möglich ist die Read/Write Funktion irgendwie via AutoIt zu modifizieren ist mir Wurst wie der Rest abläuft.

    In nativem AutoIt hat es doch auch etwas an die Grenzen des Machbaren zu stoßen

    AutoItcode zu verwenden ist, wenn es auf Geschwindigkeit bei BERECHNUNGEN in langen Schleifen ankommt, extremst suboptimal!

    Bei einem Vergleich von zwei Algorithmen A und B gewinnt der bei einer Compilersprache 20x ( !!! ) schnellere Algorithmus A das Rennen, bei AutoIt allerdings B, weil AutoIt den Algorithmus B "besser" (schneller) verarbeiten kann, weil bspw. einfach die Codelänge kürzer ist! Das ist die Krux bei Interpreter vs Compiler, und nicht etwa, dass der Compiler "so viel schneller" ist! Denn DAS stimmt nur bei den schon erwähnten "langen" Berechnungsschleifen!

    Ich bin sicher, selbst der "langsamste" von dir verlinkte C-Code erfüllt die Aufgabe in einer beliebig großen Bitmap in nur in einer Handvoll Millisekunden. Und der "schnellste" Code ist dann wegen mir doppelt so schnell. Und jetzt? Ist ein "halber" Augenblick schneller als ein ganzer?!

    Bei AutoIt stellt sich diese Frage überhaupt nicht! Dort stellt sich eher die Frage "wieso AutoIt-Code"?! Wenn du eine 500x500 Pixel Bitmap per AutoIt-Code Floodfillen willst und dafür 3 Minuten brauchst und mit einem "AutoItoptimierten" Code dann nur noch 1,5 Minuten, dann ist das zwar absolut gesehen eine Verbesserung auf 50% Codelaufzeit, relativ gesehen ist dein Code aber 5000% langsamer als ein Algorithmusunabhängig schnellerer/langsamerer Compiler-Code....

    Den man, wie bereits von dir beschrieben, ja simpelst bspw. als Compilersprachen-Funktion in einer DLL (oder direkt) "inlinen" kann.


    //EDIT

    Nur mal für die Galerie, hier mal dein sonst unverändertes Script mit anderem Startpunkt und 800x800 Pixeln....soviel zum Thema "Spitzenkandidat" :whistling:

    Fast Flood Fill 800x800.au3

    Was dann bei mir zu folgendem Ergebnis führt:

    Code
    FF_ANDY3:  4154.791 ms
    Reads:  205506 (R/Px: 955.84)
    Writes: 205359
    
    FF3:       10111.162 ms
    Reads:  1916914 (R/Px: 8915.88)
    Writes: 639758
    
    FF4X:      8033.367 ms
    Reads:  1279599 (R/Px: 5951.62)
    Writes: 639758
    
    FF5X:      4611.533 ms
    Reads:  644680 (R/Px: 2998.51)
    Writes: 639758
    Alles anzeigen
  • Assembler - Fortsetzung

    • Andy
    • 15. Juli 2018 um 08:52
    Zitat von vcopsmtl

    bekomme bei meinen gewandelten *.bmp Bildern wie bei den *.tif Bildern von Autoit eine Fehlermeldeung:


    msgbox(0,"AutoIt","Error allocating Memory") ;mit Fehlerkreuz Icon in der Fehlermeldung

    und Speicherausnutzung von 2.191,9 MB

    naja, da wird wohl irgendwo im Code zuviel Speicher angefordert...

    Diese Stelle zu finden hat mich exakt 2 Minuten gekostet, davon waren 1,5 Minuten warten auf meine Kaffeemaschine, die restlichen 30 Sekunden habe ich mit einige Male Drücken von ALT-D verbracht, gefolgt von einem F5.

    In dieser Zeile Code wird der MAXIMAL erforderliche Speicher für den Text angefordert, um sämtliche mögliche Farben mit ihrer Anzahl im Format "1DEF44,12345678" (Farbe,Anzahl) in eine Textdatei zu schreiben.

    Da es aber kaum gigantische Bilder gibt, die diese gigantische Menge Farben haben, könnte man es bei extrem großen Bildern ja einfach mal mit einer Speicheranforderung mit der Hälfte der möglichen Zeichen versuchen.

    "Die Hälfte" wird bei Programmierern übrigens entweder mit /2 oder *0.5 in den Code übertragen...

    Bei meinem Beispielbild von 10000x10000 Pixeln dauert die "Auswertung", d.h. die Bestimmung der Anzahl der Farben und die Erstellung der entsprechenden Textdatei, ziemlich genau eine Sekunde.

  • Flood Fill

    • Andy
    • 11. Juli 2018 um 19:51

    Wenn du ernsthaft drangehen solltest, hier mal eine kleine Idee, wie man Koordinaten "anders" speichern kann...

    Gerade die Umwandlung von einer Pixeladresse in x- und y-Koordinaten "tut weh" weil MOD und DIV schon arg "teure" Operationen sind. (Na gut, Assembler gibt bei DIV sowohl den Quotient als auch den Rest zurück, "teuer" ist es trotzdem)

    Da ich die Pixelposition nur aus meiner Liste nehme, speichere ich sie dort direkt als 32Bit-Zahl ab, aufgeteilt in die 16 MSB als x-Koordinate und die 16 LSB als y-Koordinate

    $liste[$listcounter] = BitShift($x,-16)+$y

    und wieder zurück

    $y=bitand($liste[$counter],0xFFFF) ;16 LSB

    $x=Bitshift($liste[$counter],16) ;16 MSB

    Kostet für jede Koordinate 1 Takt, ein je nach Prozessor ausgeführtes DIV bis zu 20 Takte bei 32Bit bzw. bei 64Bit auch mal >50Takte

    AutoIt
    Func FloodFill_Andy16Bitxy($x, $y, $iColFill)
        Dim $liste[$iW * $iH]                               ;maximaler Füllbereich, normalerweise eine "leere" Bitmap
        Dim $bitmap_marker[$iW * $iH]
        Local $iColRead = Read($x, $y)
        $counter = 0                                        ;für Listenelement
        $listcounter = 0                                    ;anzahl elemente in liste
        $liste[$listcounter] = BitShift($x,-16)+$y          ;position pixel in bitmap mit x- und y-koordinate
        Write($x, $y, $iColFill)
    
        While 1                                             ;$listende_nicht_erreicht
    
            $y=bitand($liste[$counter],0xFFFF) ;16 LSB
            $x=Bitshift($liste[$counter],16) ;16 MSB
    
            $xL = $x - 1                                    ;linker pixel
            $xR = $x + 1                                    ;rechter pixel
            $yO = $y - 1
            $yU = $y + 1
    
            $pos = $y * $iW + $xL
            If $xL >= 0 And $bitmap_marker[$pos] = 0 Then   ;wenn im bereich und noch nicht in der Liste
                If Read($xL, $y) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($xL, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = BitShift($xL,-16)+$y             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            $pos = $y * $iW + $xR
            If $xR < $iW And $bitmap_marker[$pos] = 0 Then
                If Read($xR, $y) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($xR, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = BitShift($xR,-16)+$y             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            $pos = $yO * $iW + $x
            If $yO >= 0 And $bitmap_marker[$pos] = 0 Then
                If Read($x, $yO) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($x, $yO, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = BitShift($x,-16)+$yO             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            $pos = $yU * $iW + $x
            If $yU < $iH And $bitmap_marker[$pos] = 0 Then
                If Read($x, $yU) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($x, $yU, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = BitShift($x,-16)+$yU            ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            If $listcounter = $counter Then ExitLoop
            $counter = $counter + 1
    
        WEnd
    
    
    EndFunc
    Alles anzeigen
  • Flood Fill

    • Andy
    • 11. Juli 2018 um 07:33
    Zitat von Mars

    Scanline hat sehr wohl einen Vorteil, hier werden Bereiche "gesperrt" (eigentlich logisch ausgeschlossen) und nicht einzelne Pixel. Das heißt, dass man für den ganzen Bereich auch nur eine einzige Abfrage braucht.

    Frage: Wie viele Abfragen auf jedes Pixel hast du in einer Scanline?

    DU MUSST jedes einzelne Pixel abfragen, Und das ist der Punkt!

    Zitat von Mars

    Für eine im Grenzfall sehr lange Linie kann man also mit vernachlässigbar wenigen Operationen sehr viele Checks einsparen.

    Du sparst ja nur das ein, was du im Vorfeld durch die "faule" Methode bereits "rausgeballert" hast.

    if(nx >= 0 && nx < w && ny >= 0 && ny < h && screenBuffer[ny][nx] == oldColor) { push(stack, nx, ny);DAS ist die Krankheit!

    5 Abfragen, obwohl 3 reichen würden!

    Letztendlich kannst du nur einsparen, indem du mehrere Pixel gleichzeitig abfragst, und das geht bspw. durch SSE (wirklich SEHR einfach in C zu implementieren, da müssen nur die Variablen mit uint4 spezifiziert werden).

    Da kann ich pro Speicher-read 4 Pixel gleichzeitig auf iColRead prüfen UND AUCH GLEICH mit iColFill BESCHREIBEN!

  • Flood Fill

    • Andy
    • 10. Juli 2018 um 18:28
    Zitat von Mars

    Der letzte Schritt zur vollendung der besten FloodFill Funktion des Planeten wird das ganze auf eine Iterative Version umgestellt (incl Umstellung der Bitmap auf eine Struct) und geschaut ob man dann noch etwas wegkürzen kann (wahrscheinlich ein paar Umrechnungen von xy -> pointer). Für ASM wird die Sache dann wohl zu lang zum programmieren werden, aber in C/Go/Basic ist das quasi Copy & Paste -> Compilen, inlinen (DllCallAdress) -> schnellste Version die es gibt. Um dazu eine gute Idee zu bekommen gehe ich jetzt aber mal wieder ins Bett

    Der Algorithmus ist nur dann "schnellstmöglich" wenn im Vorfeld so wenige Vergleiche wie nötig stattfinden. Rekursion fällt definitiv weg, da schon bei "kleinen" Flächen der Stack überläuft...

    Scanline hat imho auch keinen Vorteil, da die Abfrage "ist der nächste Punkt in der Farbe iColRead ? Ja, dann einfärben mit iColFill! Nein, nächster Punkt suchen..." die Minimalstabfolge ist!

    Der Knackpunkt dabei ist ja "Nein, nächster Punkt suchen..."!

    Die von mir angewandte "Liste" enthält ja bereits nur Pixel(adressen), die auf "Nachbarn" zu untersuchen sind. Und jeder dieser Pixel hat nun mal 4 Nachbarn, von denen definitiv einer (der vorherige Startpunkt) bereits mit iColFill gefüllt wurde. Mal angenommen, man würde dieser "Pixeladresse" 4 Bits mitgeben (die 4 MSB werden bei "normalgroßen" Bitmaps sowieso nicht genutzt) welche die 4 Richtungen der weiteren Prüfung freigeben (1) oder sperren(0).

    Die Frage lautet jetzt, ob es mehr Prozessortakte kostet, die 4 Bits abzufragen, oder gleich (alle) 4 Adressen der Nachbarpixel, wobei man bei einem "Treffer" direkt schon auf iColRead geprüft hätte....

    Ist die im schlechtesten Fall eine überflüssige Abfrage auf den Ursprungspunkt den Aufwand "Bits vergleichen und eine Jump-chain abklappern" wert?

    Sehr interessant!!! -> Ausprobieren!:D

    In meinem vorliegenden Algorithmus habe ich ja eine "1-Bit-Bitmap" implementiert, um die zu "sperrenden" bzw. nicht weiter zu berücksichtigenden Pixeladressen direkt zu markieren. Dieses Bit kann man aber auch einfach direkt an das MSB der "Listenadresse" schreiben....

    Was ich definitiv machen würde, wäre per SSE, die 4 "Nachbaradressen" gleichzeitig(!) zu berechnen (1 Takt) und auch abzufragen. Liegen dann diese 4 Pixeladressen im Cache, "schwuppt" die folgende Abfrage innerhalb eines Prozessortaktes. So wie ich das zzt. sehe, läuft alles auf eine clevere Nutzung des Cache raus!

    An der eigentlichen "Berechnung" ist ja sowieso nix dran.8)

    Wobei in heutige Lvl3-Caches ohne Probleme die meisten Bitmaps reinpassen sollten^^

    Da der Lvl3-Cache von allen Cores auch gleichzeitig genutzt werden kann, würde sich ein Multithreading anbieten, bei ASM also absolut kein Thema


    Die OpenCL-Variante lass ich mal außen vor:theke:

  • Flood Fill

    • Andy
    • 8. Juli 2018 um 13:56
    Zitat von Mars

    den Prozessor zwingen könnte die Prüfliste in den Cache zu stecken wäre das nochtmal eine andere Geschichte,

    In dem Moment, wo du die erste Position aus der "Liste" (sprich "Speicherbereich", vorteilhafter Weise eine Struct ) liest, werden sämtliche darauf folgenden Positionen in den Cache geladen. Dann liegen zwar die Listenitems alle im Cache, aber das sind ja nur die Adressen bzw. Positionen der Pixel. Idealerweise würde man dann die "kleinste" Adresse dort zuerst laden und hätte die meisten anderen somit im Cache...

    Bei 128kB Lvl1-Cache passt da ja ein Teil der Bitmap rein^^

    Zitat von Mars

    In einer üblichen Bitmap ist es aber nahezu gleich Aufwändig die Bitmapadresse auf "[Adresse] = color" zu testen oder die Prüfliste mit "[pos] = 0" zu checken.

    DAS stimmt, ist aber nicht die Intention der Liste. Sinn ist es, die Anzahl der Listenitems, also die "nächsten abzuarbeitenden" Pixelpositionen, radikal zu dezimieren. Wenn es dumm läuft, und das ist bei den meisten Pixeln so, und auch bei sämtlichen Rekursionsmodellen, dann wird jedes zu prüfende Pixel 4 mal, nämlich von Links, Rechts, Oben und Unten, "vorgemerkt". An dieser Stelle ist an diesem Zeitpunkt nämlich die Farbe nicht $iColFill sondern $iColRead!

    In der Liste befinden sich AUSSCHLIESSLICH zu prüfende Pixel, d,h. ich könnte mit einem Thread einen Teil der Liste abarbeiten, und mit einem anderen den Rest.

    Da die Liste extrem schnell wächst (mit jeder Iteration kommen idealerweise 3 Pixel dazu (eins wird ja aktuell abgearbeitet)) lohnt es sich bestimmt, die Arbeit "aufzuteilen".

    Zitat von Mars

    OpenCL werde ich aber nie wieder anfassen, das ist Hexerei und Zauberei

    Ach, bissl Voodoo muss ab und zu sein, du weisst schon...."separates the boys from the men":rofl:

    Blöd ist natürlich nur, dass am Anfang die Liste nicht viele Items enthält, jede Rückgabe der OCL-Abarbeitungsfunktion würde die weiteren ermittelten Listitems erhalten.

    Bei kleinen Flächen macht das imho wenig Sinn, aber wenn ich 1024 Workitems gleichzeitig eine Pixelfarbe setzen und danach wieder 1024 Listitems zurückgeben lasse, dann rockt der Algorithmus schon^^

    Zitat von Mars

    Edit: Villeicht wenn man eine Art QuadTree aufspannt

    Der vorliegende Algorithmus "baut" dir ja den QuadTree auf! Logisch, wenn man alle einzufärbenden Pixel bereits hat, DANN ist es einfach ;)


    //EDIT

    Und wieder fragt man sich, warum man bei einer Funktion, welche auch bei großen Bitmaps nur einige Millisekunden dauert, den Aufwand einer "Beschleunigung um Faktor X" treiben sollte...

  • Flood Fill

    • Andy
    • 8. Juli 2018 um 06:59

    ....wenn man mal eine Nacht schläft, dann kommt man oft zu erstaunlichen Ergebnissen am nächsten Morgen :o)

    Die Abfrage je Pixel reduziert sich um eine weitere, denn wenn ich bspw. die Position um 1 in x-Richtung vermindere, dann brauche ich zwangsläufig nicht mehr auf $x<$iW zu prüfen, sondern nur noch auf $x>=0

    Gegenüber der von dir schon verlinkten"kurzen" Version in einer Schleife reduziert sich beim loop unrolling die Abfrage bzw. die Vergleiche pro Pixel von 5 auf 3!

    1) "neue" Position If $xL >= 0 And

    2) ist diese Pixelposition bereits Element in der "Liste" $bitmap_marker[$pos]=0 Then

    3) Farbe lesen an dieser Position If Read($xL, $y) = $iColRead Then

    wird dann zu

    Code
    $pos=$y * $iW + $xL  ;neue x-position      
           If $xL >= 0 and $bitmap_marker[$pos]=0 Then  ;wenn im bereich und noch nicht in der Liste
                If Read($xL, $y) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xL, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos ;position pixel in bitmap
                    $bitmap_marker[$pos]=1   ;position in der 1-Bit-Bitmap :-) markieren 
                EndIf
           EndIf

    Gegenüber den 5 Vergleichen im Link eine massive Verbesserung, da dort der eigentliche Vorteil, nämlich die Abfrage, ob das Pixel in der Liste bereits schon berechnet wurde, gar nicht berücksichtigt ist!

    In der verlinkten Version wird ja die Position des zu untersuchenden Pixels auf den "Stack" gepushed. Da in den meisten Fällen dieses Pixel aber wiederum 4 Nachbarn hat, pushed jeder Nachbar (unötigerweise) diese Position, der Stack muss zwangsläufig viel größer werden und die Abfragen wachsen im gleichen Anteil!

    Die Reihenfolge der Pixelprüfungen legt man günstiger Weise auf oben, links, rechts, unten. So liegen auch bei großen Bitmaps sämtliche Positionen bereits nach der Prüfung auf "oben" im Cache (zwei komplette Pixelzeilen).


    //EDIT Komplettscript:

    Gegenüber Vorversion ca. 10% Laufzeit eingespart...bei Autoit ( ! ), gar nicht auszumalen, wie sich das bei einer Compilersprache auswirken würde

    Code
    #include <Array.au3>
    
    
    ; Einstellungen zum Ausprobieren
    Global Const $n = 10                                   ; Anzahl Runden deren mittlere Zeit gemessen wird
    Global Const $ArrayDisplay = false                       ; Will man die Arrays sehen ?
    
    ; Die "Bitmap" wird hier erstellt. Es wird angenommen, dass die FloodFill Algorithmen iW und iH kennen (global)
    Global Const $iW = 24
    Global Const $iH = 24
    Global $aBitmap[$iH][$iW], $aReads[$iH][$iW], $aWrites[$iH][$iW], $iPixel = 0
    Func Reset()                                            ; Hier kann sich jeder eine "bitmap" basteln mit 2 Farben
        $iPixel = 0
        For $y = 0 To $iW - 1 Step 1
            For $x = 0 To $iH - 1 Step 1
                $aBitmap[$y][$x] = ($x - 8) ^ 2 + ($y - 8) ^ 2 < 6 ^ 2 ? 2 : 1
                $aBitmap[$y][$x] = ($x - 16) ^ 2 + ($y - 16) ^ 2 < 6 ^ 2 ? 2 : $aBitmap[$y][$x]
                If $aBitmap[$y][$x] = 2 Then $iPixel += 1
                $aReads[$y][$x] = 0
                $aWrites[$y][$x] = 0
            Next
        Next
        $aBitmap[19][2] = 2
        $aBitmap[18][2] = 2
        $aBitmap[17][2] = 2
        $aBitmap[15][2] = 2
        $aBitmap[15][3] = 2
        $aBitmap[16][4] = 2
        $aBitmap[17][5] = 2
        $aBitmap[18][4] = 2
        $aBitmap[19][4] = 2
        $aBitmap[16][1] = 2
        $aBitmap[15][0] = 2
        $aBitmap[17][0] = 2
        $aBitmap[19][3] = 2
        $aBitmap[7][7] = 1
    
    EndFunc                                                 ;==>Reset
    ; ################################################################################
    
    Global $iTimer, $iTime
    Reset()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill1(2, 2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('FF1: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill2(2, 2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    
    ConsoleWrite('FF2: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill3(2, 2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('FF3: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill_Andy(2, 2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('Andy: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    
    
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill_Andy2(2, 2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('Andy2: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    
    Func FloodFill_Andy($x, $y, $iColFill)
        Dim $liste[$iW * $iH]                               ;maximaler Füllbereich, normalerweise eine "leere" Bitmap
        Dim $bitmap_marker[$iW * $iH]
        Local $iColRead = Read($x, $y)
        $counter = 0                                        ;für Listenelement
        $listcounter = 0                                    ;anzahl elemente in liste
        $liste[$listcounter] = $y * $iW + $x                ;position pixel in bitmap
        Write($x, $y, $iColFill)
        While 1                                             ;$listende_nicht_erreicht
    
            ;koordinate nächstes Element in der Liste, diese umrecherei ist in einer bitmap völlig unnötig.....
            $x = Mod($liste[$counter], $iW)
            $y = Int($liste[$counter] / $iH)
    
    
            ;4 Nachbarpunkte auf $iColRead testen
            $xL = $x - 1                                    ;linker pixel
            $yL = $y
            $xR = $x + 1                                    ;rechter pixel
            $yR = $y
            $xO = $x                                        ;oberer Pixel
            $yO = $y - 1
            $xU = $x                                        ;unterer Pixel
            $yU = $y + 1
    
            If $xL >= 0 And $xL < $iW And $bitmap_marker[$yL * $iW + $xL] = 0 Then ;wenn im bereich und noch nicht in der Liste
                If Read($xL, $yL) = $iColRead Then          ;Pixel mit $iColRead gefunden
                    Write($xL, $yL, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yL * $iW + $xL  ;position pixel in bitmap
                    $bitmap_marker[$yL * $iW + $xL] = 1
                EndIf
            EndIf
            If $xR >= 0 And $xR < $iW And $bitmap_marker[$yR * $iW + $xR] = 0 Then
                If Read($xR, $yR) = $iColRead Then          ;Pixel mit $iColRead gefunden
                    Write($xR, $yR, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yR * $iW + $xR  ;position pixel in bitmap
                    $bitmap_marker[$yR * $iW + $xR] = 1
                EndIf
            EndIf
            If $yO >= 0 And $yO < $iH And $bitmap_marker[$yO * $iW + $xO] = 0 Then
                If Read($xO, $yO) = $iColRead Then          ;Pixel mit $iColRead gefunden
                    Write($xO, $yO, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yO * $iW + $xO  ;position pixel in bitmap
                    $bitmap_marker[$yO * $iW + $xO] = 1
                EndIf
            EndIf
            If $yU >= 0 And $yU < $iH And $bitmap_marker[$yU * $iW + $xU] = 0 Then
                If Read($xU, $yU) = $iColRead Then          ;Pixel mit $iColRead gefunden
                    Write($xU, $yU, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yU * $iW + $xU  ;position pixel in bitmap
                    $bitmap_marker[$yU * $iW + $xU] = 1
                EndIf
            EndIf
            If $listcounter = $counter Then ExitLoop
            $counter = $counter + 1
            ;    _arraydisplay($liste)
    ;~         If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
        WEnd
    
    ;~     If $ArrayDisplay Then _ArrayDisplay($areads)
    ;~     If $ArrayDisplay Then _ArrayDisplay($bitmap_marker)
    
    EndFunc                                                 ;==>FloodFill_Andy
    
    
    Func FloodFill_Andy2($x, $y, $iColFill)
        Dim $liste[$iW * $iH]                               ;maximaler Füllbereich, normalerweise eine "leere" Bitmap
        Dim $bitmap_marker[$iW * $iH]
        Local $iColRead = Read($x, $y)
        $counter = 0                                        ;für Listenelement
        $listcounter = 0                                    ;anzahl elemente in liste
        $liste[$listcounter] = $y * $iW + $x                ;position pixel in bitmap
        Write($x, $y, $iColFill)
    
        While 1                                             ;$listende_nicht_erreicht
    
            ;koordinate nächstes Element in der Liste, diese umrecherei ist in einer bitmap völlig unnötig.....
            $x = Mod($liste[$counter], $iW)
            $y = Int($liste[$counter] / $iH)
    
    
            ;4 Nachbarpunkte auf $iColRead testen
            $xL = $x - 1                                    ;linker pixel
            $xR = $x + 1                                    ;rechter pixel
            $yO = $y - 1
            $yU = $y + 1
    
            $pos = $y * $iW + $xL
            If $xL >= 0 And $bitmap_marker[$pos] = 0 Then   ;wenn im bereich und noch nicht in der Liste
                If Read($xL, $y) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($xL, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            $pos = $y * $iW + $xR
            If $xR < $iW And $bitmap_marker[$pos] = 0 Then
                If Read($xR, $y) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($xR, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            $pos = $yO * $iW + $x
            If $yO >= 0 And $bitmap_marker[$pos] = 0 Then
                If Read($x, $yO) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($x, $yO, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            $pos = $yU * $iW + $x
            If $yU < $iH And $bitmap_marker[$pos] = 0 Then
                If Read($x, $yU) = $iColRead Then           ;Pixel mit $iColRead gefunden
                    Write($x, $yU, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos             ;position pixel in bitmap
                    $bitmap_marker[$pos] = 1
                EndIf
            EndIf
            If $listcounter = $counter Then ExitLoop
            $counter = $counter + 1
            ;    _arraydisplay($liste)
    ;~         If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
        WEnd
    
    ;~     If $ArrayDisplay Then _ArrayDisplay($areads)
    ;~     If $ArrayDisplay Then _ArrayDisplay($bitmap_marker)
    
    EndFunc                                                 ;==>FloodFill_Andy2
    
    
    
    Func FloodFill1($x, $y, $iColFill, $iColArea = 0)       ; Aus dem Bilderbuch bzw. Wikipedia.
        Local $iColRead = Read($x, $y)                      ; Tempo    : Bummelbahn mit angezogener Handbremse
        If $iColArea = 0 Then $iColArea = $iColRead         ; Rekursion: Sehr schnell sehr viele Rekursionen
        If $iColArea <> $iColRead Then Return               ; Reads    : So viel wie möglich (schlecht)
        If $iColFill = $iColRead Then Return
        Write($x, $y, $iColFill)
        If $x > 0 Then FloodFill1($x - 1, $y, $iColFill, $iColArea)
        If $x < $iW - 1 Then FloodFill1($x + 1, $y, $iColFill, $iColArea)
        If $y > 0 Then FloodFill1($x, $y - 1, $iColFill, $iColArea)
        If $y < $iH - 1 Then FloodFill1($x, $y + 1, $iColFill, $iColArea)
    EndFunc                                                 ;==>FloodFill1
    
    Func FloodFill2($x, $y, $iColFill, $iColArea = 0, $iLast = -1) ; Genau das gleiche wie FloodFill1 nur, dass man nicht mehr dahingehen kann wo man herkommt.
        Local $iColRead = Read($x, $y)                      ; Tempo    : Bummelbahn
        If $iColArea = 0 Then $iColArea = $iColRead         ; Rekursion: Sehr schnell sehr viele Rekursionen
        If $iColArea <> $iColRead Then Return               ; Reads    : Weniger als FloodFill1 und FloodFill3
        If $iColFill = $iColRead Then Return
        Write($x, $y, $iColFill)
        If $iLast <> 0 And $x > 0 Then FloodFill2($x - 1, $y, $iColFill, $iColArea, 2)
        If $iLast <> 2 And $x < $iW - 1 Then FloodFill2($x + 1, $y, $iColFill, $iColArea, 0)
        If $iLast <> 3 And $y > 0 Then FloodFill2($x, $y - 1, $iColFill, $iColArea, 1)
        If $iLast <> 1 And $y < $iH - 1 Then FloodFill2($x, $y + 1, $iColFill, $iColArea, 3)
    EndFunc                                                 ;==>FloodFill2
    
    Func FloodFill3($x, $y, $iColFill, $iColArea = 0)       ; Spontan ausgedacht. Nachschlagen ergab, dass eine ähnliche Methode Scanline Flood Fill heißt.
        If $iColArea = 0 Then $iColArea = Read($x, $y)      ; Tempo    : Mofa mit aufgebohrtem Zylinderkopf und zugepetztem Auspuff.
        Write($x, $y, $iColFill)                            ; Rekursion: Eine für jede "Linie" in jeder Zeile. Also irgendwas wie die CONST * AREAHEIGHT (sollte nicht so schnell wachsen)
        For $xMax = $x + 1 To $iW - 1 Step 1                ; Reads    : Weniger als FloodFill1 und mehr als FloodFill3
            $iColRead = Read($xMax, $y)
            If $iColRead <> $iColArea Then ExitLoop
            Write($xMax, $y, $iColFill)
        Next
        For $xMin = $x - 1 To 0 Step -1
            $iColRead = Read($xMin, $y)
            If $iColRead <> $iColArea Then ExitLoop
            Write($xMin, $y, $iColFill)
        Next
        If $xMin = -1 Then $xMin = 0
        If $xMax = $iW Then $xMax = $iW - 1
        If $y > 0 Then
            For $i = $xMin To $xMax Step 1
                If Read($i, $y - 1) = $iColArea Then FloodFill3($i, $y - 1, $iColFill, $iColArea)
            Next
        EndIf
        If $y < $iH - 1 Then
            For $i = $xMin To $xMax Step 1
                If Read($i, $y + 1) = $iColArea Then FloodFill3($i, $y + 1, $iColFill, $iColArea)
            Next
        EndIf
    EndFunc                                                 ;==>FloodFill3
    
    Func Info($bPlot = False)
        Local $iReads, $iWrites
        If $bPlot Then ConsoleWrite('##################################### [ Reads | Writes ] ######################################' & @CRLF)
        For $y = 0 To 15 Step 1
            For $x = 0 To 15 Step 1
                $iReads += $aReads[$y][$x]
                $iWrites += $aWrites[$y][$x]
                If $bPlot Then ConsoleWrite('[' & $aReads[$y][$x] & '|' & $aWrites[$y][$x] & '] ')
            Next
            If $bPlot Then ConsoleWrite(@CRLF)
        Next
        ConsoleWrite('Reads:  ' & $iReads & @CRLF)
        ConsoleWrite('Writes: ' & $iWrites & @CRLF)
        If $bPlot Then ConsoleWrite('###############################################################################################' & @CRLF)
    EndFunc                                                 ;==>Info
    
    Func Read($x, $y)
        $aReads[$y][$x] += 1
        Return $aBitmap[$y][$x]
    EndFunc                                                 ;==>Read
    
    Func Write($x, $y, $iCol)
        $aWrites[$y][$x] += 1
        $aBitmap[$y][$x] = $iCol
    EndFunc                                                 ;==>Write
    Alles anzeigen
  • Flood Fill

    • Andy
    • 7. Juli 2018 um 18:23

    Ich habe, wie du sicher festgestellt hast, in weiser Voraussicht schon "Loop unrolling" betrieben, mit dem Hintergrund, so nur 2 Koordinaten je Pixel (s. Script) prüfen zu müssen.

    Bissl kürzbar und "schneller" ist auch, die Position $pos vor dem Vergleich auszurechnen.

    Umgewandelt in eine "Struct"-Version statt Array wäre das dann eine Steilvorlage für ....na schaumamal^^

    Code
       While 1;$listende_nicht_erreicht
    
            ;koordinate nächstes Element in der Liste, diese umrecherei ist in einer bitmap völlig unnötig.....
            $x = Mod($liste[$counter], $iW)
            $y = Int($liste[$counter] / $iH)
    
    
            ;4 Nachbarpunkte auf $iColRead testen
            $xL = $x - 1 ;linker pixel
            $xR = $x + 1 ;rechter pixel
            $yO = $y - 1
            $yU = $y + 1
    
            $pos=$y * $iW + $xL
           If $xL >= 0 And $xL < $iW and $bitmap_marker[$pos]=0 Then  ;wenn im bereich und noch nicht in der Liste
                If Read($xL, $y) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xL, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos ;position pixel in bitmap
                    $bitmap_marker[$pos]=1
                EndIf
           EndIf
           $pos=$y * $iW + $xR
            If $xR >= 0 And $xR < $iW and $bitmap_marker[$pos]=0 Then
                If Read($xR, $y) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xR, $y, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos ;position pixel in bitmap
                    $bitmap_marker[$pos]=1
                EndIf
            EndIf
            $pos=$yO * $iW + $x
            If $yO >= 0 And $yO < $iH and $bitmap_marker[$pos]=0 Then
                If Read($x, $yO) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($x, $yO, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos ;position pixel in bitmap
                    $bitmap_marker[$pos]=1
                EndIf
            EndIf
            $pos=$yU * $iW + $x
            If $yU >= 0 And $yU < $iH and $bitmap_marker[$pos]=0 Then
                If Read($x, $yU) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($x, $yU, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $pos ;position pixel in bitmap
                    $bitmap_marker[$pos]=1
                EndIf
            EndIf
            If $listcounter = $counter Then exitloop
            $counter = $counter + 1
            ;    _arraydisplay($liste)
    ;~         If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
        WEnd
    Alles anzeigen

    //EDIT

    Script Teil geändert/gekürzt

  • Flood Fill

    • Andy
    • 7. Juli 2018 um 15:12

    Hi,

    habe keine rekursive, sondern iterative Variante.

    Schau aber bei deinem floodfill3() mal nach, ob das Ergebnis so gewollt ist, auch "diagonal" erreichbare Felder zu füllen?!

    Mein Beispiel könnte bei Bearbeitung einer "realen" Bitmap (die ist nämlich kein Array mit x- und y-Koordinaten ;) ) noch etwas schneller sein, da die meisten Umrechnungen entfallen.

    Die iterative Variante hat den Vorteil, die unbearbeiteten, in der abzuarbeitenden Liste befindlichen "Pixel" je einem Thread zuordnen zu können, ohne dass es zu Überschneidungen oder Ärger mit Synchronisierungen kommt.

    Per OpenCL bspw. kann/könnte man somit mehrere Listenblöcke von bspw. je 256 Pixelpositionen GLEICHZEITIG bearbeiten.

    Nachteil ist, dass man eine weite 1-Bit-Bitmap als Markierungshilfe benötigt....

    Code
    #include <Array.au3>
    
    ; Einstellungen zum Ausprobieren
    Global Const $n = 10 ; Anzahl Runden deren mittlere Zeit gemessen wird
    Global Const $ArrayDisplay = true ; Will man die Arrays sehen ?
    
    ; Die "Bitmap" wird hier erstellt. Es wird angenommen, dass die FloodFill Algorithmen iW und iH kennen (global)
    Global Const $iW = 24
    Global Const $iH = 24
    Global $aBitmap[$iH][$iW], $aReads[$iH][$iW], $aWrites[$iH][$iW], $iPixel = 0
    Func Reset() ; Hier kann sich jeder eine "bitmap" basteln mit 2 Farben
        $iPixel = 0
        For $y = 0 To $iW - 1 Step 1
            For $x = 0 To $iH - 1 Step 1
                $aBitmap[$y][$x] = ($x - 8) ^ 2 + ($y - 8) ^ 2 < 6 ^ 2 ? 2 : 1
                $aBitmap[$y][$x] = ($x - 16) ^ 2 + ($y - 16) ^ 2 < 6 ^ 2 ? 2 : $aBitmap[$y][$x]
                If $aBitmap[$y][$x] = 2 Then $iPixel += 1
                $aReads[$y][$x] = 0
                $aWrites[$y][$x] = 0
            Next
        Next
        $aBitmap[19][2]=2
        $aBitmap[18][2]=2
        $aBitmap[17][2]=2
        $aBitmap[15][2]=2
        $aBitmap[15][3]=2
        $aBitmap[16][4]=2
        $aBitmap[17][5]=2
        $aBitmap[18][4]=2
        $aBitmap[19][4]=2
        $aBitmap[16][1]=2
        $aBitmap[15][0]=2
        $aBitmap[17][0]=2
        $aBitmap[19][3]=2
        $aBitmap[7][7]=1
    
    EndFunc   ;==>Reset
    ; ################################################################################
    
    Global $iTimer, $iTime
    Reset()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill1(2,2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('FF1: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill2(2,2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    
    ConsoleWrite('FF2: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill3(2,2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('FF3: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    
    $iTime = 0
    For $i = 1 To $n Step 1
        Reset()
        $iTimer = TimerInit()
        FloodFill_Andy(2, 2, 123)
        $iTime += TimerDiff($iTimer)
    Next
    ConsoleWrite('FF3: ' & StringFormat('%.3f', $iTime / $n) & ' ms' & @CRLF)
    Info()
    If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
    ConsoleWrite('###############' & @CRLF)
    
    
    Func FloodFill_Andy($x, $y, $iColFill)
        Dim $liste[$iW * $iH] ;maximaler Füllbereich, normalerweise eine "leere" Bitmap
        dim $bitmap_marker[$iW*$iH]
        Local $iColRead = Read($x, $y)
        $counter = 0
        $listcounter = 0 ;anzahl elemente in liste
        $liste[$listcounter] = $y * $iW + $x ;position pixel in bitmap
        Write($x, $y, $iColFill)
        While 1;$listende_nicht_erreicht
    
            ;koordinate letztes Element in der Liste, diese umrecherei ist in einer bitmap völlig unnötig.....
            $x = Mod($liste[$counter], $iW)
            $y = Int($liste[$counter] / $iH)
    
    
            ;4 Nachbarpunkte auf $iColRead testen
            $xL = $x - 1 ;linker pixel
            $yL = $y
            $xR = $x + 1 ;rechter pixel
            $yR = $y
            $xO = $x ;oberer Pixel
            $yO = $y - 1
            $xU = $x ;unterer Pixel
            $yU = $y + 1
    
            If $xL >= 0 And $xL < $iW and $bitmap_marker[$yL * $iW + $xL]=0 Then  ;wenn im bereich und noch nicht in der Liste
                If Read($xL, $yL) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xL, $yL, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yL * $iW + $xL ;position pixel in bitmap
                    $bitmap_marker[$yL * $iW + $xL]=1
                EndIf
            EndIf
            If $xR >= 0 And $xR < $iW and $bitmap_marker[$yR * $iW + $xR]=0 Then
                If Read($xR, $yR) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xR, $yR, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yR * $iW + $xR ;position pixel in bitmap
                    $bitmap_marker[$yR * $iW + $xR]=1
                EndIf
            EndIf
            If $yO >= 0 And $yO < $iH and $bitmap_marker[$yO * $iW + $xO]=0 Then
                If Read($xO, $yO) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xO, $yO, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yO * $iW + $xO ;position pixel in bitmap
                    $bitmap_marker[$yO * $iW + $xO]=1
                EndIf
            EndIf
            If $yU >= 0 And $yU < $iH and $bitmap_marker[$yU * $iW + $xU]=0 Then
                If Read($xU, $yU) = $iColRead Then ;Pixel mit $iColRead gefunden
                    Write($xU, $yU, $iColFill)
                    $listcounter += 1
                    $liste[$listcounter] = $yU * $iW + $xU ;position pixel in bitmap
                    $bitmap_marker[$yU * $iW + $xU]=1
                EndIf
            EndIf
            If $listcounter = $counter Then exitloop
            $counter = $counter + 1
            ;    _arraydisplay($liste)
    ;~         If $ArrayDisplay Then _ArrayDisplay($aBitmap)
    
        WEnd
    
    ;~     If $ArrayDisplay Then _ArrayDisplay($areads)
    ;~     If $ArrayDisplay Then _ArrayDisplay($bitmap_marker)
    
    EndFunc   ;==>FloodFill_Andy
    
    
    Func FloodFill1($x, $y, $iColFill, $iColArea = 0) ; Aus dem Bilderbuch bzw. Wikipedia.
        Local $iColRead = Read($x, $y) ; Tempo    : Bummelbahn mit angezogener Handbremse
        If $iColArea = 0 Then $iColArea = $iColRead ; Rekursion: Sehr schnell sehr viele Rekursionen
        If $iColArea <> $iColRead Then Return ; Reads    : So viel wie möglich (schlecht)
        If $iColFill = $iColRead Then Return
        Write($x, $y, $iColFill)
        If $x > 0 Then FloodFill1($x - 1, $y, $iColFill, $iColArea)
        If $x < $iW - 1 Then FloodFill1($x + 1, $y, $iColFill, $iColArea)
        If $y > 0 Then FloodFill1($x, $y - 1, $iColFill, $iColArea)
        If $y < $iH - 1 Then FloodFill1($x, $y + 1, $iColFill, $iColArea)
    EndFunc   ;==>FloodFill1
    
    Func FloodFill2($x, $y, $iColFill, $iColArea = 0, $iLast = -1) ; Genau das gleiche wie FloodFill1 nur, dass man nicht mehr dahingehen kann wo man herkommt.
        Local $iColRead = Read($x, $y) ; Tempo    : Bummelbahn
        If $iColArea = 0 Then $iColArea = $iColRead ; Rekursion: Sehr schnell sehr viele Rekursionen
        If $iColArea <> $iColRead Then Return ; Reads    : Weniger als FloodFill1 und FloodFill3
        If $iColFill = $iColRead Then Return
        Write($x, $y, $iColFill)
        If $iLast <> 0 And $x > 0 Then FloodFill2($x - 1, $y, $iColFill, $iColArea, 2)
        If $iLast <> 2 And $x < $iW - 1 Then FloodFill2($x + 1, $y, $iColFill, $iColArea, 0)
        If $iLast <> 3 And $y > 0 Then FloodFill2($x, $y - 1, $iColFill, $iColArea, 1)
        If $iLast <> 1 And $y < $iH - 1 Then FloodFill2($x, $y + 1, $iColFill, $iColArea, 3)
    EndFunc   ;==>FloodFill2
    
    Func FloodFill3($x, $y, $iColFill, $iColArea = 0) ; Spontan ausgedacht. Nachschlagen ergab, dass eine ähnliche Methode Scanline Flood Fill heißt.
        If $iColArea = 0 Then $iColArea = Read($x, $y) ; Tempo    : Mofa mit aufgebohrtem Zylinderkopf und zugepetztem Auspuff.
        Write($x, $y, $iColFill) ; Rekursion: Eine für jede "Linie" in jeder Zeile. Also irgendwas wie die CONST * AREAHEIGHT (sollte nicht so schnell wachsen)
        For $xMax = $x + 1 To $iW - 1 Step 1 ; Reads    : Weniger als FloodFill1 und mehr als FloodFill3
            $iColRead = Read($xMax, $y)
            If $iColRead <> $iColArea Then ExitLoop
            Write($xMax, $y, $iColFill)
        Next
        For $xMin = $x - 1 To 0 Step -1
            $iColRead = Read($xMin, $y)
            If $iColRead <> $iColArea Then ExitLoop
            Write($xMin, $y, $iColFill)
        Next
        If $xMin = -1 Then $xMin = 0
        If $xMax = $iW Then $xMax = $iW - 1
        If $y > 0 Then
            For $i = $xMin To $xMax Step 1
                If Read($i, $y - 1) = $iColArea Then FloodFill3($i, $y - 1, $iColFill, $iColArea)
            Next
        EndIf
        If $y < $iH - 1 Then
            For $i = $xMin To $xMax Step 1
                If Read($i, $y + 1) = $iColArea Then FloodFill3($i, $y + 1, $iColFill, $iColArea)
            Next
        EndIf
    EndFunc   ;==>FloodFill3
    
    Func Info($bPlot = False)
        Local $iReads, $iWrites
        If $bPlot Then ConsoleWrite('##################################### [ Reads | Writes ] ######################################' & @CRLF)
        For $y = 0 To 15 Step 1
            For $x = 0 To 15 Step 1
                $iReads += $aReads[$y][$x]
                $iWrites += $aWrites[$y][$x]
                If $bPlot Then ConsoleWrite('[' & $aReads[$y][$x] & '|' & $aWrites[$y][$x] & '] ')
            Next
            If $bPlot Then ConsoleWrite(@CRLF)
        Next
        ConsoleWrite('Reads:  ' & $iReads & @CRLF)
        ConsoleWrite('Writes: ' & $iWrites & @CRLF)
        If $bPlot Then ConsoleWrite('###############################################################################################' & @CRLF)
    EndFunc   ;==>Info
    
    Func Read($x, $y)
        $aReads[$y][$x] += 1
        Return $aBitmap[$y][$x]
    EndFunc   ;==>Read
    
    Func Write($x, $y, $iCol)
        $aWrites[$y][$x] += 1
        $aBitmap[$y][$x] = $iCol
    EndFunc   ;==>Write
    Alles anzeigen
  • Pixelsearch / alternative für Bilder

    • Andy
    • 24. Juni 2018 um 11:10
    Zitat von vcopsmtl

    und schau mal nach gdi+pixelget" -> wäre auch hilfreich gewesen.

    Zitat von vcopsmtl

    Geb hier mal einen Aktuellen Stand:

    bei mir braucht er für das Bild etwa 1h.

    Weißt du was du bist?

    Diesen Ausdruck zu verwenden verbietet mir meine Kinderstube, fängt aber mit "A" an....

    Hier geht es um Bild(be bzw. ver)arbeitung von Bilddatengrößen von 7000x7000x4 Byte => 196MB und du kommst mit dem LANGSAMSTEN GDI(+) - gedöns wie GetPixel() an. Dabei habe ich schon etliche Male dargestellt, dass dieses Vorgehen, einzelne Pixel per "Grafikbefehl" aus von einem auf einem Bildschirm (bzw Grafikspeicher) dargestellten Bild auszulesen, völliger Nonsens ist.

    Ich bin endgültig raus...

    Nur mal so am Rande, HIER hatte ich etwas ähnliches vorgestellt.

    Zählt die Farben innerhalb eines Bildes und schreibt jede Farbe mit ihrer jeweils vorkommenden Anzahl in eine Datei. Für bspw. ein 3MB großes Bild benötigt das Script gerade mal 40 Millisekunden, für ein 27MB Bild 250ms . Das approximiert auf 196MB ergibt eine Laufzeit von...na, probiert es selber aus...

    Jedenfalls sollte das ganze "Problem" in einigen wenigen SEKUNDEN gelöst sein.

    Wäre es auch längst, wenn der TE mal seinen Arsch hochheben und in diesem Thread ein Beispielscript und die dazugehörige Bilddatei posten würde!

    Stattdessen werden diese Informationen per PN versendet...wtf...:Face:

    //EDIT:

    @vcopsmtl, überleg dir mal in einer ruhigen Minute, was du hier im Forum innerhalb der letzten 11 Tage nach der Erstellung deines Threads erreicht hast.

    Ist das Ergebnis deine Zielvorgabe? Was würdest du als Vorgesetzter eines Mitarbeiters, der sämtliche Vorteile des Internetz und des dort gesammelt vorhandenen KnowHow´s nicht in der Lage ist nur annähernd zu nutzen, machen?

    Loben? Befördern? Weitere 11 Tage abwarten?

    Wenn du erfolgreich Foren nutzen willst, solltest du daran arbeiten, schon im ersten Thread alles an Informationen bereitzustellen, was für eine Lösung deines Problems nötig ist.

    Und nicht das was DU denkst, denn genau DARAN bist du ja gescheitert, ansonsten wärst du nicht hier!

    Lernresistenz wird gnadenlos geahndet...

  • Pixelsearch / alternative für Bilder

    • Andy
    • 16. Juni 2018 um 13:26

    Der Trick ist doch, zu beschreiben was man benötigt, und nicht sich die Würmer aus der Nase ziehen zu lassen und zu jammern, was alles mit dem Schrott den man fabriziert hat NICHT funktioniert. Und dann für diese "falsche " Vorgehensweise auch noch Lösungen abzufragen!

    Diese Posts sind insgesamt wieder mal feinste Beispiele von X-Y-Problemen (siehe Link in meiner Sig)

    Fast alles, was in irgendeiner Art und Weise mit "Pixeln" zu tun hat, wurde hier im Forum (von vielen auch aus Geschwindigkeitsgründen mittels ASM) schon unzählige Male durchgekaut.

    Das ist für die "Cracks" ein einfach zu beackerndes Feld!

    Man sollte sich mal Fragen wie mies ein Startpost sein muss, dass sich diese Leute nicht mit "Lösungen" einklinken...

    Und nach dem 8. Post ist es immer noch nicht besser1

    Ich verweise mal auf einen weiteren Link in meiner Sig, "Wie man Fragen richtig stellt..."

    Lernresistenz wird nicht belohnt!

  • Pixelsearch / alternative für Bilder

    • Andy
    • 16. Juni 2018 um 00:32

    @vcopsmtl

    Du hast immer noch nicht begriffen um was es überhaupt geht...:Face:

    DU BRAUCHST KEINEN BILDSCHIRM!

    Wenn du irgendwelche Daten aus einer Datei auslesen und bearbeiten willst, brauchst du dafür kein BILD! Und schon überhaupt gar keine "Darstellung" auf einem Monitor oder gar in einer GUI.

    Einem Computer ist es völlig schnurz, nach was er in einem Haufen Daten sucht!

    Es ist allein deine beschränkte VORSTELLUNG von einem Bild, und dessen "Bearbeitung"....

    Mal angenommen, deine Datei liegt im 32Bit-BMP-Format vor, dann ist ein Bildpunkt durch die 4 "Farbbytes" ARGB beschrieben. https://de.wikipedia.org/wiki/Windows_Bitmap

    Für "rein schwarz" also die 4 Bytes 0x00000000.

    Wer hindert dich daran, diese Datei als binary zu öffnen, und per AutoIt-StringInstr()-Funktion nach der Position der 4 Bytes chr(0)&chr(0)&chr(0)&chr(0) zu suchen?

    Durch die im Datei-Header enthaltene bekannte Höhe und Breite des "Bildes" ergibt sich über die Position die Zeile und Spalte des Bildpunktes "schwarzes Pixel".

    Um ein "rotes Pixel" 0x00FF0000 zu finden, suchst du dann nach chr(0)&chr(255)&chr(0)&chr(0).....

    Das Laden der Datei und anschließendes Durchsuchen per StringInstr() dauert eine Handvoll Millisekunden incl. Schreiben der Textdatei mit den Koordinaten der "Pixelfarbe"

    Für das TIF(F)-Format gilt selbiges. Das ist kein BILD- sondern eine DATEI-Format!

    Die Umwandlung in eine durchsuchbare Bitmap (was anderes macht keinen Sinn) erfolgt, wie von alpines beschrieben, per _GDIPlus_BitmapCreateFromFile()


    Und überhaupt!

    Wer braucht in einer Textdatei die Koordinaten von schwarzen Bildpunkten?

    Da bekomm ich ja Bauchkrämpfe! Die Koordinaten sind doch bereits im "Bild" enthalten und können von dort direkt weiterverarbeitet werden.:Face:

  • Panoramabild mit GDI+ möglich?

    • Andy
    • 13. Juni 2018 um 19:51

    Mir stellt sich eher die Frage, wieso er nicht direkt ein Script erstellt, welches die Daten von der Website in ein Bild schreibt....ggf. mit Auswahlrahmen.

    Einzelne Screenshots von einer Website zu machen um die dann "von Hand" zusammenzusetzen ist Murks.

    Dafür verschwendet man keine Zeit!

    Die Tabelle auf einen Rutsch in ein Bild zu schreiben ist das Ziel!

    Ich hatte vor Jahren mal was gepostet, da konnte man komplette Webseiten in ein Bild speichern. Es wurde auf der Website so lange runtergescrollt und der "neue" sichtbare Teil an das Bild angehängt, bis man "unten" angekommen war.

    Ich finde mein Script aber nicht mehr^^.

    Macht ja nix, hat man schnell wieder zusammengepuzzled.

  • Pixelsearch / alternative für Bilder

    • Andy
    • 13. Juni 2018 um 19:35

    Hi,

    Zitat von vcopsmtl

    ich versuche ein Bild ( 7k x7k ) welches ich mit bitmapcreatefromfile einlese nach bestimmten Pixeln zu durchsuchen

    Verstehe ich nicht. Du hast schon eine Datei (die heißt deswegen so, weil da DATEN, in deinem Fall die Pixel, drin sind), die lädst du in den Speicher, schiebst sie von dort in den Grafikspeicher, lässt diese Daten auf dem Bildschirm anzeigen, um dann mit einem Datensuchprogramm am BILDSCHIRM nach Übereinstimmungen zu suchen?!

    Zitat von vcopsmtl

    ODER sollte /muss ich anders an die Sache herantreten

    DAS ist die richtige Frage, welche mit JA beantwortet werden muss!

    Wenn du bereits eine Bilddatei hast, dann stell diese uns zur Verfügung und gib an, welche der "Pixel" (ich nehme an du meinst eine Farbe innerhalb der Grafik) du suchst.

    Oscar

    Zitat von Oscar

    Was hast Du denn vor?

    Wette?:D:party:

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™