Sign in to follow this  
Followers 0
Syruz

Search area for DARKEST pixel

17 posts in this topic

Is there a way to search an area for the darkest pixel in it no matter what the color ends up being?

Share this post


Link to post
Share on other sites



Is there a way to search an area for the darkest pixel in it no matter what the color ends up being?

No problem, as long as you can mathematically define "darkest", given that the pixel color is a 24-bit RGB number. For example, do you consider 0xFF0000 to be darker than 0x0000FF?

<_<


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

blacks and browns would be considered the darkest

Share this post


Link to post
Share on other sites

Here is what I came up with...it isn't very fast, then again I have a 24 inch monitor at 1900 x 1200.

#include <Color.au3>

$result = FindDarkestPixel(0, 0, 400, 400)
MsgBox(0,"","Darkest pixel found at X: " & $result[0] & " Y: " & $result[1])

Func FindDarkestPixel($LL = 0, $TT = 0, $RR = @DesktopWidth, $BB = @DesktopHeight)
    Local $darkest[2] = [0,0]
    Local $darkestColor = 255
    
    For $T = $TT to $BB
        For $L = $LL to $RR
        
            $result = PixelGetColor ( $L , $T )
            $grayscale = (_ColorGetBlue ( $result ) + _ColorGetRed ( $result ) + _ColorGetGreen ( $result )) / 3
            If $grayscale < $darkestColor Then
                $darkest[0] = $L
                $darkest[1] = $T
                $darkestColor = $grayscale
            EndIf
        
        Next
    Next
    
    Return $darkest
EndFunc

Share this post


Link to post
Share on other sites

You'd have to write the equivalent of a guassian blur formula, where the program takes a pixel and then gets the values surrounding it in all 8 positions and compares each one. If it finds a darker one, jump to that pixel and re-compare.

OR

Start at the beginning of your bounding box and compare each pixel going forward, left to right and then down. Store the pixel colour value, go to the next one. If lower, re-store the value and continue, otherwise ... skip it.

Caveat Emptor: Browns are in the red/yellow range .... and if you have a brown next to your blue, the blue will read as "lower" with this method, due to the way that hex numbers are calculated. You may want to use the option that swaps the "normal" way of reading colour from 0xRGB to 0xBGR


Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Share this post


Link to post
Share on other sites

Here is another version that doesn't use the _ColorGet functions:

$result = FindDarkestPixel(0, 0, 400, 400)
MsgBox(0,"","Darkest pixel found at X: " & $result[0] & " Y: " & $result[1])

Func FindDarkestPixel($LL = 0, $TT = 0, $RR = @DesktopWidth, $BB = @DesktopHeight)
    Local $darkest[2] = [0,0]
    Local $darkestColor = 0xFFFFFF
    
    For $T = $TT to $BB
        For $L = $LL to $RR
            
            $grayscale = Hex(PixelGetColor ( $L , $T ))
            
            If $grayscale < $darkestColor Then
                $darkest[0] = $L
                $darkest[1] = $T
                $darkestColor = $grayscale
            EndIf
        
        Next
    Next
    
    Return $darkest
EndFunc

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Im assuming 400 by 400 is the measurements pixel wise of the search area?

Edit: Nvm, is there a way of changing that to search an area within a rectangle? Like Pixelsearch

Edited by Syruz

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

You are correct. If speed is critical you could add a Step 2 or Step 3 to the For loops to skip a few pixels each time it checks; however, accuracy will be lost.

Edit: For clarification the parameters are absolute so FindDarkestPixel(LEFT, TOP, RIGHT, BOTTOM)

Edited by weaponx

Share this post


Link to post
Share on other sites

Here is another version that doesn't use the _ColorGet functions:

$result = FindDarkestPixel(0, 0, 400, 400)
MsgBox(0,"","Darkest pixel found at X: " & $result[0] & " Y: " & $result[1])

Func FindDarkestPixel($LL = 0, $TT = 0, $RR = @DesktopWidth, $BB = @DesktopHeight)
    Local $darkest[2] = [0,0]
    Local $darkestColor = 0xFFFFFF
    
    For $T = $TT to $BB
        For $L = $LL to $RR
            
            $grayscale = Hex(PixelGetColor ( $L , $T ))
            
            If $grayscale < $darkestColor Then
                $darkest[0] = $L
                $darkest[1] = $T
                $darkestColor = $grayscale
            EndIf
        
        Next
    Next
    
    Return $darkest
