Compare RGB colors so that the color difference is more significant than the intensity

When it comes to color matching during image analysis, you'll soon find that you can just use the image in grayscale. What for? Because usually you do this:

double average = (color.r+color.g+color.b)/3; 

Based on the grascale middle colors, I made an algorithm that is actually quite satisfactory when I need to find an object on the screen (I used the entire desktop, but this is good):

image description

A medium color search took 67 ms, while a search for exact pixel matching (blue frame) took 1.255 seconds! (and the first is completed immediately after the first match, while the average color algorithm sings the full image).

But I wanted to improve the accuracy of the graphical interface. In the GUI, the red button looks the same as the blue button, and may not be mapped correctly. That's why I implemented a color integrated image. Now I found that I do not know how to correctly compare the sums of colors to get real color reproduction.

So, imagine that you have 2 arrays of 3 elements.

 //Summed colors on the image you're looking for double sumOnSearchedImage[3]; //Summed colors on currently checked rectangle (in some loop we'll not bother with here) double sumOnBigImage[3]; 

Each number in the arrays represents a red, blue, and green sum (not average), respectively. How do you compare them, so the difference between rgb(0, 255, 255) and rgb(255,255,255) greater than the difference between rgb(170,170,170) and rgb(255,255,255) ?

+1
source share
2 answers

In metric space, the distance between rgb (0, 255, 255) and rgb (255,255,255) is already much greater than the distance between rgb (170,170,170) and rgb (255,255,255).

Use not squares, but squares for speed.

 |(0, 255, 255), (255,255,255)|^2 = 255^2 = 9*85^2 |(170,170,170), (255,255,255)|^2 = 3*85^2 

By the way, do not be surprised to find that shades of gray are often enough. Good design forces designers to make things a) well visible and b) at least somehow visible to about 18% of people, as many of them have problems with colors. http://www.colour-blindness.com/general/prevalence/

+1
source

use a point product

 dc=cos(ang)=dot(col1,col2); dc=r1*r2+g1*g2+b1*b2 

for normalized RGB colors (vector units) this gives you a coefficient in the range dc=<0,1> , where 0 means a 90 degree angle between the colors (maximum difference) and 1 means the same color (not intensity)

performance

use 8 bits per channel ... so the range is <0,255> to avoid using FPUs . You can avoid using sqrt for unnormalized colors simply by:

 dc=(r1*r2+g1*g2+b1*b2)^2/(|col1|^2*|col2|^2) |col|^2=r*r+g*g+b*b 

[edit1] more information

normalized colors are units of 3D vectors

if you convert this value to an 8-bit range, for example 255*(r,g,b) , then you get a range of 8 bits per channel so that you can treat each color channel as an integer or a decimal point with a fixed point. For a fixed point, you just need to change the multiplication and division, all other operations are the same:

 add=a+b sub=ab mul=(a*b)>>8 div=((a<<8)/b)>>8 

when you use normalized colors then |col|=1 so you don't need sqrt or division. For a fixed point, just shift right 8 bits instead ... For integers <0,255> |col|=255 , which are also done ~ shift 8 bits to the right. For abnormal colors you need to divide by |col| which need sqrt and division, but the dc coefficient is in the range <0,1> , so if you use dc^2 , you just change the linearity of the coefficient, which is not important for you and for |col|^2 use of sqrt is deprecated , because |col|^2=sqrt(r*r+g*g+b*b)^2=(r*r+g*g+b*b) .

For greater speed, you must convert the entire image to normalized colors before your task. If encoded correctly, it should be around 10+ ms for normal desktop permissions.

[Note]

There are other color spaces that are more suitable for your purpose, such as HSV

+2
source

Source: https://habr.com/ru/post/1234948/


All Articles