68

The common mixing of RGB colors is very different from mixing colors for paintings, it's mixing of light instead mixing of pigments.

For example:

Blue (0,0,255) + Yellow (255,255,0) = Grey (128,128,128)

(It should be Blue + Yellow = Green)

Is there any known algorithm for color mixing that works like mixing real colors?


My approach

I've already tried following:

Converting both colors to HSV and mixing hues (multiplied by coefficient computed from saturation), and a simple average for saturation and value channels. Then I computed average luminance from both colors and adjusted the resulting color to match this luminance. This worked quite well, but the hue mixing was sometimes wrong, e. g.:

Red (Hue 0°) + Blue (Hue 240°) = Green (Hue 120°)

I've figured out that sometimes I need to shift the hue value by 360° (when the difference between hues is greater than 180°).

Red (Hue 360°) + Blue (Hue 240°) = Magenta/fuchsia (Hue 300°)

But this shifting wasn't very good too, e.g.:

Cyan (Hue 179°) + Red (Hue 0°) = Hue 89.5°
Cyan (Hue 181°) + Red (Hue 0°) --> shifting is performed (the difference is greater than 180°)
Cyan (Hue 181°) + Red (Hue 360°) = Hue 270.5°

(Hue 179 + Red) and (Hue 181 + Red) results in two completely different colors.


Then I tried CIE Lab color space (as in Photoshop), which is designed to be closer to how humans perceive the colors.

I used just a simple average for each corresponding two channels, but the results weren't satisfying, for example, I got pink (64, 26, -9.5) out of blue (98, -16, 93) and yellow (30, 68, -112). These coefficients were taken from Photoshop.

Maybe if I used some different operation than average, it could work, but I don't know what.


CMYK didn't work too, results are just like in RGB or LAB.


It seems that neither the trivial additive nor subtractive color mixing in any of these color spaces yields natural results.


Working implementations

Krita – Painterly mixer

Raster graphics editor Krita had a working implementation of more realistic color mixing at some point: http://commit-digest.org/issues/2007-08-12/ (Painterly mixer plugin)

They say it is the first public application that implements special technology using Kubelka and Munk equations that describe the behavior of pigments.

Here's a video of Krita color mixing: https://www.youtube.com/watch?v=lyLPZDVdQiQ

Paper by FiftyThree

There's also article about color blending in the Paper app for iOS developed by FiftyThree. They describe how they innovate and experiment in the area and also offer samples of mixing blue and yellow that results in green. However, the actual process or algorithm isn't really described there.

Quoting:

"In searching for a good blending algorithm, we initially tried interpolating across various color-spaces: RGB, HSV, and HSL, then CieLAB and CieLUV. The results were disappointing," says Chen. "We know red and yellow should yield orange, or that red and blue should make purple—but there isn't any way to arrive at these colors no matter what color-space you use. There's an engineering axiom: Do the simplest thing that could possibly work. Well, we had now tried the easiest possible approaches and they didn't feel even remotely right."

It seems that same as Krita, Paper implements the Kubelka-Munk model:

[...] the Kubelka-Munk model had at least six values for each color, including reflection and absorption values for each of the RGB colors. "While the appearance of a color on a screen can be described in three dimensions, the blending of color actually is happening in a six-dimensional space," explains Georg Petschnigg, FiftyThree's co-founder and CEO. The Kubelka-Munk paper had allowed the team to translate an aesthetic problem into a mathematical framework. [...]

From all this information, it seems that implementation based on the Kubelka-Munk model could be the way forward and offer results that are much closer to reality.

Even though it looks like a complicated process, I haven't yet seen much good information on how to implement something like this.


Related questions

These questions were posted after this one all relating to the same thing.

None of them really has the answer.


Other related links and resources

Tom Pažourek
  • 7,390
  • 7
  • 51
  • 92

7 Answers7

27

The correct answer is NO, because there is no correct working model of how "color mixing in the real world" really works. It is FAR too complex and conditional and not really at all like the simple Red-Blue-Yellow stuff that we learned in school (it in fact requires all of Chemistry and a lot of Physics and Biology to resolve).

However, the simplistic answer is: YES, use subtractive mixing rather than Additive mixing.