EndFunc
By that comparison, the bright Green color 0x00FF00 is "darker" than the almost-black red of 0x010000. Simple numeric compares just won't do for this.

<_<


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

One would have to do three comparisons. One for the blue channel, one for the green channel, one for the red channel and compare the hex values. (0x00 to 0xFF)


Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Share this post


Link to post
Share on other sites

Well then stick with the first version I posted. It converts the pixel color to grayscale for comparison.

Share this post


Link to post
Share on other sites

Didn't notice that.


Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Share this post


Link to post
Share on other sites

Well then stick with the first version I posted. It converts the pixel color to grayscale for comparison.

I see what you mean, and that's good if the OP accepts that mathematical definition of "darkest", but I don't think it produces visually natural results. For example, the following demo allows testing various values and comparing them side by side for visual "darkness". The default values that it starts with are 0x800080 and 0x00FF00. The second is mathematically "darker", but doesn't look that way on the screen:

#include <guiconstants.au3>

Opt("GuiOnEventMode", 1)

Global $Color_1 = 0x800080, $Color_2 = 0x00FF00
$hGUI = GUICreate("Test", 400, 300)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Quit")

$Graphic_1 = GUICtrlCreateGraphic(10, 10, 185, 185)
GUICtrlSetBkColor(-1, $Color_1)
$Input_1 = GUICtrlCreateInput("0x" & Hex($Color_1, 6), 10, 205, 185, 20)
$Button_1 = GUICtrlCreateButton("Set Color 1", 30, 235, 145, 30)
GUICtrlSetOnEvent(-1, "_ButtonHit")

$Graphic_2 = GUICtrlCreateGraphic(205, 10, 185, 185)
GUICtrlSetBkColor(-1, $Color_2)
$Input_2 = GUICtrlCreateInput("0x" & Hex($Color_2, 6), 205, 205, 185, 20)
$Button_2 = GUICtrlCreateButton("Set Color 1", 225, 235, 145, 30)
GUICtrlSetOnEvent(-1, "_ButtonHit")

GUISetState()

While 1
    Sleep(20)
WEnd

Func _ButtonHit()
    Switch @GUI_CtrlId
        Case $Button_1
            $Input = Number(GUICtrlRead($Input_1))
            If $Input <> $Color_1 And $Input >= 0 And $Input <= 0xFFFFFF Then $Color_1 = $Input
            GUICtrlSetBkColor($Graphic_1, $Color_1)
            GUICtrlSetData($Input_1, "0x" & Hex($Color_1, 6))
        Case $Button_2
            $Input = Number(GUICtrlRead($Input_2))
            If $Input <> $Color_2 And $Input >= 0 And $Input <= 0xFFFFFF Then $Color_2 = $Input
            GUICtrlSetBkColor($Graphic_2, $Color_2)
            GUICtrlSetData($Input_2, "0x" & Hex($Color_2, 6))
    EndSwitch
EndFunc

Func _Quit()
    Exit
EndFunc

<_<


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

PsaltyDS....ouch....driveby

I was thinking about using HSB / HSL color format and using the lightness / brightness value for comparison but...converting to those values takes a lot of code and it's slow already.

I found this RGBtoHSL function here in the forum but it depends on another seperate UDF on top:

http://www.autoitscript.com/forum/index.ph...p;hl=brightness

I also tried converting this .NET code but the return values don't seem to match Photoshop:

http://www.xtremevbtalk.com/showpost.php?p=746148

RGB2HSL("000255000")

