PixelGetColor - Check many colors at one coordinate

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Albireo
Posts: 1754
Joined: 16 Oct 2013, 13:53

PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 04:33

My wish is to check color changes in a point or on a area.

The x-, y- and color values, can I see in AHK-Window spy.
But, I find it difficult to read where the mouse points.
Because of this problem, I have written a small program to check colors in one area.
The results can be advantageous analyzed in e.g. Calc or Excel

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
#SingleInstance Force
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Result file
FileName = ColorArea.txt
IfExist %FileName%
	FileDelete %FileName%

; Area to check
CoordMode Pixel, Client
xPos1 = 325	; Upper left corner (Client value)
yPos1 = 6

xPos2 = 350	; Lower right corner (Client value)
yPos2 = 30

MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%,
(LTrim Join
	The controlled area. (Mode = Client)`n
	(the area values is changed in this AHK-program)`n
	- - Upper left`n
	`txPos = %xPos1% `n
	`tyPos = %yPos1% `n`n
	- - Lower right`n
	`txPos = %xPos2%`n
	`tyPos = %yPos2%`n`n
	Activate the desired window/program, after the button "OK!" is pressed. `n
	After the button "OK" is pressed, This program is then wait 5 seconds, `n
	before the colorcheck is begun.
)
Sleep 5000

; Adjust for headlines
xPos := xPos1
xStep := xPos2 + 1 - xPos1
yPos := yPos1
yStep := yPos2 + 1 - yPos1

xPos1 = %xPos% ; Keep the original x-pos
Loop % xStep + 1
{	If A_Index = 1	; Add an empty column
	{	Result := A_Space ";"
		EnvSub xPos, 1
	}
	else
	{	EnvAdd xPos, 1	; Remove the last "semicolon"
		If A_Index <= %xStep%
			Result .= xPos ";"
		else
			Result .= xPos "`n"
	}
}


xPos = %xPos1% ; Begin again
yPos1 = %yPos% ; Keep the original y-pos
Loop %yStep%
{	Loop % xStep + 1
	{	If A_Index = 1 ; The Y-value
		{	Result .= yPos ";"
			EnvSub xPos, 1 ; Remove the first column
		}
		else
		{	EnvAdd xPos, 1	; Remove the last "semicolon"
			If A_Index <= %xStep%
			{	ColorName := ColorName(xPos, yPos)	; Give the color of a position a name
				Result .= ColorName ";"
			}	
			else
			{	ColorName := ColorName(xPos, yPos)	; Give the color of a position a name
				Result .= ColorName "`n"
			}
			; MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%,  xPos = %xPos% `nyPos = %yPos% `nColorName = %ColorName%
		}
	}
	EnvAdd yPos, 1
	; MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%, xPos = %xPos% `nyPos = %yPos% `n`n%Result%
	xPos := xPos1
}

FileAppend %Result%, %FileName%
MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%, Logfil .: %FileName% `n`nThe area ColorCheck is Ready!
ExitApp

ColorName(xPos, yPos)	; Give the RGB-color a name
{	; MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%,  OutName = %OutName% `nPixColor = %PixColor% `nxPos = %xPos% `nyPos = %yPos%
	CoordMode Pixel, Client
	PixelGetColor PixColor, %xPos%, %yPos%, RGB ; Read the color (RGB) in a determined position
	OutName = %PixColor%
	; MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%,  OutName = %OutName% `nPixColor = %PixColor% `nxPos = %xPos% `nyPos = %yPos%
	If PixColor = 0x000000
		OutName := "Black"
	If PixColor = 0xFFFFFF
		OutName := "White"
	If PixColor = 0x0078D7
		OutName := "MarkBlue"
	If PixColor = 0xA8C9EA
		OutName := "LightBlue"
	If PixColor = 0xF0F0F0
		OutName := "LightGray"
	If PixColor = 0xF0AB60
	  	OutName := "Orange"
	If PixColor = 0xA0A0A0
		OutName := "Gray"
	If (PixColor = 0x40C040) or (PixColor = 0x00FF00)
		OutName := "Green"
	If PixColor = 0x008000
		OutName := "DarkGreen1"
	If PixColor = 0x005600
	 	OutName := "DarkGreen"
	If PixColor = 0xFF0000
		OutName := "Red"
	If PixColor = 0xA7C8E9
		OutName = "LightPurple"
	If PixColor = 0xA7C7E8
		OutName = "LightPurple"
	If PixColor = 0xA6C7E7
		OutName = "LightPurple"
	If PixColor = 0xA5C6E6
		OutName = "LightPurple"
	If PixColor = 0xA5C5E6
		OutName = "LightPurple"
	If PixColor = 0xA6C7E8
		OutName = "LightPurple"
	If PixColor = 0xA6C6E7
		OutName = "LightPurple"
	If PixColor = 0xA5C5E5	
		OutName = "LightPurple"
	; MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%,  OutName = %OutName% `nPixColor = %PixColor% `nxPos = %xPos% `nyPos = %yPos%
	Return %OutName%
}
The program works, (the colornames can always be discussed).
However, different computers (depending on resolution, etc.) provide different color values in the analysis.
The variations are not large, but enough to not match.
For example, with my eye is both 0xFFFFFF, and 0xFCFFFF an white color.
The program above give me the hex-color name, and I can give the color an easier name,
and give many HEX-colors the same name.
But my color names can have many, many, variations of hex colors,
and I do not want to write huge if-instructions or build complicated loops for each color.
Is there any alternative?
Which way is easiest to name a variety of adjacent colors to the same name?

(This makes it easier to analyze the colors in areas)

Then I want to create a function that checks the color in a selected point.
Something like this .:

Code: Select all

Result := ColorCheck(xPos,yPos,"White")
If Result = Yes
   Do....