The color-mixing that we learned in grade school is based on pigment combinations which are a form of subtractive color mixing (very simplistically). That is the more colors that we add together, the darker it becomes because each pigment subtracts a little bit more light.

On the other hand, almost all computer color-schemes are additive in that they are based on combining light waves (very simplistically), so they get brighter, because each color adds a little bit more light.

The RGB+ scheme is somewhat, the additive complement to the subtractive scheme that we learned in most US elementary schools (which is RBY-). However, they do not match up exactly and it can be difficult to convert between them (researching now ...)


OK, if you just want to switch from additive combinations in RGB to subtractive ones, you can use the following reverse-bayesan type formula to combine two colors:

NewColor.R = (Color1.R * Color2.R)/255
NewColor.G = (Color1.G * Color2.G)/255
NewColor.B = (Color1.B * Color2.B)/255

Adjusting for the difference in the chromatic poles (G to Y, then back to G) is a lot harder ...


It has been pointed out that this produces Black for the example problem, and technically this is correct for a true subtractive system, however, if you want more diluting/subtractive system, you could try this instead:

NewColor.R = 255 - SQRT(((255-Color1.R)^2 + (255-Color2.R)^2)/2)
NewColor.G = 255 - SQRT(((255-Color1.G)^2 + (255-Color2.G)^2)/2)
NewColor.B = 255 - SQRT(((255-Color1.B)^2 + (255-Color2.B)^2)/2)

This produces a dark grey instead of Black. But to get Yellow or anything close, you still have to fix the color-scheme's pole-alignment problem.

