Jump to content
Sign in to follow this  
funkey

Picture effect - improvements in speed and functionality

Recommended Posts

funkey

Hello,

I made this script to set pictures to greyscale but leave one color original.

Can anyone help me to get the better and faster picture effect?

Here is the code, test it with small pictures:

#include <GDIPlus.au3>
#include <WindowsConstants.au3>
#include <Color.au3>
#include <WinAPI.au3>
#include <Array.au3>

Opt("GUIOnEventMode", 1)

Global $sPath = FileOpenDialog("Choose Picture", @ScriptDir, "Pictures (*.bmp;*.jpg;*.png)", 1)
If @error Then Exit

Global $iCol = -1


_GDIPlus_Startup()
Global $hImage = _GDIPlus_ImageLoadFromFile($sPath)
Global $iWidth = _GDIPlus_ImageGetWidth($hImage)
Global $iHeight = _GDIPlus_ImageGetHeight($hImage)
_GDIPlus_ImageDispose($hImage)


Global $hGui = GUICreate("Color effect - Click to choose color", $iWidth, $iHeight);, -1, -1, 0x80000000)
Global $nPic = GUICtrlCreatePic($sPath, 0, 0, $iWidth, $iHeight)
GUICtrlSetOnEvent(-1, "_GetColor")
GUISetState(@SW_SHOW, $hGui)

Do
Until $iCol <> -1
Opt("GUIOnEventMode", 0)

WinSetTitle("Color effect", "", "Color effect - Please wait")

Global $hBitmap = _GDIPlus_BitmapCreateFromFile($sPath)
Global $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD + $GDIP_ILMWRITE, $GDIP_PXF32RGB)

;Stride - Offset, in bytes, between consecutive scan lines of the bitmap.
;If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
Global $iStride = DllStructGetData($tBitmapData, "Stride")
;Pixel format - Integer that specifies the pixel format of the bitmap
Global $iPixelFormat = DllStructGetData($tBitmapData, "Format")
;Scan0 - Pointer to the first (index 0) scan line of the bitmap.
Global $pScan0 = DllStructGetData($tBitmapData, "Scan0")

Global $tPixel

Global $iColPixel, $aCol[3], $aSetCol = _ColorGetRGB($iCol)
Global $iTol = 120, $Luma

For $row = 0 To $iHeight - 1
    For $col = 0 To $iWidth - 1
        $tPixel = DllStructCreate("dword", $pScan0 + $row * $iStride + $col * 4)
        $iColPixel = DllStructGetData($tPixel, 1)
        $aCol[0] = BitAND(BitShift($iColPixel, 16), 0xFF)
        $aCol[1] = BitAND(BitShift($iColPixel, 8), 0xFF)
        $aCol[2] = BitAND($iColPixel, 0xFF)

        If Not _ColorInTolerance($aSetCol, $aCol, $iTol) Then
            $Luma = $aCol[0] * 0.3 + $aCol[1] * 0.59 + $aCol[2] * 0.11
            DllStructSetData($tPixel, 1, BitOR($Luma, BitShift($Luma, -8), BitShift($Luma, -16)))
        EndIf
    Next
Next

_GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)

Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
_WinAPI_DeleteObject(GUICtrlSendMsg($nPic, 370, 0, $hHBitmap))

WinSetTitle("Color effect", "", "Color effect - Finished")

Do
Until GUIGetMsg() = -3


Global $sFileName = FileSaveDialog("Save picture", @ScriptDir, "JPG mage (*.jpg)", 16, "Bitmap_" & Hex($iCol, 6) & ".JPG")
If Not @error Then
    If StringRight($sFileName, 4) <> ".JPG" Then $sFileName &= ".JPG"
    Global $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap)
    _GDIPlus_ImageSaveToFile($hImage, $sFileName)
    _WinAPI_DeleteObject($hImage)
EndIf

_WinAPI_DeleteObject($hBitmap)
_WinAPI_DeleteObject($hHBitmap)
_GDIPlus_Shutdown()

Func _ColorInTolerance($aSetCol, $aCol, $iTol)
    Global $aTol[3] = [$iTol / 4, $iTol / 4, $iTol / 4]
    $aTol[_ArrayMaxIndex($aSetCol)] = $iTol

    If ($aSetCol[0] - $aTol[0]) < $aCol[0] And ($aSetCol[0] + $aTol[0]) > $aCol[0] And _
            ($aSetCol[1] - $aTol[1]) < $aCol[1] And ($aSetCol[1] + $aTol[1]) > $aCol[1] And _
            ($aSetCol[2] - $aTol[2]) < $aCol[2] And ($aSetCol[2] + $aTol[2]) > $aCol[2] Then
        Return 1
    Else
        Return 0
    EndIf
EndFunc   ;==>_ColorInTolerance

Func _GetColor()
    $iCol = PixelGetColor(MouseGetPos(0), MouseGetPos(1))
EndFunc   ;==>_GetColor

Thanks for any help!

Edited by funkey

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites
UEZ

Welcome to the cool GDI+ club :)

Such operations can only be faster when using ext. DLLs or ASM. No chance using built-in loops.

Edit: or using GDIP.au3 which has a lot of GDI+ function.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Jardz

I'm sure UEZ is spot on but I was to try to achieve this I'd look at Chroma keying.

_GDIPlus_ImageAttributesSetColorKeys (I think!!)

If this could reliably select your colour area and make transparent, then you could greyscale the left overs and drop onto the original??!

Personally I've never got this to select the right pixels for me, seems to use 'or' logic for each channel and not 'and' logic when selecting the pixels.

Good luck getting a faster solution.

Share this post


Link to post
Share on other sites
funkey

Thank you for your answers.

@UEZ: I'm in the GDI+-Club since I made my 'Kurven-Spiel'. ;)

I will make a DLL, when I'm satisfied with the result. I think the effect can be better.

@Jardz: Thanks, I will have a look at this function.


Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites
UEZ

Thank you for your answers.

@UEZ: I'm in the GDI+-Club since I made my 'Kurven-Spiel'. ;)

Totally forgot it... :>

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×