Compute RGB codes for mixed colors, assuming red, blue, and YELLOW as primary colors

There is a mismatch between light colors and paint: while the physicist says that three primary colors: red, green and blue, the artist will give red, blue and yellow colors as primary colors. Indeed, when drawing with watercolors you cannot mix yellow with red, green and blue, and instead of mixing orange, you will only be brown.

Here's what I am trying to do: from two of the given RGB colors, I would like to calculate the RGB code for the combined color, and I would like the colors to mix, like watercolor, on paper. As I understand it, the calculation will usually look like this:

  • # FF0000 + # 0000FF = # 880088 ((FF + 00) / 2 = 88, (00 + 00) / 2 = 00, (00 + FF) / 2 = 88), so the red and blue colors are magenta (as it should be)
  • # FF0000 + # FFFF00 = # FF8800 ((FF + FF) / 2 = FF, (00 + FF) / 2 = 88, (00 + 00) / 2 = 00), so red and yellow shades give orange (like this should be)

However, when mixing blue and yellow, the result is gray:

  • # 0000FF + # FFFF00 = # 888888 ((00 + FF) / 2 = 88, (00 + FF) / 2 = 88, (FF + 00) / 2 = 88) = GRAY

while on paper you expect to get green (# 008800) and you can never turn gray when mixing colors.

So my question is: how can I exchange green with yellow as the primary color, and how can I then calculate the mixed colors that follow the laws of paint, not the colors of light?

+2
colors
Jan 26 '12 at 21:48
source share
4 answers

There is no simple physical model that will do this; the painter's colors have very complex interactions with light. Fortunately, we have computers that are not limited to modeling the physical world - we can get them to do any arbitrary thing that we need!

The first step is to create a color wheel with the distribution of shades that we need, with red, yellow and blue in increments of 120 degrees. There are many examples on the Internet. I created one here that has only saturated colors, so it can be used to create a full RGB gamut. The colors on the wheel are completely arbitrary; I set orange (60 °) to (255,160,0) because the midpoint between red and yellow was too red, and I moved pure blue (from 0.0255) to 250 ° instead of 240 °, so that 240 ° Blue would be look better.

RYB hue color wheel

Remembering the experiments of my childhood, when you mix the same amount of red, yellow and blue together, you get a fuzzy brownish-gray color. I have chosen a suitable color that you can see in the center of the color wheel; in the code, I affectionately call it "dirt."

To get every conceivable color that you need more than red, yellow and blue, you also need to mix white and black. For example, you get Pink by mixing red and white, and you get Brown by mixing orange (yellow + red) with black.

Conversion works with relationships, not absolute numbers. As with real paint, there is no difference between mixing 1 part red and 1 part yellow, versus 100 parts red and 100 parts yellow.

The code is presented in Python, but it is difficult to convert to other languages. The hardest part is adding red, yellow, and blue to create a hue angle. I use vector addition and convert back to corner with atan2 . Almost everything else is done with linear interpolation (lerp).

 # elementary_colors.py from math import degrees, radians, atan2, sin, cos red = (255, 0, 0) orange = (255, 160, 0) yellow = (255, 255, 0) green = (0, 255, 0) cyan = (0, 255, 255) blue = (0, 0, 255) magenta = (255, 0, 255) white = (255, 255, 255) black = (0, 0, 0) mud = (94, 81, 74) colorwheel = [(0, red), (60, orange), (120, yellow), (180, green), (215, cyan), (250, blue), (330, magenta), (360, red)] red_x, red_y = cos(radians(0)), sin(radians(0)) yellow_x, yellow_y = cos(radians(120)), sin(radians(120)) blue_x, blue_y = cos(radians(240)), sin(radians(240)) def lerp(left, right, left_part, total): if total == 0: return left ratio = float(left_part) / total return [l * ratio + r * (1.0 - ratio) for l,r in zip(left, right)] def hue_to_rgb(deg): deg = deg % 360 previous_angle, previous_color = colorwheel[0] for angle, color in colorwheel: if deg <= angle: return lerp(previous_color, color, angle - deg, angle - previous_angle) previous_angle = angle previous_color = color def int_rgb(rgb): return tuple(int(c * 255.99 / 255) for c in rgb) def rybwk_to_rgb(r, y, b, w, k): if r == 0 and y == 0 and b == 0: rgb = white else: hue = degrees(atan2(r * red_y + y * yellow_y + b * blue_y, r * red_x + y * yellow_x + b * blue_x)) rgb = hue_to_rgb(hue) rgb = lerp(mud, rgb, min(r, y, b), max(r, y, b)) gray = lerp(white, black, w, w+k) rgb = lerp(rgb, gray, r+y+b, r+y+b+w+k) return int_rgb(rgb) 
+5
Feb 02
source share

If you mix red, blue and yellow inks together, you get a dark brown, not black. This is because “red, blue, and yellow” are not really accurate primary colors. Cyan, Magenta and Yellow, so printers work in CMYK (K - black).

So, you are really asking how to convert RGB color to CMYK, in which case any of these links will help you.

+1
Jan 26 2018-12-12T00:
source share

I suggest departing from the concept of primaries, whether it's RGB or RYB or CMY, etc.

As I understand it, your goal is to mix colors (which are described in the RGB color space) in such a way as to mimic how the paint will mix, i.e. offset subtract. Converting from RGB to CMY or CMYK will not be productive, because you still have to deal with the calculation of the subtractive mixture, which is not so easy to do in CMY space.

Instead, let me suggest thinking about converting RGB colors to spectral reflection curves. The conversion is pretty simple, and once you do, you can make a true subtractive mixture of reflection curves and then convert the result back to RGB.

There is one more similar question: https://stackoverflow.com/a/212716/212 where the process is discussed in more detail.

+1
Apr 30 '15 at 11:47
source share

Blue, purple and yellow - this is what should be red, yellow and blue - this is a medieval agreement.

Apparently, this is not a simple switch, and I fell asleep in the middle of mathematics, but here is one way.

RYB RGB Conversion

0
Jan 26 2018-12-12T00:
source share



All Articles