Script to determine how close colors are together

Post your working scripts, libraries and tools for AHK v1.1 and older
locohost0
Posts: 2
Joined: 20 Jul 2016, 15:05

Script to determine how close colors are together

20 Jul 2016, 15:30

Hello,
I was having some trouble using pixelsearch, it was taking too long (30-70) ms per search where I needed to do 10s of comparisons this was starting to add up.
I began rewriting the same script using pixelcolorget, however, I found I would expect, for example, white (FFFFFF) and would get FFFFFE or FFFCFF or similar due to some variation in 3d rendering or something and my if statement would not match.
Pixelsearch has a very useful Variation option that solves this problem but I could not find any similar functionality to compare colors outside of that function.
This is what I wrote to solve the problem. Thanks to several other threads here where I borrowed ideas from.

Please let me know if this is helpful, if anyone has any suggestions, or is aware of something that already exists that does this better, as I could not find it.

Execute the function like so and get_variance will break the color into its R,G,B components, take the absolute value of the difference and add them together. In this case the variance is 3.

hexWhite := 0xFFFFFF
foundcolor : = 0xFEFEFE
get_variance(hexWhite, foundcolor)

Again, let me know if anyone has any suggestions.
Attachments
get_variance.ahk
(920 Bytes) Downloaded 192 times
gv_example.ahk
(1.9 KiB) Downloaded 151 times
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Script to determine how close colors are together

22 Jul 2016, 10:01

I don't think ImageSearch checks the sum of the difference of each shade.
If two colors are percieved as similar I think they are close in each color shade. Eg. 150 150 150 is percived as close to 160 160 160 but less to 150 150 180, but the "variance" is the same.
Image
(Left: 150 150 150, Middle: 160 160 160, Right: 150 150 180)
locohost0
Posts: 2
Joined: 20 Jul 2016, 15:05

Re: Script to determine how close colors are together

22 Jul 2016, 14:38

great point Helgef. I looked over the AHK source code and I believe I found in script2.cpp what pixelsearch is doing in terms of variance/variation and it appears to be, indeed, calculating the variation for r, g, b each individually.

Code: Select all