ColorCheck(xPos,yPos,Color)
{ ....
   Return %Result%   ; Return Yes och HEX-Colorname (No)
}
BoBo
Posts: 6564
Joined: 13 May 2014, 17:15

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 05:50

You could create color-group-arrays and check if a color belongs to a specific group.
This might come handy :)
https://www.w3schools.com/colors/colors_groups.asp
User avatar
boiler
Posts: 16932
Joined: 21 Dec 2014, 02:44

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 06:39

Instead of testing for every possible color, you should define a range of values of the red, green, and blue components that you consider to be grouped together within one named color. You can break a color into its components like this:

Code: Select all

blue := rgbColor & 0xFF
green := (rgbColor & 0xFF00) >> 8
red := (rgbColor & 0xFF0000) >> 16
Then you might consider white to be when all the components are greater than 0xF0 or something.
Albireo
Posts: 1754
Joined: 16 Oct 2013, 13:53

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 06:54

I think this way feel real complicated, (but maybe it's the only way?)
When I look at the color-groups, it have only defined a few colors.
for example
"Green" (on page .: Color groups) is defined as0x008000
A little lighter green is "ForestGreen" defined as 0x228B22 and little darker is "DarkGreen" 0x006400
Inside Green it is shades (beween white to black).
This means very many colors, and I have not checked everyone.

Maybe it works when to match a webpage, but I want to check the color on other programs and windows.
(What color is 0x7086AC)
User avatar
boiler
Posts: 16932
Joined: 21 Dec 2014, 02:44

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 07:51

If you think defining a range of colors is complicated, why do you think it would be easier to list every possible variation of a color that you would define as green, for example?

Yes, trying to generalize all the possible colors is an involved task, but that's because you've decided to take on a difficult task. If you would rather list all the potential variations that would fall within what you would define as a named color, it would be tremendously tedious to set up that list, and the code we be very slow in executing.
Albireo
Posts: 1754
Joined: 16 Oct 2013, 13:53

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 08:00

boiler wrote:....... You can break a color into its components like this:

Code: Select all

blue := rgbColor & 0xFF
green := (rgbColor & 0xFF00) >> 8
red := (rgbColor & 0xFF0000) >> 16
Then you might consider white to be when all the components are greater than 0xF0 or something.
It's something I don't understand.
How to translate (what happens) rgbColor & 0xFF or (rgbColor & 0xFF00) >> 8 or (rgbColor & 0xFF0000) >> 16?

Now I tested something like this

Code: Select all

ColorName(xPos, yPos)
{	; All matchlists
	Black = 0x000000,0x1B00000
	White = 0xFFFFFF,0xFCFFFF
	Gray = 0x7086AC,0xA0A0A0
	
	CoordMode Pixel, Client
	
	PixelGetColor PixColor, %xPos%, %yPos%, RGB ; Read the color (RGB) in a determined position
	; MsgBox 64, Rad %A_LineNumber% -> %A_ScriptName%, PixColor = %PixColor%
	
	If PixColor in %Black%
		Return "Black"	
	
	If PixColor in %White%
		Return "White"	

	If PixColor in %Gray%
		Return "Gray"
		
	If PixColor in %LightBlue%
		Return "LightBlue"

	Return %PixColor%	
}
If the function have "0x..." in the return, the color could not be in any ot the match lists.
(and can later be manually added to the correct match list)
User avatar
boiler
Posts: 16932
Joined: 21 Dec 2014, 02:44

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 09:12

The whole point it to not use a match list anymore. You determine ranges that the three components need to fall within for it to be considered a certain named color. The code below demonstrates a function that breaks it up into its components. Then it's up to you to decide what color it is based on the values. As I said before, perhaps it's white when they are all > 0xF0. Perhaps it's grey when they are all within 0x0F of each other (and maybe be within a certain range if you don't want to include dark greys or light greys, or to categorize them separately).

Code: Select all

Color := 0x7086AC
GetRgbComponents(Color, Red, Green, Blue)
SetFormat, IntegerFast, hex
MsgBox, % "Color: " Color "`nR: " Red "`nG: " Green "`nB: " Blue
return

GetRgbComponents(rgbColor, ByRef red, ByRef green, ByRef blue)
{
	blue := rgbColor & 0xFF
	green := (rgbColor & 0xFF00) >> 8
	red := (rgbColor & 0xFF0000) >> 16
}
Albireo
Posts: 1754
Joined: 16 Oct 2013, 13:53

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 10:25

Thanks for your time!
What does this instructions means? & 0xFF
and (rgbColor & 0xFF00) >> 8
and & 0xFF0000) >> 16
and all instructions together.
What happens?
User avatar
boiler
Posts: 16932
Joined: 21 Dec 2014, 02:44

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 11:52

It's bit-level math, which is operating on the bits of the color value to extract parts of it and shift them. The "&" is a bitwise "and", so and-ing it with 0xFF gets rid of the rest. 0x7086AC becomes 0x0000AC (or 0xAC). Similarly, 0x7086AC & 0xFF00 becomes 0x008600. Then you have to make 0x8600 become 0x86, so you have to shift the bits to the right by 8 (one byte), which is what ">> 8" does. Similarly for 0xFF0000, which then needs to be shifted 16 bits (two bytes) to the right.
User avatar
boiler
Posts: 16932
Joined: 21 Dec 2014, 02:44

Re: PixelGetColor - Check many colors at one coordinate

21 Sep 2017, 11:59

To make it easier to understand, you have to think about it in terms of bits:

0x0000FF: 0000 0000 0000 0000 1111 1111
0x7086AC: 0111 0000 0111 0110 1010 1100
& result: 0000 0000 0000 0000 1010 1100

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 311 guests