Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithm for finding the color between two others - in the colorspace of painted colors

When mixing blue and yellow paint, the result is some sort of green.

I have two rgb colors:

blue = (0, 0, 255)

and yellow = (255, 255, 0)

What is the algorithm for finding the rgb color that is the result of mixing the two colors, as they would appear when using paint? The resulting colors from the algorithm does not have to be terribly exact. For the example above it would only have to look like some sort of green.

Thanks in advance.

Edit: This function, written in Go, worked for me, based on the answer from LaC.

func paintMix(c1, c2 image.RGBAColor) image.RGBAColor {      r := 255 - ((255 - c1.R) + (255 - c2.R))     g := 255 - ((255 - c1.G) + (255 - c2.G))     b := 255 - ((255 - c1.B) + (255 - c2.B))     return image.RGBAColor{r, g, b, 255} } 

Edit #2 Allthought this manages to mix cyan and yellow, the mix between blue and yellow becomes black, which doesn't seem right. I'm still looking for a working algorithm.

Edit #3 Here's a complete working example in Go, using the HLS colorspace: http://go.pastie.org/1976031. Thanks Mark Ransom.

Edit #4 It seems like the way forward for even better color mixing would be to use the Kubelka-Munk equation

like image 862
Alexander Avatar asked May 25 '11 20:05

Alexander


2 Answers

Paint works by absorption. You start with white light (255,255,255) and multiply it by the absorption factors.

Blue paint absorbs all red and green light that hits it.

Yellow paint absorbs all blue light that hits it.

In a perfect world, that means that combining yellow and blue paint would result in black paint, or at best a muddy gray. In practice the "blue" paint has a bias towards green, so you get a muddy green. I've never seen an example of mixing yellow and blue that produces a satisfactory green. Wikipedia goes into some of the complexities of this process: http://en.wikipedia.org/wiki/Primary_color#Subtractive_primaries

I think what you are really asking is how to interpolate colors along a color wheel. This should be independent of whether the colors are absorptive as in paint, or emissive as in RGB displays.

Edit: By working in the HSL color space you can get the kind of results you're looking for. Here's some code in Python that implements the algorithm; averaging hues is tricky, and is based on a previous answer of mine for averaging angles.

from colorsys import rgb_to_hls,hls_to_rgb from math import sin,cos,atan2,pi  def average_colors(rgb1, rgb2):     h1, l1, s1 = rgb_to_hls(rgb1[0]/255., rgb1[1]/255., rgb1[2]/255.)     h2, l2, s2 = rgb_to_hls(rgb2[0]/255., rgb2[1]/255., rgb2[2]/255.)     s = 0.5 * (s1 + s2)     l = 0.5 * (l1 + l2)     x = cos(2*pi*h1) + cos(2*pi*h2)     y = sin(2*pi*h1) + sin(2*pi*h2)     if x != 0.0 or y != 0.0:         h = atan2(y, x) / (2*pi)     else:         h = 0.0         s = 0.0     r, g, b = hls_to_rgb(h, l, s)     return (int(r*255.), int(g*255.), int(b*255.))  >>> average_colors((255,255,0),(0,0,255)) (0, 255, 111) >>> average_colors((255,255,0),(0,255,255)) (0, 255, 0) 

Note that this answer does not emulate paint mixing, for the reasons stated above. Rather it gives an intuitive mixing of colors that is not grounded in any physical world reality.

like image 182
Mark Ransom Avatar answered Sep 29 '22 15:09

Mark Ransom


Actually, you get green from mixing (subtractively) yellow and cyan. Yellow is red + green (255, 255, 0), cyan is green + blue (0, 255, 255). Now make their opposite colors: blue (0, 0, 255) and red (255, 0, 0). Mix them additively and you get purple (255, 0, 255). Make its opposite and you get green (0, 255, 0).

In other words, you can get a subtractive mix as the opposite of the additive mix of the opposites of your two colors.

like image 42
LaC Avatar answered Sep 29 '22 15:09

LaC