script2.cpp:            //BYTE red_low1 = (aVariation > search_red1) ? 0 : search_red1 - aVariation;
script2.cpp:            //BYTE green_low1 = (aVariation > search_green1) ? 0 : search_green1 - aVariation;
script2.cpp:            //BYTE blue_low1 = (aVariation > search_blue1) ? 0 : search_blue1 - aVariation;
script2.cpp:            //BYTE red_high1 = (aVariation > 0xFF - search_red1) ? 0xFF : search_red1 + aVariation;
script2.cpp:            //BYTE green_high1 = (aVariation > 0xFF - search_green1) ? 0xFF : search_green1 + aVariation;
script2.cpp:            //BYTE blue_high1 = (aVariation > 0xFF - search_blue1) ? 0xFF : search_blue1 + aVariation;
script.h:       ResultType PixelSearch(int aLeft, int aTop, int aRight, int aBottom, COLORREF aColorBGR, int aVariation
The simplest solution to make variance in my function more similar to variation in pixelsearch would be to determine which is the highest of Absrdiff , Absgdiff , Absbdiff and report that as the variance. However that would not distinguish between 150,150, 170 and 170,170,170. Which are also as different as 1 and 2 are from 3 in the example colors you posted. That said, based on your feedback I am a bit concerned by how close 1 and 2 are in your example while still having a variance of 30! Though so far get_variance.ahk is working great for my use case, I think will for now change it as described but think of a way to implement some kind of weight.

Thanks for the feedback.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Script to determine how close colors are together

23 Jul 2016, 04:39

What is the best measure is of course dependent on the application, there could be other concerns than the percieved difference. You could have an option in your function, like,

Code: Select all

get_var(colA,colB, option="Sum")
{
.
.
.
if (option="maximum")
	return max(rDiff,gDiff,bDiff) ; Non-existent function.
else
	return rDiff+gDiff+gDiff
}
Also, it's inefficient to do string operations on the hex representation of the color.
A good exercise could be to see if you can improve it, using

Code: Select all

r:=(col&0xFF0000) >> 16
g:=(col&0x00FF00) >> 8
b:=col&0x0000FF
; Where col is some color, eg, 0xabcdef
Spoiler
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

Re: Script to determine how close colors are together

23 Jul 2016, 11:30

Hi. I would have seen the color values as a 3 dimensional vector. When there are two vectors, you could easilly calculate the difference between them:

[edit]
diff := Sqrt( Abs( (color1_r**2 + color1_g**2 + color1_b**2) - (color2_r**2 + color2_g**2 + color2_b**2) ) )
This is a wrong formula - it just gives the absolute difference between length of two vectors, not the distance between.
However it will be useful if the purpose is to compare brightness of two colors regardless to color value.

The appropriate formula is:

Code: Select all

diff := Sqrt( (color1_r - color2_r)**2 + (color1_g - color2_g)**2 + (color1_b - color2_b)**2 )
[/edit]

Without further adjustments it will give a maximum distance of approx 442 ( 255 x sqrt(3) ) between white to black.

The nice thing about this method is that the distance as numbers also will be true compared to most humans subjective perception of the color difference - in the means of low numbers are similar colors and high numbers are different colors :thumbup:
Last edited by Almost_there on 23 Jul 2016, 12:31, edited 2 times in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Script to determine how close colors are together

23 Jul 2016, 11:52

>> sqrt(abs((150^2+150^2+150^2)-(150^2+150^2+180^2)))
ans =
99.4987
>> sqrt(abs((150^2+150^2+150^2)-(160^2+160^2+160^2)))
ans =
96.4365

I'm not convinced mate, the colors are are vastly different to my eyes, but they score almost the same, compared to 150 150 150, on your scale.

Edit: I actually have two eyes :wtf:
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

Re: Script to determine how close colors are together

23 Jul 2016, 12:29

Helgef
You can try again, I've corrected an math error.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Script to determine how close colors are together

23 Jul 2016, 16:13

Better for sure, but as mentioned, it depends on what you want to compare. And it's not hard to find an example where this measure doesn't say that much, with respect to percieved difference,

Image
from left to right: A=[0 220 220], B= [50 250 250], C=[0 0 0], D=[66 0 0]
Imo, A and B are more similar to each other, than C and D are, but norm2(A-B)~=norm2(C-D)~=66. Where norm2() is Almost_there's function. So the question here is, what does a score of 66 give you? The difference between turqoise and slightly darker turqoise, but also the difference between black and dark red wine.

The problem is that the norm2 is not invertible, so we lose information.

On a side note, the norm2 need to convert numbers to doubles, which should be a concern if comparing a lot of pixels, like in ImageSearch.
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

Re: Script to determine how close colors are together

24 Jul 2016, 07:57

Yes I see that the conversion may cause the script to run less efficiently.

I assume that the Sqrt() is one cause of this - I would like to see if there is a really effective way to solve this - is there a faster way to perform square root, that only deals with integers?

On the other hand - A faster way woult be:

Code: Select all

diff := Abs(color1_r - color2_r) + Abs(color1_g - color2_g) + Abs(color1_b - color2_b)
That would be a number between 0 (same color) and 255x3=765 (black to white).
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Script to determine how close colors are together

24 Jul 2016, 08:25

Almost_there wrote:Yes I see that the conversion may cause the script to run less efficiently.

I assume that the Sqrt() is one cause of this - I would like to see if there is a really effective way to solve this - is there a faster way to perform square root, that only deals with integers?

On the other hand - A faster way woult be:

Code: Select all

diff := Abs(color1_r - color2_r) + Abs(color1_g - color2_g) + Abs(color1_b - color2_b)
That would be a number between 0 (same color) and 255x3=765 (black to white).
That code is exactly what was originally proposed by the author and it's the same as in the "Spoiler" in my previous post.
Yes, the square root is the cause, it goes ℤ+ -> ℝ+.
Ruevil2
Posts: 174
Joined: 14 Jul 2014, 10:39

Re: Script to determine how close colors are together

25 Jul 2016, 11:30

Here is an example of this same thing using bit-shift.

Original by VxE, I condensed it into a single line.

Code: Select all

Distance(c1, c2)
{ ; function by [VxE], return value range = [0, 441.67295593006372]
   return Sqrt((((c1>>16)-(c2>>16))**2) + (((c1>>8&255) - (c2>>8&255))**2) + (((c1&255)-(c1&255))**2))
}

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 240 guests