Func RGB2HSL($pRGB)
    $pRGBR = StringLeft ( $pRGB, 3)
    $pRGBG = StringMid ( $pRGB,4, 3)
    $pRGBB = StringRight ( $pRGB, 3)

    Local $Rd, $Gd, $Bd
    Local $Max, $Min, $Dif, $Sum
  
  
    ;scale down the RGB color values to a 0-1 range
    $Rd = $pRGBR / 255
    $Gd = $pRGBG / 255
    $Bd = $pRGBB / 255
    
    ;get the strongest color
    $Max = 0
    
    If $Rd > $Max Then $Max = $Rd
    If $Gd > $Max Then $Max = $Gd
    If $Bd > $Max Then $Max = $Bd
    
    ;get the weakest color
    $Min = 1
    
    If $Rd < $Min Then $Min = $Rd
    If $Gd < $Min Then $Min = $Gd
    If $Bd < $Min Then $Min = $Bd
    
    ;calculate Luminosity
    $HSLL = ($Max + $Min) / 2
    
    If $Max = $Min Then ;the color is gray (all RGB values are equal)
        $HSLS = 0
        ;this is actually undefined
        $HSLH = 0
    Else
        $Dif = ($Max - $Min)
        $Sum = ($Max + $Min)
        
        ;calculate Saturation
        If $HSLL > 0.5 Then
            $HSLS = $Dif / $Sum
        Else
            $HSLS = $Dif / (2 - $Sum)
        EndIf
        
        ;calculate Hue
        Switch $Max
        Case $Rd
            $HSLH = (($Gd - $Bd) / $Dif)
        Case $Gd
            $HSLH = (($Bd - $Rd) / $Dif) + 2
        Case $Bd
            $HSLH = (($Rd - $Gd) / $Dif) + 4
        EndSwitch
        
        $HSLH = $HSLH / 6
        
        If $HSLH < 0 Then $HSLH = $HSLH + 1
        
    EndIf
    
    ;return the results
    ;Return = $HSL
    MsgBox(0,"","Luminosity: " & $HSLL & @CRLF & "Saturation: " & $HSLS & @CRLF & "Hue: " & $HSLH)
    
EndFunc

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

<_< Does the VB code create values that match photoshop? Edited by Blue_Drache

Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

Didn't try it. I think it was .NET code and I don't have .NET Studio

But with the code I posted I entered this

R 0

G 255

B 0

Which returns:

B: .5

S: 1

H: .3333333333

Photoshop:

B: 100%

S: 100%

H: 120 degrees

Edited by weaponx

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

This is my last submission...this version will convert each pixel into HSV / HSB format for comparison, using the brightness as the metric (very slow):

$result = FindDarkestPixel(0, 0, 200, 200)
MsgBox(0,"","Darkest pixel found at X: " & $result[0] & " Y: " & $result[1])

Func FindDarkestPixel($LL = 0, $TT = 0, $RR = @DesktopWidth, $BB = @DesktopHeight)
    Local $darkest[2] = [0,0]
    Local $darkestValue = 100
   
    For $T = $TT to $BB
        For $L = $LL to $RR
           
            ;Store hex color code
            $nColor = Hex(PixelGetColor ( $L , $T ))
            
            ;Return HSV color value from decimal number converted to hex
            $HSV = RGB2HSL(BitAND( BitShift($nColor, 16), 0xff), BitAND( BitShift($nColor, 8), 0xff), BitAND($nColor, 0xff))            
           
            ;If new color is darker, store its coordinates and its brightness value
            If $HSV[2] < $darkestValue Then
                $darkest[0] = $L
                $darkest[1] = $T
                $darkestValue = $HSV[2]
            EndIf
       
        Next
    Next
   
    Return $darkest
EndFunc

;This function will return an array [0]:H [1]:S [2]:V
Func RGB2HSL($RRR, $BBB, $GGG)
    Local $H, $S, $V, $largest
    Local $hsvArray[3] = [0,0,0]
    
    ;Determine highest component value
    $Max = 0
    
    If $RRR > $Max Then 
        $Max = $RRR
        $largest = "R"
    EndIf
    If $GGG > $Max Then 
        $Max = $GGG
        $largest = "G"
    EndIf
    If $BBB > $Max Then 
        $Max = $BBB
        $largest = "B"
    EndIf
    
    ;Determine lowest component value
    $Min = 1
   
    If $RRR < $Min Then $Min = $RRR
    If $GGG < $Min Then $Min = $GGG
    If $BBB < $Min Then $Min = $BBB
    
    ;Color is grey
    If $Max = $Min Then
        $H = 0
    Else
        ;Determine Hue
        Switch $largest
            Case "R"
                $H = 60 * ($GGG - $BBB) / ($Max - $Min)
            Case "G"
                $H = 180 * ($BBB - $RRR) / ($Max - $Min)
            Case "B"
                $H = 300 * ($RRR - $GGG) / ($Max - $Min)
            Case Else
                $H = 0
        EndSwitch
    EndIf
    
    ;Determine Saturation
    $S = ($Max - $Min) / $Max
    
    ;Determine Value
    $V = ($Max / 255) * 100
    
    ;MsgBox(0,"","H:" & $H & @CRLF & "S:" & $S & @CRLF & "V:" & $V)
    $hsvArray[0] = $H
    $hsvArray[1] = $S
    $hsvArray[2] = $V
    
    Return $hsvArray
EndFunc
Edited by weaponx

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  
Followers 0