Pixel einlesen und ggf. Färben

  • Hi,
    ich arbeite momentan an einem Skript, dass bestimmte Pixel ausliest und bei Bedarf färbt. Meine Funktion arbeitet mit einer While Schleife, weil meine vorherige Rekursive Funktion nicht funktioniert hat. Die Schleifen Funktion funktionert leider nur teilweise. Ich habe momentan 2 Probleme mit ihr:
    -Der nicht eingefärbte Bereich ist danach komplett schwarz, obwohl vorher ein Bild darauf geladen war und diese Pixel garnicht verändert wurden
    -An einer Stelle vom gefärbten Bereich "reißt" er einfach ab => Schnitt obwohl die Funktion dort weiter Färben sollte

    Die problematische Funktion ist _PaintRecursiv()

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>
    #Include <GDIPlus.au3>
    #include <Color.au3>
    #include <Misc.au3>

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    Dim $hBitmap[4]
    Global $BrushSize = 10
    Global $Tolerance = 10
    $PrimaryDown = False
    $SecondaryDown = False
    $PlusDown = False
    $MinusDown = False
    $UpArrowDown = False
    $DownArrowDown = False
    $sFile = FileOpenDialog("Bild öffnen", @DesktopDir, "Bilder (*.jpg;*.bmp;*.png)")
    ;~ $sFile = @DesktopDir &"\Foto.jpg"
    AutoItSetOption("MouseCoordMode", 2)

    [/autoit] [autoit][/autoit] [autoit]

    If $sFile <> "" Then
    $MiscDLL = DllOpen("user32.dll")

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("->Lädt Bild..." &@CRLF)
    $hBitmap[1] = _GDIPlus_ImageLoadFromFile($sFile)
    $hBitmap[2] = _GDIPlus_ImageLoadFromFile($sFile)
    $hBitmap[3] = _GDIPlus_ImageLoadFromFile($sFile)
    $hBuffer3 = _GDIPlus_ImageGetGraphicsContext($hBitmap[3])
    ConsoleWrite("+>Geladen..." &@CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $iWidth = _GDIPlus_ImageGetWidth($hBitmap[1])
    $iHeight = _GDIPlus_ImageGetHeight($hBitmap[1])
    _GreyScale($hBitmap[1], 0, 0, $iWidth, $iHeight) ; Bereich wird in Graustufen umberechnet
    _GDIPlus_GraphicsDrawImageRect($hBuffer3, $hBitmap[1], 0, 0, $iWidth, $iHeight)

    [/autoit] [autoit][/autoit] [autoit]

    $hGui = GUICreate("", $iWidth, $iHeight)
    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui)
    $hBitmap[0] = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphics)
    $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap[0])
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $FPSTimer = TimerInit()
    $GUIMsg = GUIGetMsg()
    $MouseX = MouseGetPos(0)
    $MouseY = MouseGetPos(1)
    Switch $GUIMsg
    Case $GUI_EVENT_CLOSE
    ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    Case $GUI_EVENT_PRIMARYDOWN
    $PrimaryDown = True

    [/autoit] [autoit][/autoit] [autoit]

    Case $GUI_EVENT_PRIMARYUP
    $PrimaryDown = False

    [/autoit] [autoit][/autoit] [autoit]

    Case $GUI_EVENT_SECONDARYDOWN
    $SecondaryDown = True

    [/autoit] [autoit][/autoit] [autoit]

    Case $GUI_EVENT_SECONDARYUP
    $SecondaryDown = False
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    If _IsPressed("6B", $MiscDLL) Then
    If Not $PlusDown Then $BrushSize += 5
    $PlusDown = True
    Else
    $PlusDown = False
    EndIf
    If _IsPressed("6D", $MiscDLL) Then
    If Not $MinusDown And $BrushSize >= 5 Then $BrushSize -= 5
    $MinusDown = True
    Else
    $MinusDown = False
    EndIf
    If _IsPressed("26", $MiscDLL) Then
    If Not $UpArrowDown And $Tolerance <= 95 Then $Tolerance += 5
    $UpArrowDown = True
    Else
    $UpArrowDown = False
    EndIf
    If _IsPressed("28", $MiscDLL) Then
    If Not $DownArrowDown And $Tolerance >= 5 Then $Tolerance -= 5
    $DownArrowDown = True
    Else
    $DownArrowDown = False
    EndIf
    If _IsPressed("53", $MiscDLL) Then
    _PaintRecursiv($hBitmap[2], $hBitmap[3], $MouseX, $MouseY, $iWidth, $iHeight)
    _GDIPlus_GraphicsDrawImageRect($hBuffer, $hBitmap[3], 0, 0, $iWidth, $iHeight)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $PrimaryDown Then
    _GDIPlus_GraphicsDrawImageRectRect($hBuffer, $hBitmap[2], $MouseX, $MouseY, $BrushSize, $BrushSize, $MouseX, $MouseY, $BrushSize, $BrushSize)
    ElseIf $SecondaryDown Then
    _GDIPlus_GraphicsDrawImageRectRect($hBuffer, $hBitmap[1], $MouseX, $MouseY, $BrushSize, $BrushSize, $MouseX, $MouseY, $BrushSize, $BrushSize)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($hBuffer, $hBitmap[3], 0, 0, $iWidth, $iHeight)
    _GDIPlus_GraphicsDrawString($hBuffer, "FPS: " &Round(1000 / TimerDiff($FPSTimer)) &" Pinselgröße: " &$BrushSize &" Toleranz: " &$Tolerance &"%", 10, 10, "Arial", 12)
    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap[0], 0, 0, $iWidth, $iHeight) ;zeichne auf die GUI
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDispose($hGraphics) ; gibt Grafikhandle wieder frei
    _GDIPlus_ImageSaveToFile($hBitmap[0], @DesktopDir &"\Test.jpg") ; speichere fertiges Bild

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($hBitmap) - 1
    _GDIPlus_BitmapDispose($hBitmap[$i])
    Next
    _GDIPlus_GraphicsDispose($hBuffer)
    _GDIPlus_GraphicsDispose($hBuffer3)
    _GDIPlus_Shutdown()
    DllClose($MiscDLL)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Func _PaintRecursiv($hGetterBitmap, $hSetterBitmap, $iX, $iY, $iW, $iH)
    Local $KonvertingTimer = TimerInit()
    Local $OneSecondTimer = $KonvertingTimer
    Local $ColorTolerance = Round(($Tolerance / 100) * 255)
    Local $SetterBitmapData = _GDIPlus_BitmapLockBits($hSetterBitmap, 0, 0, $iW, $iH, $GDIP_ILMWRITE, $GDIP_PXF32RGB)
    Local $GetterBitmapData = _GDIPlus_BitmapLockBits($hGetterBitmap, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32RGB)
    Local $SetterScan0 = DllStructGetData($SetterBitmapData, "Scan0")
    Local $GetterScan0 = DllStructGetData($GetterBitmapData, "Scan0")
    Local $Stride = DllStructGetData($SetterBitmapData, "Stride") ; Anzahl der Pixel in einer Reihe
    Local $Color, $Red, $Green, $Blue, $RedDiff, $GreenDiff, $BlueDiff, $GetterPixelData, $PixelChecked[$iW * $iH], $PixelToCheck[2][2] = [[1, ''], [$iX, $iY]], $Zaehler = 0
    $GetterPixelData = DllStructCreate("dword", $GetterScan0 + ($iY * $Stride) + ($iX * 4))
    $SetterPixelData = DllStructCreate("dword", $SetterScan0 + ($iY * $Stride) + ($iX * 4))
    $Color = DllStructGetData($GetterPixelData, 1)
    $Red = _ColorGetRed($Color)
    $Green = _ColorGetGreen($Color)
    $Blue = _ColorGetBlue($Color)
    Local $TargetColor[3] = [$Red, $Green, $Blue]
    ConsoleWrite("->Sucht rekursiv nach Pixeln... " &@CRLF &">Zielfarbe: " &$TargetColor[0] &" " &$TargetColor[1] &" " &$TargetColor[2] &" von " &$iX &"|" &$iY &", die Zielfarbe darf um " &$ColorTolerance &" abweichen." &@CRLF)
    DllStructSetData($SetterPixelData, 1, BitOR($Blue, BitShift($Green, -8), BitShift($Red, -16)))
    $Zaehler += 1
    While $PixelToCheck[0][0] > 0
    $iX = $PixelToCheck[$PixelToCheck[0][0]][0]
    $iY = $PixelToCheck[$PixelToCheck[0][0]][1]
    If $iX >= 0 And $iX < $iW And $iY >= 0 And $iY < $iH And $PixelChecked[($iY * $iW) + $iX] = '' Then
    $SetterPixelData = DllStructCreate("dword", $SetterScan0 + ($iY * $Stride) + ($iX * 4))
    $GetterPixelData = DllStructCreate("dword", $GetterScan0 + ($iY * $Stride) + ($iX * 4))
    $Color = DllStructGetData($GetterPixelData, 1)
    $Red = _ColorGetRed($Color)
    $Green = _ColorGetGreen($Color)
    $Blue = _ColorGetBlue($Color)
    $RedDiff = Abs($TargetColor[0] - $Red)
    $GreenDiff = Abs($TargetColor[1] - $Green)
    $BlueDiff = Abs($TargetColor[2] - $Blue)
    If $RedDiff <= $ColorTolerance And $GreenDiff <= $ColorTolerance And $BlueDiff <= $ColorTolerance Then
    DllStructSetData($SetterPixelData, 1, BitOR($Blue, BitShift($Green, -8), BitShift($Red, -16)))
    $PixelToCheck[0][0] += 7
    ReDim $PixelToCheck[$PixelToCheck[0][0] + 1][2]
    $i = -7

    [/autoit] [autoit][/autoit] [autoit]

    For $x = $iX To $iX + 1
    For $y = $iY - 1 To $iY + 1
    If $y <> $iY Or $x <> $iX Then
    If $PixelChecked[($y * $iW) + $x] = '' Then
    $PixelToCheck[$PixelToCheck[0][0] + $i][0] = $x
    $PixelToCheck[$PixelToCheck[0][0] + $i][1] = $y
    Else
    ReDim $PixelToCheck[$PixelToCheck[0][0]][2]
    $PixelToCheck[0][0] -= 1
    EndIf
    $i += 1
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Zaehler += 1
    Else
    ReDim $PixelToCheck[$PixelToCheck[0][0]][2]
    $PixelToCheck[0][0] -= 1
    EndIf
    $PixelChecked[($iY * $iW) + $iX] = True
    Else
    ReDim $PixelToCheck[$PixelToCheck[0][0]][2]
    $PixelToCheck[0][0] -= 1
    EndIf
    If TimerDiff($OneSecondTimer) >= 1000 Then
    ConsoleWrite(">" &$Zaehler &" gefärbte Pixel. Letzte Differenzen: " &$RedDiff &" " &$GreenDiff &" " &$BlueDiff &", zu prüfende Pixel: " &$PixelToCheck[0][0] &@CRLF)
    $OneSecondTimer = TimerInit()
    EndIf
    WEnd
    _GDIPlus_BitmapUnlockBits($hSetterBitmap, $SetterBitmapData)
    _GDIPlus_BitmapUnlockBits($hGetterBitmap, $GetterBitmapData)
    ConsoleWrite("+>Fertig... Verstrichene Zeit: " &Round(TimerDiff($KonvertingTimer) / 1000, 2) &"s, gefärbte Pixel: " &$Zaehler &@CRLF)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _GreyScale($hBitmap, $iX, $iY, $iW, $iH)
    ConsoleWrite("->Konvertiert in Grautöne..." &@CRLF)
    Local $KonvertingTimer = TimerInit()
    Local $OneSecondTimer = $KonvertingTimer
    Local $BitmapData = _GDIPlus_BitmapLockBits($hBitmap, $iX, $iY, $iW, $iH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
    Local $Stride = DllStructGetData($BitmapData, "Stride") ; Stride ist der Offset von einer Reihe zur nächsten
    Local $Width = DllStructGetData($BitmapData, "Width") ; Anzahl der Spalten
    Local $Height = DllStructGetData($BitmapData, "Height") ; Anzahl der Reihen
    Local $Scan0 = DllStructGetData($BitmapData, "Scan0") ; Die Bilddaten im Speicher
    Local $PixelData, $Color, $Luma
    For $row = 0 To $Height - 1 ; Reihe für Reihe
    For $col = 0 To $Width - 1 ; Spalte für Spalte
    ; lese Farbinformation des aktuellen Pixels(Spalte,Reihe) aus
    $PixelData = DllStructCreate("dword", $Scan0 + ($row * $Stride) + ($col * 4))
    $Color = DllStructGetData($PixelData, 1)
    ; berechne Grauwert
    $Luma = _ColorGetRed($Color) * 0.3 + _ColorGetGreen($Color) * 0.59 + _ColorGetBlue($Color) * 0.11
    ; Rot Grün und Blau wert werden jeweils auf den berechneten Grauwert gesetzt
    DllStructSetData($PixelData, 1, BitOR($Luma, BitShift($Luma, -8), BitShift($Luma, -16)))
    Next
    If TimerDiff($OneSecondTimer) >= 1000 Then
    ConsoleWrite(">" &Round(($row + 1) / ($Height / 100)) &"%" &@CRLF)
    $OneSecondTimer = TimerInit()
    EndIf
    Next
    _GDIPlus_BitmapUnlockBits($hBitmap, $BitmapData)
    ConsoleWrite("+>Fertig... Verstrichene Zeit: " &Round(TimerDiff($KonvertingTimer) / 1000, 2) &"s" &@CRLF)
    EndFunc ;==>_GreyScale

    [/autoit]