RBarryYoung
  • 49,956
  • 12
  • 91
  • 127
  • This formula would give black in the situation mentioned, wouldn't it? – Dolphin Aug 31 '09 at 15:49
  • So have you found something better? – Tom Pažourek Sep 11 '09 at 10:42
  • No, it's pretty hard not to come up with Black in any subtractive approach because all three poles are maxed out in the source. The only solutions that I can see require re-mapping to a different scheme which I've been trying to avoid for a "simple" solution. Hmmm, ... give me a couple of hours this morning though, I may have a "simple" re-mapping to fix it... – RBarryYoung Sep 11 '09 at 13:01
  • Dye mixing is subtractive, but many dyes don't actually operate on primary colors. Paint mixing is not subtractive but may be, depending upon the paint, an arbitrary combination of additive, subtractive, and weird-and-wacky. – supercat Jun 11 '12 at 22:34
  • Paint mixing is either subtractive or averaging, depending on what is meant by "mixing". It can never be additive because paint cannot create its own light. (you could argue the point with fluorescence and phosphorescence, but these are ntis). – RBarryYoung Jun 13 '12 at 15:09
  • The mixing we learned is somewhat more like CMYK, since (if you think about it) add a little 'k' and you get red/blue/yellow. Unsurprising that this is the color scheme printers (as far as I know) all use. –  Jul 07 '12 at 13:26
  • I have use this alghoritms to make a [simple test interface](http://stackoverflow.com/a/14596657/848072) It works pretty well! – albfan Jan 30 '13 at 04:25
5

there are two different possibilities combining colors:

  1. additive mixing (like RGB)

  2. subtractive mixing (like CMYK)

So in subtractive color mixing the result is what you expected, but there is no blue, instead there is cyan:

Yellow + cyan = green

In general subtractive color mixing is just "taking away" (filtering) from white while additive color mixing is adding up from black. (base colors of subtractive are inverse from additive: red ->cyan; green->magenta; blue->yellow)

So if you start with white screen applying filters:

min( white (255,255,255), yellow (255,255,0), cyan (0,255,255)) = green (0,255,0)

Peter Parker
  • 26,796
  • 5
  • 47
  • 78
  • What if I try blue as Cyan+Magenta (100%, 100%, 0, 0). When I mix this with yellow, it doesn't seem very realistic and natural. – Tom Pažourek Aug 29 '09 at 13:39
  • 1
    The "rule "yellow+blue=green" is a misconception. You have to mix cyan with yellow to get blue(on subtractive colors). – Peter Parker Aug 29 '09 at 13:49
  • CMYK isn't "right" either. It's an approximation model, just like RBY-. You could perhaps argue that it is "more" right than RBY-. – RBarryYoung Aug 29 '09 at 13:58
  • 1
    @RBarryYoung: CMYK is only an accurate model when applied to inks or dyes which are deliberately formulated so as to make it reasonably accurate. RGB additive synthesis, by contrast, is relatively accurate regardless of whether colors are "pure" or not. – supercat Jun 11 '12 at 22:35
2

There is code to mix colors in a realistic way in krita: https://projects.kde.org/projects/calligra/repository/revisions/master/show/krita/plugins/extensions/painterlyframework.

Note that the code including the illuminants file is GPLv2+. It can convert from RGB to wavelengths, do composition and convert back.

  • Thank you for the link. I've mentioned Krita in my question, I just couldn't find the related source code. But is it really the light wavelength that drives the algorithm? Blue light has wavelength about 475 nm, red light about 650 nm. How are the wavelengths combined to get violet light? It must be working with something more difficult than just light wavelength. I'm sure that the algorithm itself is very complicated and I'm still looking for its, at least brief, explanation. – Tom Pažourek Apr 22 '12 at 17:04
  • You will need to go back to version 2.4.x, it seems that code was removed because it was not maintained. – Ben Holland Feb 12 '13 at 19:25
  • The source is on github now buried in the history: https://github.com/KDE/krita/tree/7036146c5a75e53196a20a3e4232313d796de9d9/krita/plugins/extensions/painterlyframework – CyberFox Nov 26 '19 at 04:04
1

One way to do subtractive mixture of RGB colors is to first convert the RGB colors to spectral reflectance curves. The conversion is fairly simple, and once you've done it, you can do a true subtractive mixture of the reflectance curves, and then convert the result back to RGB. There is another similar question: stackoverflow.com/questions/10254022/, where this process is discussed in more detail.

Community
  • 1
  • 1
Scott Burns
  • 71
  • 1
  • 4
1

Wondering if calculation of inversion of the RGB value work. Since it's about subtraction of lights, technically the subtraction part can be calculated by simple math.

For example cyan + yellow

cyan = 0x00ffff yellow = 0xffff00

Their inversions are 0xff0000 and 0x0000ff, meaning they absorbed red and blue lights completely. Their 1:1 mixture should absorb half of red and blue lights (since the other half of the mixture can still reflects some red and blue light), which is consistent with (0xff0000 + 0x00ffff) / 2 = 0x7f007f. Now we subtract the value from 0xffffff we have 0x80ff80 which is green!

frankli
  • 91
  • 1
  • 3
  • Cyan is a different color. Try mixing blue (0x0000ff) with yellow and you will get grey. If you mix those exact same shades in real world in paint, you'll never get grey. – Tom Pažourek Oct 14 '16 at 12:14
1

I think your problem with combining hues is that you are doing it by adding together the two angles and dividing by two. As you've noticed, the result often makes no sense. I think you'd be better off converting the angles to Cartesian coordinates on the unit circle, averaging those, and finding the angle of the resulting point (ignoring the magnitude).

-1

Check this implementation for additive, substractive and other mixing alghoritms.

Is fully functional (writed in java), so you can test whatever colors you need to mix, and see if it fit your needs.

As other responses pointed, Blue + Yellow (exactly Cyan + Yellow) is Green on substractive CMYK alghoritm. See by yourself

Community
  • 1
  • 1
albfan
  • 10,988
  • 2
  • 49
  • 74
  • Yes, but neither additive, nor subtractive color mixing works well in all cases. Try mixing real blue (#0000ff) and yellow (#ffff00), neither of these two give green. – Tom Pažourek Jan 30 '13 at 13:33
  • So, which is the real blue? This is a real mix http://www.youtube.com/watch?v=OQ0qEBMC5xs of blue and yellow and blue seems cyan in video. don't it? – albfan Feb 01 '13 at 03:36
  • Well the color in the video looks blue and not cyan to me. But that is not the point, even if you mix strong blue with yellow, you won't get grey, but some shade of green. – Tom Pažourek Feb 02 '13 at 19:18