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. Oscar

Beiträge von Oscar

  • Fehler in der deutschen Hilfe bitte hier melden (Hilfedatei 3.3.14.2 2017.11.12)

    • Oscar
    • 24. November 2017 um 17:15
    Zitat von Bitnugger

    Eine Variable, die als Konstante deklariert wurde, kann nur über einen Const-Parameter an eine Funktion übergeben werden.

    Der Satz ist falsch oder ich verstehe ihn falsch:

    AutoIt
    Global Const $ABC = 'abc'
    _test($ABC)
    
    Func _test($var)
        ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $var = ' & $var & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    EndFunc

    Vor $var muss kein Const stehen.

  • Über Func erzeugtes Gui schliessen ohne Hauptprogramm zu beenden

    • Oscar
    • 23. November 2017 um 19:31

    Nach GuiDelete musst Du noch die Funktion verlassen (mit RETURN).

  • Über Func erzeugtes Gui schliessen ohne Hauptprogramm zu beenden

    • Oscar
    • 23. November 2017 um 17:01

    Ich denke, Dir fehlen noch ein paar Grundlagen. :)

    Eine Funktion verlässt man mit RETURN nicht mit EXIT.

    Da Du innerhalb der Funktion allerdings eine neue GUI erstellst, musst Du diese vor dem verlassen der Funktion wieder löschen: GuiDelete

  • GetUniqueColors

    • Oscar
    • 23. November 2017 um 15:43

    Bei PNGs habe ich auch keinen Unterschied zwischen meiner Funktion und IrfanView festgestellt.

  • GetUniqueColors

    • Oscar
    • 23. November 2017 um 15:19
    Zitat von UEZ

    Ich hatte auch vor einiger Zeit diese Funktion in AutoIt und FreeBasic geschrieben und dabei bemerkt, dass die Anzahl der Farben sich von Programm zu Programm unterscheidet.

    Dein Amsel Bild:


    Unsere GDI+ Versionen: 160514

    IfranView: 148516

    XnView: 160537


    Keine Ahnung, wie man nun weiß, welcher Wert der richtige ist.

    Alles anzeigen

    Das ist mir auch schon aufgefallen. Ich kann mir aber nicht erklären wieso das so ist.

    Vom Prinzip her dürfte die von uns verwendete Array-Methode keine "falschen" Ergebnisse liefern.

    Kann es sein, dass die Laderoutinen von GDI+ und den von IrfanView bzw. XnView die JPEG-Daten anders "interpretieren"?

    Edit: Zum zählen der echten 32 Bit (ARGB): da wirklich 4 GB RAM zu reservieren, finde ich übertrieben. Ich bin in meiner Funktion ja den Weg über PARGB gegangen. So werden die Alphawerte vor dem Bitlock auf die RGB-Werte addiert.

  • _GDIPlus_ImageGetUniqueColors

    • Oscar
    • 23. November 2017 um 08:34

    Nachdem das Thema in "Hilfe & Unterstützung" ausführlich behandelt wurde, und ich (wieder mal) eine tolle Hilfe erfahren durfte, möchte ich das Result auch als kleine UDF präsentieren.

    Man übergibt der Funktion "_GDIPlus_ImageGetUniqueColors" das Handle zu einer GDI+ Bitmap und bekommt die Anzahl der verwendeten Farben zurück.

    Weil das Ganze in purem AutoIt zu lange dauern würde, haben wir (Mars, Andy und ich) das zählen der Farben in eine Assemblerroutine ausgelagert. Diese kleine (40 Byte) Routine befindet sich als Binaercode in der UDF und wird direkt vom Speicher aus aufgerufen.

    Die UDF sowie ein Beispielscript (mit Beispielbild im Binärformat) befindet sich im ZIP-Archiv im Anhang.

    AutoIt
    #AutoIt3Wrapper_UseX64=n                          ; 32Bit-Modus!
    #Region ;************ Includes ************
    #include-once
    #include <GDIPlus.au3>
    #include <Memory.au3>
    #EndRegion ;************ Includes ************
    
    #Region ASM-Code
    #cs _CountUniqueColors                            ;
        Use32                                         ; 32Bit Modus!
        mov esi,dword[esp+4]                          ; Pixelstruct-Pointer holen
        mov ecx,dword[esp+8]                          ; Anzahl der Pixel holen (Pixelcounter)
        mov edi,dword[esp+12]                         ; Colorstruct-Pointer holen
        xor eax,eax                                   ; eax als Farbzaehler (auf null setzen)
        @pixel_count:                                 ; Anfang der Schleife fuer alle Pixel
        mov ebx,[esi]                                 ; Farbwert aus Pixelstruct holen
        and ebx,0xffffff                              ; Alphachannel eliminieren
        cmp byte[edi+ebx],0                           ; Wert aus der Colorstruct = 0?
        jnz @next                                     ; wenn nicht 0, dann wurde die Farbe bereits gezaehlt, weiter -> @next
        inc eax                                       ; den Farbzaehler um eins erhoehen
        mov byte[edi+ebx],1                           ; den Wert in der Colorstruct auf 1 setzen
        @next:
        add esi,4                                     ; den Pixelstruct-Pointer um 4 erhoehen (naechstes DWORD)
        dec ecx                                       ; Pixelcounter um eins verringern
        jnz @pixel_count                              ; wenn Pixelcount nocht nicht 0, dann Schleife wiederholen
        ret                                           ; eax (Farbzaehler) wird zurueckgegeben
    #ce
    #EndRegion ASM-Code
    
    ; $__IGUC_g_bCode entspricht dem obigen ASM-Code im Binaerformat
    Global Const $__IGUC_g_bCode = '0x8B7424048B4C24088B7C240C31C08B1E81E3FFFFFF00803C1F00750540C6041F0183C6044975E7C3'
    ; Die Speichergroesse fuer den ASM-Code berechnen
    Global Const $__IGUC_g_iMemSize = StringLen($__IGUC_g_bCode) / 2 - 1
    ; Achtung! Hier unbedingt virtuellen Speicher mit "_MemVirtualAlloc" anfordern, weil sonst
    ; (bei eingeschalteter Datenausfuehrungsverhinderung = DEP) AutoIt mit einer Fehlermeldung beendet wird.
    Global Const $__IGUC_g_pMem = _MemVirtualAlloc(0, $__IGUC_g_iMemSize, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
    If $__IGUC_g_pMem = 0 Then Exit MsgBox(16, 'Error!', "Can't allocate virtual memory!")
    ; Struktur fuer den ASM-Code im virtuellen Speicher erstellen
    Global $__IGUC_g_tCodeBuffer = DllStructCreate('byte[' & $__IGUC_g_iMemSize & ']', $__IGUC_g_pMem)
    ; den ASM-Code in den Speicher schreiben (wird unten bei DllCallAddress aufgerufen)
    DllStructSetData($__IGUC_g_tCodeBuffer, 1, $__IGUC_g_bCode)
    
    OnAutoItExitRegister('__IGUC_Exit')
    _GDIPlus_Startup()
    
    Func __IGUC_Exit()
        _MemVirtualFree($__IGUC_g_pMem, $__IGUC_g_iMemSize, $MEM_DECOMMIT)
        $__IGUC_g_tCodeBuffer = 0
        _GDIPlus_Shutdown()
    EndFunc   ;==>__IGUC_Exit
    
    Func _GDIPlus_ImageGetUniqueColors(ByRef $hImage)
        Local $aDim, $tBitmapData, $tPixel, $pPixel, $tColors, $pColors, $aRet, $iError = 0
        $aDim =  _GDIPlus_ImageGetDimension($hImage)
        $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $aDim[0], $aDim[1], $GDIP_ILMREAD, $GDIP_PXF32PARGB)
        If @error Then Return SetError(@error, 0, -1)
        $tPixel = DllStructCreate('dword[' & $tBitmapData.Width * $tBitmapData.Height & '];', $tBitmapData.Scan0) ; Pixelstruct (dword = 32 Bit pro Pixel)
        If @error Then Return SetError(10 + @error, 0, -1)
        $pPixel = DllStructGetPtr($tPixel)
        $tColors = DllStructCreate('byte[' & 0xffffff + 1 & '];') ; Colorstruct (1 Byte pro Farbwert)
        If @error Then Return SetError(20 + @error, 0, -1)
        $pColors = DllStructGetPtr($tColors)
        $aRet = DllCallAddress('uint:cdecl', DllStructGetPtr($__IGUC_g_tCodeBuffer), 'ptr', $pPixel, 'dword', $tBitmapData.Width * $tBitmapData.Height, 'ptr', $pColors)
        $iError = 30 + @error
        _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
        $tColors = 0
        $tPixel = 0
        $tBitmapData = 0
        Return SetError($iError, 0, (IsArray($aRet) ? $aRet[0] : -1))
    EndFunc   ;==>_GDIPlus_ImageGetUniqueColors
    Alles anzeigen

    Dateien

    _GDIPlus_ImageGetUniqueColors.zip 580,21 kB – 273 Downloads
  • GetUniqueColors

    • Oscar
    • 23. November 2017 um 06:33

    Erstmal Danke für Deine "Bewertung"!

    Ich bin ja schon froh, dass ich da nicht grobe Schnitzer eingebaut habe. Von Mars habe ich mir jetzt auch noch die kürzere Variante abgeguckt. Eigentlich lagen wir ja schon dicht zusammen.

    Und so wie die Funktion jetzt arbeitet, reicht mir das völlig. Für ein 4k-Bild (3840x2160 px) braucht die Funktion ca. 85ms. Der reine ASM-Teil liegt bei 20ms. Ich denke, da hat es wenig Sinn weiter am ASM-Teil zu feilen.

    Die ganz großen Bilder (direkt von der Kamera) liegen mit ca. 185ms auch völlig im grünen Bereich. Und das mit nur 40 Bytes Assemblercode. :)

    Den Debugger habe ich auch benutzt und finde ihn sehr hilfreich. Man kann schnell mal nachsehen, ob in den Registern die vorgesehen Werte stehen. Top! :klatschen:

    Ich denke, solche Inner-Loops werde ich jetzt öfter in Assembler schreiben. :)

    Edit: Muss man sich eigentlich um das "Retten" der Registerinhalte selbst kümmern? Also bei Aufruf des ASM-Codes alle Register auf den Stack und am Ende wiederherstellen? Oder macht DllCallAddress das automatisch?

    Ich habe das "Retten" bisher nicht gemacht und es klappte alles, aber ich weiß nicht, ob das nicht auf Dauer zum Absturz führen kann.

  • UUID auslesen mit Autoit

    • Oscar
    • 21. November 2017 um 18:01

    Du musst die Rückgabe der Funktion speichern/anzeigen:

    AutoIt
    Global $UUID = UUID()
    MsgBox(0, 'UUID', $UUID)
    
    Func UUID()
        Local $oWMI = ObjGet("winmgmts:\\.\root\CIMV2")
        For $x In $oWMI.ExecQuery("SELECT UUID FROM Win32_computersystemproduct", "WQL", 0x30)
            Return $x.UUID
        Next
    EndFunc   ;==>UUID
  • Text in ein Fenster einfügen mit $WM_SETTEXT nicht möglich?

    • Oscar
    • 21. November 2017 um 15:17

    Übrigens: Wenn es Dir nur um das einfügen in Word geht, bietet Word bereits eine Funktion zum unformatierten Einfügen: [ctrl] & [alt] & [v].

    Bei Softmaker FreeOffice ist es: [ctrl] & [shift] & [v]

  • Text in ein Fenster einfügen mit $WM_SETTEXT nicht möglich?

    • Oscar
    • 21. November 2017 um 14:53

    Ich hätte noch eine andere Idee.

    Man registriert einen eigenen Clipboard-Viewer (Beispiel aus der Hilfe zu "_ClipBoard_SetViewer").

    Dort dann bei "_ClipBoard_GetData" $CF_UNICODETEXT eintragen und zurück in die Zwischenablage. Fertig!

    Und so nebenbei bleibt man bei den gewohnten [ctrl] & [c] bzw, [ctrl] & [v]:

    AutoIt
    #include <Clipboard.au3>
    #include <GUIConstantsEx.au3>
    #include <SendMessage.au3>
    #include <WindowsConstants.au3>
    
    Global $g_idMemo, $g_hNext = 0
    
    Example()
    
    Func Example()
        Local $hGUI
    
        ; Create GUI
        $hGUI = GUICreate("Clipboard", 600, 400)
        $g_idMemo = GUICtrlCreateEdit("", 2, 2, 596, 396, $WS_VSCROLL)
        GUICtrlSetFont($g_idMemo, 9, 400, 0, "Courier New")
        GUISetState(@SW_SHOW)
    
        ; Initialize clipboard viewer
        $g_hNext = _ClipBoard_SetViewer($hGUI)
    
        GUIRegisterMsg($WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN")
        GUIRegisterMsg($WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD")
    
        MemoWrite("GUI handle ....: " & $hGUI)
        MemoWrite("Viewer handle .: " & _ClipBoard_GetViewer())
    
        ; Loop until the user exits.
        Do
        Until GUIGetMsg() = $GUI_EVENT_CLOSE
    
        ; Shut down clipboard viewer
        _ClipBoard_ChangeChain($hGUI, $g_hNext)
    EndFunc   ;==>Example
    
    ; Write message to memo
    Func MemoWrite($sMessage = "")
        GUICtrlSetData($g_idMemo, $sMessage & @CRLF, 1)
    EndFunc   ;==>MemoWrite
    
    ; Handle $WM_CHANGECBCHAIN messages
    Func WM_CHANGECBCHAIN($hWnd, $iMsg, $wParam, $lParam)
        #forceref $hWnd, $iMsg
        ; Show that message was received
        MemoWrite("***** $WM_CHANGECBCHAIN *****")
    
        ; If the next window is closing, repair the chain
        If $wParam = $g_hNext Then
            $g_hNext = $lParam
            ; Otherwise pass the message to the next viewer
        ElseIf $g_hNext <> 0 Then
            _SendMessage($g_hNext, $WM_CHANGECBCHAIN, $wParam, $lParam, 0, "hwnd", "hwnd")
        EndIf
    EndFunc   ;==>WM_CHANGECBCHAIN
    
    ; Handle $WM_DRAWCLIPBOARD messages
    Func WM_DRAWCLIPBOARD($hWnd, $iMsg, $wParam, $lParam)
        #forceref $hWnd, $iMsg
        ; Display any text on clipboard
        Local $sClip = _ClipBoard_GetData($CF_UNICODETEXT) ; <- Zwischenablage hier als Text auslesen
        _ClipBoard_SetData($sClip) ; <- und hier wieder in die Zwischenablage zurueckschreiben
        MemoWrite($sClip)
    
        ; Pass the message to the next viewer
        If $g_hNext <> 0 Then _SendMessage($g_hNext, $WM_DRAWCLIPBOARD, $wParam, $lParam)
    EndFunc   ;==>WM_DRAWCLIPBOARD
    Alles anzeigen
  • _ScreenCapture_Capture() bei mehreren Bildschirmen

    • Oscar
    • 20. November 2017 um 13:48

    Warum umständlich die Koordinaten auslesen?

    Benutze einfach "_ScreenCapture_CaptureWnd":

    AutoIt
    #include <ScreenCapture.au3>
    
    $hGUI = WinWaitActive("[CLASS:screenClass]", "", 20)
    
    _ScreenCapture_CaptureWnd(@MyDocumentsDir & "\GDIPlus_Image.jpg", $hGUI)
    
    ShellExecute(@MyDocumentsDir & "\GDIPlus_Image.jpg")
  • GetUniqueColors

    • Oscar
    • 20. November 2017 um 08:08

    Andy: Vielen Dank für Dein Beispiel!

    Mit der Hilfe habe ich mal mein erstes ASM-Programm erstellt und es funktioniert sogar. :)

    Bei den kleinen Bildern ist es nicht viel schneller als die mit TCC erstellte DLL in C, aber bei dem großen Bild (4608 x 3456 px) ist es dann doch noch etwas schneller (185ms).

    Wobei ich dazusagen muss, dass mir die 200ms bei der DLL schon ausreichen würden. Im Gegensatz zu den fast 29 Sekunden beim puren AutoIt ist das schon eine andere Liga.

    Außerdem sollte ich noch erwähnen, dass der größte Teil von den 200 bzw. 185 ms für das "_GDIPlus_BitmapLockBits" unter AutoIt draufgehen (ca. 141 ms).

    Aber vielleicht magst Du ja mal über mein ASM-Programm schauen und mir evtl. Verbesserungsvorschläge aufschreiben:

    AutoIt
    #AutoIt3Wrapper_UseX64=n                  ;32Bit-Modus
    #include <GDIPlus.au3>
    #include <Memory.au3>
    ;~ #include "assembleit2_64.au3"
    
    #cs _countpixelcolors                             ;
        Use32                                         ;32Bit!
        mov esi,dword[esp+4]                          ;pointer Pixelstruct
        mov ecx,dword[esp+8]                          ;width bitmap
        mov ebx,dword[esp+12]                         ;height bitmap
        mov edi,dword[esp+16]                         ;pointer Colorstruct
        mov eax,ebx                                   ;h
        mul ecx                                       ;w*h
        mov edx,eax                                   ;edx = Pixelcounter (w*h)
        xor ecx,ecx                                   ;ecx jetzt als Farbzaehler (auf null setzen)
        ; Schleife ANFANG fuer alle Pixel
        @pixel_count:                                 ;alle pixel
        mov eax,[esi]                                 ;Farbwert aus Pixelstruct holen
        and eax,0xffffff                              ;Alphachannel eliminieren
        movsx bx,byte[edi+eax]                        ;den Wert aus der Colorstruct holen
        cmp ebx,0                                     ;mit 0 vergleichen
        jnz @next                                     ;wenn nicht 0, dann wurde die Farbe bereits gezaehlt weiter -> @next
        inc ecx                                       ;den Farbzaehler um eins erhoehen
        mov byte[edi+eax],1                           ;den Wert in der Colorstruct auf 1 setzen
        @next:
        add esi,4                                     ;den Pixelstruct-Pointer um 4 erhoehen (naechstes DWORD)
        dec edx                                       ;Pixelcounter um eins verringern
        jnz near @pixel_count                         ;jump if not zero
        ; Schleife ENDE
        mov eax,ecx
        ret
    #ce
    
    ;~ $binarycode = _AssembleIt2("retbinary", "_countpixelcolors") ;gibt nur den assemblierten code zurück
    ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $binarycode = ' & ($binarycode) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;~ Exit
    Global $g_pMem, $g_iMemSize, $bCode, $tCodeBuffer, $hImage, $iW, $iH, $iTimer, $tBitmapData, $pScan0, $tPixel, $pPixel, $tColors, $pColors, $ret
    $bCode = "0x8B7424048B4C24088B5C240C8B7C241089D8F7E189C231C98B0625FFFFFF00660FBE1C0783FB00750541C604070183C6044A0F85E0FFFFFF89C8C3"
    $tCodeBuffer = _dllstructcreate64_("byte[" & StringLen($bCode) / 2 - 1 & "]") ;reserve Memory for opcodes
    DllStructSetData($tCodeBuffer, 1, $bCode)
    
    _GDIPlus_Startup()
    
    $hImage = _GDIPlus_BitmapCreateFromFile(@ScriptDir & '\test_g.jpg')
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    ConsoleWrite(StringFormat('_GetUniqueColors (ASM)\n%d x %d = %s px\n', $iW, $iH, $iW * $iH))
    $iTimer = TimerInit()
    $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32PARGB)
    $pScan0 = $tBitmapData.Scan0
    ConsoleWrite('Zeit (BitmapLockBits): ' & Round(TimerDiff($iTimer), 2) & ' ms' & @CR)
    $tPixel = DllStructCreate('dword[' & $iW * $iH & '];', $pScan0) ; Pixelstruct (dword = 32 Bit pro Pixel)
    $pPixel = DllStructGetPtr($tPixel)
    ConsoleWrite('Zeit (Pixelstruct): ' & Round(TimerDiff($iTimer), 2) & ' ms' & @CR)
    $tColors = DllStructCreate('byte[' & 0xffffff + 1 & '];') ; Colorstruct
    $pColors = DllStructGetPtr($tColors)
    ConsoleWrite('Zeit (Colorstruct): ' & Round(TimerDiff($iTimer), 2) & ' ms' & @CR)
    $ret = DllCallAddress("uint:cdecl", DllStructGetPtr($tCodeBuffer), "ptr", $pPixel, "dword", $iW, "dword", $iH, "ptr", $pColors)
    $ret = $ret[0]
    ;~ $ret = _AssembleIt2("dword", "_countpixelcolors", "ptr", $pPixel, "dword", $iW, "dword", $iH, "ptr", $pColors)
    ConsoleWrite('Anzahl der Farben = ' & $ret & @CR)
    ConsoleWrite('Zeit: ' & Round(TimerDiff($iTimer), 2) & ' ms' & @CR)
    
    _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
    $tPixel = 0
    $tColors = 0
    $tBitmapData = 0
    _GDIPlus_BitmapDispose($hImage)
    _GDIPlus_Shutdown()
    _MemVirtualFree($g_pMem, $g_iMemSize, $MEM_DECOMMIT)
    Exit
    
    Func _dllstructcreate64_($struct) ;align auf 16-byte adresse
        Local $temp = DllStructCreate($struct)
        $g_iMemSize = DllStructGetSize($temp) + 64
        Local $ptr = DllStructGetPtr($struct)
        Local $a1 = Mod(Number($ptr), 64)
        Local $temp = 0
        $g_pMem = _MemVirtualAlloc($ptr + $a1, $g_iMemSize, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
        Local $a2 = Mod(Number($g_pMem), 64) ;rest div 16 adresse = offset
        $sstruct = DllStructCreate($struct, (Number($g_pMem) - $a2 + 64))
        Return $sstruct ;auf 16 alingned pointer
    EndFunc   ;==>_dllstructcreate64
    Alles anzeigen

    Auf jeden Fall schonmal ein großes DANKESCHÖN für "assembleit2_64.au3"! :thumbup::klatschen:

  • Falsche If Abfrage

    • Oscar
    • 19. November 2017 um 14:24

    Wer's glaubt...

    Lies nochmal unsere Forenregeln! Hier gibt es keine Bot-Unterstützung. [Thread closed]

  • Berechnung von mehreren Einträgen

    • Oscar
    • 19. November 2017 um 07:49

    [verschoben nach: "Andere Programmiersprachen"]

  • GetUniqueColors

    • Oscar
    • 17. November 2017 um 05:00

    Ah, gute Optimierungsmöglichkeiten! :thumbup:

    Das sieht in C jetzt so aus:

    C
    #include <stdbool.h>
    #include <stdlib.h>
    
    __declspec(dllexport) unsigned int CountUniqueColors(unsigned int* pixel, unsigned int len) {
        unsigned int i, iColor, colorSum = 0;
        bool* colors = calloc(0xffffff + 1, sizeof(bool));
        for(i = 0; i < len; i++) {
            if (colors[pixel[i] & 0xffffff] == 0){
                colorSum++;
                colors[pixel[i] & 0xffffff] = 1;
            }
        }
        free(colors);
        return colorSum;
    }
    Alles anzeigen

    Und schon reduziert sich die Zeit für das große Bild von 275 ms auf 200 ms. Danke für die Verbesserungsvorschläge! :klatschen:

    Die neue DLL befindet sich im Anhang.

    Dateien

    cuc.zip 601 Byte – 524 Downloads
  • GetUniqueColors

    • Oscar
    • 17. November 2017 um 02:37

    Na gut, nach dem scheitern von AutoIt (pur), gehen wir zu einer DLL in C über. :)

    Nachdem Chesstiger eine Vorlage gegeben hat, wollte ich auch mal ein bißchen mit C rumspielen.

    Rausgekommen ist das:

    C
    #include <stdbool.h>
    #include <stdlib.h>
    #define AUTOIT_CC __declspec(dllexport)
    
    AUTOIT_CC unsigned int CountUniqueColors(unsigned int* pixel, unsigned int len) {
        unsigned int i, iColor, colorSum = 0;
        bool* colors = calloc(0xffffff + 1, sizeof(bool));
        if (colors == NULL) return 0;
        for(i = 0; i < len; i++) {
            colors[pixel[i] & 0xffffff] = 1;
        }
        for(i = 0; i < (0xffffff + 1); i++) colorSum += colors[i];
        free(colors);
        return colorSum;
    }
    Alles anzeigen

    Compiliert mit dem Tiny C Compiler (TCC) entsteht eine nur 2kB kleine DLL.

    Ich habe mal das AutoIt-Script, die DLL und ein Testbild in das ZIP-Archiv im Anhang gepackt.

    In C ist das Ganze wahnsinnig schnell (bei mir 34 und 49 ms). Selbst mit einem großen Testbild (4608 x 3456 Pixel) dauert es nur 275 ms.

    Dateien

    GetUniqueColors.zip 360,96 kB – 572 Downloads
  • GetUniqueColors

    • Oscar
    • 15. November 2017 um 19:17

    Ich habe mal die IsDeclared/Assign-Variante von UEZ noch etwas abgeändert, um noch etwas Geschwindigkeit rauszuholen und auch die Array-Variante von alpines habe ich noch etwas geändert.

    Meine Ursprungsversion mit dem Dictionary habe ich ebenfalls noch etwas verbessert. Mit diesen drei Versionen habe ich Tests mit 3 unterschiedlich großen (klein/mittel/groß) Bildern durchgeführt.

    Ich darf schonmal vorwegnehmen, dass die Array-Variante am schnellsten war. Auch die IsDeclared/Assign-Version hat sich noch ganz gut geschlagen und landete auf Platz 2.

    Die Dictionary-Version ist nicht zu empfehlen. Mit zunehmender Bildgröße benötigt sie immer mehr Zeit (beim großen Bild fast 9 Minuten).

    Das Einzige, was man ihr zugute halten kann, ist, dass sie am wenigsten Speicher benötigte. Das Testscript mit den drei Versionen findet ihr im Anhang.

    Hier die Ergebnisse im einzelnen (Bild klein/mittel/groß):

    Code
    Platz 1: _GetUniqueColors1 (Array)
    1043 x 679 = 708.197 px
    MemoryInfo: 91.049.984 bytes
    Zeit: 1.337 ms
    Anzahl der Farben: 99.394
    
    Platz 2: _GetUniqueColors2 (IsDeclared + Assign)
    1043 x 679 = 708.197 px
    MemoryInfo: 31.793.152 bytes
    Zeit: 1.951 ms
    Anzahl der Farben: 99.394
    
    Platz 3: _GetUniqueColors3 (Dictionary)
    1043 x 679 = 708.197 px
    MemoryInfo: 31.531.008 bytes
    Zeit: 5.180 ms
    Anzahl der Farben: 99.394
    Alles anzeigen
    Code
    Platz 1: _GetUniqueColors1 (Array)
    1600 x 959 = 1.534.400 px
    MemoryInfo: 96.198.656 bytes
    Zeit: 2.893 ms
    Anzahl der Farben: 152.514
    
    Platz 2: _GetUniqueColors2 (IsDeclared + Assign)
    1600 x 959 = 1.534.400 px
    MemoryInfo: 41.201.664 bytes
    Zeit: 4.557 ms
    Anzahl der Farben: 152.514
    
    Platz 3: _GetUniqueColors3 (Dictionary)
    1600 x 959 = 1.534.400 px
    MemoryInfo: 40.738.816 bytes
    Zeit: 18.482 ms
    Anzahl der Farben: 152.514
    Alles anzeigen
    Code
    Platz 1: _GetUniqueColors1 (Array)
    4608 x 3456 = 15.925.248 px
    MemoryInfo: 170.242.048 bytes
    Zeit: 28.686 ms
    Anzahl der Farben: 375.002
    
    Platz 2: _GetUniqueColors2 (IsDeclared + Assign)
    4608 x 3456 = 15.925.248 px
    MemoryInfo: 133.152.768 bytes
    Zeit: 46.144 ms
    Anzahl der Farben: 375.002
    
    Platz 3: _GetUniqueColors3 (Dictionary)
    4608 x 3456 = 15.925.248 px
    MemoryInfo: 130.936.832 bytes
    Zeit: 531.367 ms
    Anzahl der Farben: 375.002
    Alles anzeigen

    Insgesamt muss man wohl sagen, das AutoIt mit dieser Aufgabe überfordert ist.

    Eine Schleife, die über 15 Mio mal durchlaufen werden muss, ist für eine Interpretersprache wohl zu viel.

    Jedenfalls sind die fast 29 Sekunden (für das große Bild) der schnellsten Version immer noch zu langsam.

    Dateien

    _GetUniqueColors.au3 3,87 kB – 504 Downloads
  • Case $GUI_EVENT_DROPPED gibt es analog auch etwas wie case event writen ?

    • Oscar
    • 15. November 2017 um 14:37
    Zitat von Peter S. Taler

    Da ich keine Methode kenne den Status der Gui Boxen als Case zu bearbeiten.

    Du registrierst WM_COMMAND mit: GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") und kannst dann alle Änderungen an den Input-Controls mitverfolgen.

    In der Hilfe zum Befehl _GUICtrlEdit_Create findest Du ein passendes Beispielscript.

  • GetUniqueColors

    • Oscar
    • 14. November 2017 um 18:59

    Ohne Hex ergibt bei mir 0 Colors. Scheinbar mag das Scripting.Dictionary keine Zahlen als Item.

    alpines: Die Array-Variante ist zumindest schonmal schneller. Um Fehler bei Alphawerten auszuschließen sollte man aber BitAnd benutzen:

    AutoIt
    Func _GetUniqueColors2(ByRef $hImage)
        Local $iColorCounter = 0, $aColor[0xFFFFFF + 1]
        Local $iW, $iH, $tBitmapData, $pScan0, $tPixel, $iOffset, $iColor
        $iW = _GDIPlus_ImageGetWidth($hImage)
        $iH = _GDIPlus_ImageGetHeight($hImage)
        $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
        $pScan0 = DllStructGetData($tBitmapData, 'Scan0')
        $tPixel = DllStructCreate('uint[' & $iW * $iH & '];', $pScan0)
        ConsoleWrite('$iW * $iH = ' & $iW * $iH & ' px' & @CRLF)
        For $iY = 0 To $iH - 1
            $iOffset = $iY * $iW + 1
            For $iX = 0 To $iW - 1
                $iColor = BitAND(DllStructGetData($tPixel, 1, $iOffset + $iX), 0xFFFFFF)
                $aColor[$iColor] += 1
                If $aColor[$iColor] = 1 Then $iColorCounter += 1
            Next
        Next
        _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
        $tPixel = 0
        Return $iColorCounter
    EndFunc   ;==>_GetUniqueColors
    Alles anzeigen

    Aber letztendlich ist auch das zu langsam. Wenn ich den Test mit einem 4608 x 3456 Pixel Bild (aus meiner Kamera) mache, dann dauert das fast 34 sekunden.

  • GetUniqueColors

    • Oscar
    • 14. November 2017 um 17:33

    Ich möchte gern ermitteln, wie viele verschiedene Farben in einem Bild verwendet werden.

    Dazu habe ich mir eine Funktion geschrieben, die alle Pixel durchgeht und in einem Dictionary die Farben speichert.

    Das funktioniert auch recht gut, aber das dauert zu lange. Seht ihr vielleicht noch eine Möglichkeit, das schneller hinzukriegen?

    AutoIt
    #include <GDIPlus.au3>
    
    Global $sImagefile = @ScriptDir & '\test.jpg'
    
    _GDIPlus_Startup()
    Global $hImage = _GDIPlus_BitmapCreateFromFile($sImagefile)
    $iTimer = TimerInit()
    $iCount = _GetUniqueColors($hImage)
    ConsoleWrite('Zeit: ' & Int(TimerDiff($iTimer)) & ' ms' & @CR)
    ConsoleWrite('Anzahl der Farben: ' & $iCount & @CR)
    _GDIPlus_BitmapDispose($hImage)
    _GDIPlus_Shutdown()
    Exit
    
    Func _GetUniqueColors(ByRef $hImage)
        Local $iW, $iH, $tBitmapData, $pScan0, $tPixel, $iOffset, $iColor, $oUnique = ObjCreate('Scripting.Dictionary')
        $iW = _GDIPlus_ImageGetWidth($hImage)
        $iH = _GDIPlus_ImageGetHeight($hImage)
        $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
        $pScan0 = DllStructGetData($tBitmapData, 'Scan0')
        $tPixel = DllStructCreate('uint[' & $iW * $iH & '];', $pScan0)
        ConsoleWrite('$iW * $iH = ' & $iW * $iH & ' px' & @CRLF)
        For $iY = 0 To $iH - 1
            $iOffset = $iY * $iW + 1
            For $iX = 0 To $iW - 1
                $iColor = Hex(DllStructGetData($tPixel, 1, $iOffset + $iX), 8)
                $oUnique.Item($iColor) = 0
            Next
        Next
        _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
        $tPixel = 0
        Return $oUnique.Count
    EndFunc
    Alles anzeigen

    Als Ergebnis bekomme ich:

    Code
    $iW * $iH = 708197 px
    Zeit: 4717 ms
    Anzahl der Farben: 99394

    Fast 5 Sekunden für so ein kleines Bild dauert mir zu lange.

    Dateien

    _GetUniqueColors.au3 1,2 kB – 513 Downloads test.jpg 171,24 kB – 0 Downloads

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™