PDA

Click to See Complete Forum and Search --> : Colours


git
Oct 21st, 2000, 08:42 AM
Hiyas,

Let's set the scene - I have a world map in a game. There's three colours - the clicked colour, and two other colours which represent two different terrain types.

Say we have a dark tropical rainforest and grassland for the two different terrain types.

The clicked colour is somewhere in between the above colours, perhaps a slightly dark green.

How do I figure out which one it's closer to, taking into account the actual colour and the shading? (eg. it would pick blue over red if the colour picked was green)

I'm using the GetPixel function and I have the value in RGB.

Hope someone knows what I'm talking about... =)

Thanks.

-Git

git
Oct 21st, 2000, 08:45 AM
Hmm... was just thinking.

I could get the average from the RGB value ((R + B + G) / 3), converting it to B&W, for all 3 values, and then check which one is closer... Would that work? Or would it screw up because of shading?

Hmm............... I think too much. ;-)

-Git

kedaman
Oct 21st, 2000, 01:46 PM
Well, here's something i just put together, put all these stuff in a module and use the colordistance function. Two closer colors will return a lower number than two distant ones.

Type LngColor
Color As Long
End Type
Type RGBColor
Red As Byte
Green As Byte
Blue As Byte
End Type


Function ColorDistance(Color1 As Long, Color2 As Long) As Long
Dim L1 As LngColor, L2 As LngColor, RGB1 As RGBColor, RGB2 As RGBColor
L1.Color = Color1
L2.Color = Color2
LSet RGB1 = L1
LSet RGB2 = L2
ColorDistance = Abs(CLng(RGB1.Red) - RGB2.Red) + Abs(CLng(RGB1.Green) - RGB2.Green) + Abs(CLng(RGB1.Blue) - RGB2.Blue)
End Function
'Print ColorDistance(vbRed, vbBlue)
'510
'Print ColorDistance(vbYellow, vbBlue)
'765
'Print ColorDistance(vbYellow, vbRed)
'255

Koralt
Oct 21st, 2000, 09:06 PM
We don't want to add the three lengths, really. We can imagine colour existing in a three dimensional "colour space". The three axis are Red, Green, and Blue respectively. Given that visualization, we want to use the Pythagorean Thereom (aka The Distance Formula.)

I'll just copy kedaman's code and make the appropriate changes, to make it easy to see what's happening ... (and because I'm lazy!)



Type LngColor
Color As Long
End Type
Type RGBColor
Red As Byte
Green As Byte
Blue As Byte
End Type


Function ColorDistance(Color1 As Long, Color2 As Long) As Long
Dim L1 As LngColor, L2 As LngColor, RGB1 As RGBColor, RGB2 As RGBColor
Dim rd As Long, gd As Long, bd As Long
L1.Color = Color1
L2.Color = Color2
LSet RGB1 = L1
LSet RGB2 = L2

rd = RGB1.Red - RGB2.Red
gd = RGB1.Green - RGB2.Green
bd = RGB1.Blue - RGB2.Blue
ColorDistance = Int(Sqr(rd * rd + gd * gd + bd * bd))
'Note: if all you care about is which color is *CLOSEST* to some other color, you can drop the "Sqr"
End Function





The thing is, well, as far as a computer cares, while working with RGB format, Green is *completely* unlike Blue--as in completely. Of course, Blue is even more different from Yellow. Even bright blue. That's wrong. We need to compare the brightness and the coloration slightly differently ... so ...

(btw, you can head to http://www.wotsit.org ... lots of format info -- I got the YCbCr info out of the JPEG format ... probably not too useful for VB, tho')

Here's a matrix to convert to chrominance/luminance:


(R,G,B are 8-bit unsigned values)

| Y | | 0.299 0.587 0.114 | | R | | 0 |

| Cb | = |- 0.1687 - 0.3313 0.5 | * | G | + |128|

| Cr | | 0.5 - 0.4187 - 0.0813| | B | |128|



Ok, so matrices aren't too useful. Let's turn this into some VB code ...


'R G B are all single byte values -- from 0 to 255
Dim Y As Single, Cb As Single, Cr As Single

Y = 0.299*R + 0.587*G + 0.114*B
Cb = - 0.1687*R - 0.3313*G + 0.5 *B + 128
Cr = 0.5 *R - 0.4187*G - 0.0813*B + 128


'Converting back ... this isn't as important, but ...
R = Y + 1.402 *(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772 *(Cb-128)


Now, we can use the Y, Cb, and Cr values in the distance formula like we did with RGB. That should work, although a little bit of tweaking may be in order. btw, if you want to take the average of two colors, you'll be best off if you convert both RGBs to YCbCr, average those, and convert it back, although that takes way longer. ;)