Bildscan

  • Guten Tag liebes Forum
    Ich habe vor einigen Jahren (2013 *hust*) n thema erstellt, welches durchaus für einige interessant war. (falls dies thema verlinkt werden sollte, oder doch lieber der grabstein bleiben soll, wird sich wohl zeigen)
    Nun ging dies etwas verloren und aus irgendwelchen gründen, kahm mir das thema wieder auf und habe mich promt 3std hingesetzt.
    Nun, es wahren nur 3std, debbuging ist noch <X und optimierungen gibts wohl einige! ist auch schon einige zeit zurück mit autoIT :P

    Das grundgerüst hätte ich soweit, jedoch, lief ich bei der letzten version, auf ein
    "Error allocating memory"
    gehe ich davon richtig aus, das dies an autoIT selbst liegt / limitiert ist was dass verwenden des zwischenspeichers angeht?
    in diesem falle, wie könnt ich dies umgehen?
    Ich danke auch für berichtigung, bei irrtümlichkeiten.

    das script macht nichts anderes, als jedes einzelne pixel eines bildes als wert zurück gibt, habe dabei absichtlich die bitmap von GDI+ verwendet (dunkle umgehen :/), auch keine direkte beschreibung der code lines!

    Script

    #cs ----------------------------------------------------------------------------

    AutoIt Version: 3.3.14.5
    Author: Skilkor

    Script Function:
    scan & save color-grid of imported image

    #ce ----------------------------------------------------------------------------

    #Region ### #include ###
    #include <EditConstants.au3>
    #include <ButtonConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <GuiEdit.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>
    #include <FileConstants.au3>
    #include <MsgBoxConstants.au3>
    #include <ProgressConstants.au3>
    #include <GDIPlus.au3>
    #EndRegion ### #include ###

    #Region ### Global ###
    Global $hGuiTitel = 'Image Scan'
    Global $data
    Global $Pic_ODia = FileOpenDialog('Pic', @ScriptDir & '\', 'Images (*.BMP;*.JPG)', 2)
    #EndRegion ### Global ###

    #Region ### hGui ###
    $hGui = GUICreate($hGuiTitel, 720, 450, -1, -1)
    $imp_b = GUICtrlCreateButton('import...', 10, 10, 50, 25)
    $scan_b = GUICtrlCreateButton('Scan...', 10, 40, 50, 25)
    $Pic_Show = GUICtrlCreatePic('', 80, 10, 380, 140)
    $data_Field = GUICtrlCreateEdit('Startup: Init import' & @CRLF, 10, 160, 700, 210, BitOR($ES_WANTRETURN, $ES_MULTILINE, $ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $WS_VSCROLL), -1)
    _GUICtrlEdit_SetLimitText($data_Field, 0)
    $Prog_Main = GUICtrlCreateProgress(10, 380, 700, 25, $PBS_SMOOTH)
    $Prog_Sub = GUICtrlCreateProgress(10, 415, 700, 25, $PBS_SMOOTH)

    GUISetState(@SW_SHOW)
    #EndRegion ### hGui ###
    _import()
    #Region ### While 1 ###
    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    Case $imp_b
    _import()
    Case $scan_b
    _scan_init()

    EndSwitch
    WEnd
    #EndRegion ### While 1 ###

    #Region ### Fun _import() ###
    Func _import()

    If @error Then
    _Data_Field('ERROR: No file(s) were selected.')
    Else
    GUICtrlSetImage($Pic_Show, $Pic_ODia)
    _Data_Field('Imported: ' & $Pic_ODia)
    EndIf
    Return
    EndFunc ;==>_import
    #EndRegion ### Fun _import() ###

    #Region ### Scan_init ###
    Func _scan_init()
    _Data_Field('Scan: Startup')
    _GDIPlus_Startup()
    _Data_Field('Scan: GDI+ Startup')
    $hImage = _GDIPlus_ImageLoadFromFile($Pic_ODia)
    _Data_Field('Scan: GDI+ Load Image - ' & $hImage)
    $width = _GDIPlus_ImageGetWidth($hImage) ;x
    _Data_Field('Scan: GDI+ width = ' & $width)
    $height = _GDIPlus_ImageGetHeight($hImage) ;y
    _Data_Field('Scan: GDI+ height = ' & $height)
    _scan($width, $height, $hImage)
    EndFunc ;==>_scan_init
    #EndRegion ### Scan_init ###

    #Region ### Scan ###
    Func _scan($x, $y, $hImage)

    For $a = 0 To $y
    GUICtrlSetData($Prog_Main, (100 / $y * $a))

    For $i = 0 To $x
    $PGC_w = _GDIPlus_BitmapGetPixel($hImage, $i, $a)

    _Data_Field('Scan: @Grid: x: ' & $i & ' | y: ' & $a & ' | Pixel Color: ' & $PGC_w)
    _save($PGC_w & ' - ')
    GUICtrlSetData($Prog_Sub, (100 / $x * $i))
    Next
    Next

    $size = $y & 'x' & $x

    _GDIPlus_Shutdown()
    _Data_Field('Scan: GDI+ Shutdown')
    EndFunc ;==>_scan
    #EndRegion ### Scan ###

    #Region ### Func _Data_Field ###
    Func _Data_Field($data)

    GUICtrlSetData($data_Field, $data & @CRLF, 1)
    EndFunc ;==>_Data_Field
    #EndRegion ### Func _Data_Field ###

    #Region ### save ###
    Func _save($Tdata)
    Local $sFile = @ScriptDir & '\Save.txt'
    FileOpen($sFile, $FO_APPEND)
    FileWrite($sFile,$Tdata)
    FileClose($sFile)
    EndFunc ;==>_save
    #EndRegion ### save ###

    Ich hoffe es ist doch nicht zu unübersichtlich, hab mitlerweillen wohl eine "komische" aufbau weisse oä ^^

    Greez

  • Hi,

    ich verstehe zwar, was dein Script macht, aber der Sinn wird mir nicht klar.

    Es wird aus einem Bild die x- und y-Koordinate ausgelesen und mit der Farbe als Textdatei abgespeichert. Pro Pixel also ca. 50 Bytes. Mithin also ungefähr 50 mal größer wie das ursprüngliche Bild.

    In dem Bild ( ! ) kann ich ich übrigens per StringInstr() in Millisekundenbruchteilen eine bestimmte Farbe an deren Koordinaten finden wenn ich das will.

    Eine als "Bild" gespeicherte Datei ist sowieso schon das kleinstmögliche (Pixel-)Array, auf das ich zugreifen kann.

    Dieses "Array" auf die 50-fache Größe aufzupumpen um exakt dieselben Daten "anzuzeigen" braucht doch keiner?!

    Wer liest eine hunderte MB große Datei? Selbst wenn dort relevante Daten drin sein sollten sind die exakt so auch im "Bild" enthalten und dort viel schneller zu extrahieren.....

  • Hallo Andy
    Ich stimme dir zur.
    Zugegeben, die umsetzung ist, rudimentär schlecht *hust*, der sinn dahinter ist eine idee zur bilddaten speicherung, welche man weiter verwerten kann.
    Das script bis dato, ist effektiv nichts anderes als ein ,anfang... und weit vom ende entfernt.

    Die ausgegebene datengrösse, die erwähnt wurde, ist für mich secundär, da ich ersteinmal wissen möchte, wie, was, jedweige optimierungen währen nach und nach angegangen worden.
    Nun eben mein problem, wie halt ich den zwischenspeicher sauber, wenn ich es sowieso direkt in eine datei schreibe?

    und mir ist aufgefallen, dass ich die eigenschaft habe, nicht zu kontrollieren in welchem abteil es im forum landet....gnarv.

    Einmal editiert, zuletzt von Skilkor (28. März 2018 um 22:17)

    • Offizieller Beitrag

    Hallo,

    der Fehler liegt in der Funktion _save, wenn man eine Datei mit FileOpen öffnet sollte man alle weiteren Dateioperationen mit dem Filehandle durchführen der von FileOpen zurückgegeben wird. Besonders die Funktion FileClose, den diese funktioniert nur mit dem Filehandle und kann nicht mit Dateinamen aufgerufen werden.

    Richtig wäre deine Funktion so:

    Spoiler anzeigen
    AutoIt
    #Region ### save ###
    Func _save($Tdata)
        Local $sFile = @ScriptDir & "\Save.txt"
        $hFile = FileOpen($sFile, $FO_APPEND)
        FileWrite($hFile, $Tdata)
        FileClose($hFile)
    EndFunc   
    #EndRegion ### save ###

    Da aber $FO_APPEND der Standardmodus ist ginge auch folgendes:

    Spoiler anzeigen
    AutoIt
    #Region ### save ###
    Func _save($Tdata)
        Local $sFile = @ScriptDir & "\Save.txt"
        FileWrite($sFile, $Tdata)
    EndFunc   ;==>_save
    #EndRegion ### save ###

    Bei dir wrd die Datei immer wieder geöffnet aber nie geschlossen und FileWrite schreibt direkt in die Datei.

    Nun solltest du nur folgendes bedenken, du führst bei jeden Pixel eine Schreiboperation auf die Festplatte aus. Bei einem Bild mit 4K Auflösung sind das dann ca. 9.000.000 Schreiboperationen. Wer also mal ein Testprogramm braucht, das testet ob eine SSD wirklich totgeschrieben werden kann, hier ist eins.

    Ich habe dein Programm mal etwas geändert, jetzt wird nur noch einmal pro Datei geschrieben und die Ausgabe in die EditBox geschieht nur noch einmal je Pixelzeile. Dadurch wird dein Programm extrem beschleunigt.

    Spoiler anzeigen
  • Hallo,

    der Fehler liegt in der Funktion _save, wenn man eine Datei mit FileOpen öffnet sollte man alle weiteren Dateioperationen mit dem Filehandle durchführen der von FileOpen zurückgegeben wird. Besonders die Funktion FileClose, den diese funktioniert nur mit dem Filehandle und kann nicht mit Dateinamen aufgerufen werden.

    Richtig wäre deine Funktion so:

    Spoiler anzeigen
    AutoIt
    #Region ### save ###
    Func _save($Tdata)
        Local $sFile = @ScriptDir & "\Save.txt"
        $hFile = FileOpen($sFile, $FO_APPEND)
        FileWrite($hFile, $Tdata)
        FileClose($hFile)
    EndFunc   
    #EndRegion ### save ###

    Da aber $FO_APPEND der Standardmodus ist ginge auch folgendes:

    Spoiler anzeigen
    AutoIt
    #Region ### save ###
    Func _save($Tdata)
        Local $sFile = @ScriptDir & "\Save.txt"
        FileWrite($sFile, $Tdata)
    EndFunc   ;==>_save
    #EndRegion ### save ###

    Bei dir wrd die Datei immer wieder geöffnet aber nie geschlossen und FileWrite schreibt direkt in die Datei.

    :rolleyes: kleiner denk fehler grosser effekt, achje, danke dir für Hilfe.

    Ich habe dein Programm mal etwas geändert, jetzt wird nur noch einmal pro Datei geschrieben und die Ausgabe in die EditBox geschieht nur noch einmal je Pixelzeile. Dadurch wird dein Programm extrem beschleunigt.

    Auch hier nochmals, danke. muss mir dass genauer ansehen :3


    Nun solltest du nur folgendes bedenken, du führst bei jeden Pixel eine Schreiboperation auf die Festplatte aus. Bei einem Bild mit 4K Auflösung sind das dann ca. 9.000.000 Schreiboperationen. Wer also mal ein Testprogramm braucht, das testet ob eine SSD wirklich totgeschrieben werden kann, hier ist eins.

    eh, ja :saint: das ist ein schwerpunkt, der mir bekannt war.

  • der sinn dahinter ist eine idee zur bilddaten speicherung, welche man weiter verwerten kann.

    Schau mal in meiner Signatur hinter den Link zum X-Y-Problem....

    Du bastelst ein Script zur "Bilddatenspeicherung", dabei sind alle relevanten Daten bereits im Bild vorhanden.

    Du solltest besser genau beschreiben, wie du diese Daten "weiterverwerten" willst. Dann kann man Vorschläge/Beispiele machen, welche direkt zielführend sind. Und nicht Zeit und Energie an einem überflüssigen Script verschwenden, welches letztendlich das "Problem" gar nicht löst!