Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding Colours (Colors) Together like Paint (Blue + Yellow = Green, etc)

I'm making an iOS game using cocos2d libraries.

Lets say you have two objects that have two separate colours - defined in RGB as

Blue:    0,0,255
Yellow:  255,255,0

I want to add blue and yellow to make green.

To over complicate things, let's say that the Blue object is bigger than the Yellow object (for the sake of argument let's say that the ratio is 2:1), I'm adding twice as much blue as yellow - how to I calculate this new (light green) colour correctly.

I understand LAB * Color Space is useful for this sort of 'natural colour' kind of thing, but I'm not sure how to use it - especially in the context of a cocos2d object which (AFAIK) is limited to using RGB in its colour schemes.

I'd really appreciate practical help on how to implement this. Thanks heaps!

21/4 Update: So in LAB* blue+yellow ≠ green (which makes sense when you see they're at opposite ends of the same channel). It's actually quite a tricky problem with a little bit of discussion on SO. It seems that the ultimate answer is to use the Kubelka-Munk method that a piece of open source software called Krita uses. I can't find that anywhere (either the formula or the code itself).

This question has a link which uses HSL to work in a similar method to paint. I'm going to try to see if it works, and I'll feed back the result here.

In the meantime if anyone knows how to implement Kubelka-Munk or where I can find code to do this, or another solution, I would be very, very stoked!

like image 280
glenstorey Avatar asked Apr 13 '12 11:04

glenstorey


Video Answer


2 Answers

There is no color model where mixing blue and yellow makes green. Try it yourself with gouache, the only way it works is cyan and yellow. This is why you should try switching from RGB to CMYK, and back if you need. Here is how it's done

void toCMYK(float red, float green, float blue, float* cmyk)
{
  float k = MIN(255-red,MIN(255-green,255-blue));
  float c = 255*(255-red-k)/(255-k); 
  float m = 255*(255-green-k)/(255-k); 
  float y = 255*(255-blue-k)/(255-k); 

  cmyk[0] = c;
  cmyk[1] = m;
  cmyk[2] = y;
  cmyk[3] = k;
}

void toRGB(float c, float m, float y, float k, float *rgb)
{
  rgb[0] = -((c * (255-k)) / 255 + k - 255);
  rgb[1] = -((m * (255-k)) / 255 + k - 255);
  rgb[2] = -((y * (255-k)) / 255 + k - 255);
}

And then in your code, mix the cyan and yellow

float cmyk1[4];
toCMYK(255, 255, 0, cmyk1);  // yellow

float cmyk2[4];
toCMYK(0, 255, 255, cmyk2);  // cyan

// Mixing colors is as simple as adding
float cmykMix[] = { cmyk1[0] + cmyk2[0], cmyk1[1] + cmyk2[1], cmyk1[2] + cmyk2[2], cmyk1[3] + cmyk2[3] };

float rgb[3];
toRGB(cmykMix[0], cmykMix[1], cmykMix[2], cmykMix[3], rgb);  

NSLog(@"RGB mix = (%f, %f, %f)", rgb[0], rgb[1], rgb[2]);

Running the code will yield: RGB mix = (0.000000, 255.000000, 0.000000)

like image 175
mprivat Avatar answered Oct 11 '22 15:10

mprivat


Check the formulas on this site: http://www.easyrgb.com/index.php?X=MATH I've been doing similar thing, and it can be achieved by converting RGB->XYZ->Lab. However the computation is quite expensive(if you doing it for a lot of pixels).

And forget about RGB math when trying to mix colors if you want to obtain results similar to human eye

like image 42
Michał Zygar Avatar answered Oct 11 '22 13:10

Michał Zygar