Posts tagged ‘convert’

Red-Green-Blue To Red-Yellow-Blue - Part 1

I already solved this once, a long while back.  And it was handy code to have.  But unfortunately I lost the code.  So now I’m re-solving the problem.  How do you convert from a red-green-blue color scheme (that typically used by computers) into a red-yellow-blue “primary colors” color scheme (that typically used by artists)?

I guess I should explain why this is useful.  From the time we’re born our mommies and daddies give us primary colors of red, yellow, and blue.  And we know that yellow and blue make green.  And that the opposite of red is green.  They’re complementary colors.  Anyone who has ever painted, drawn, etc. knows it.  Anyone who has ever taken even a basic art class knows it.  Heck, anyone who’s ever peed into a toiled filled with blue water knows it.  Primary and secondary colors are all around us.  From the day we’re born to the day we die, it’s the color system we know like the backs of our hands.

But those of us who have done graphics work on computers know that colors don’t work that way … on a computer.  Computers don’t use this color system.  Computers use a red, green, and blue color system.  It’s based on light wavelengths.  Red plus green makes yellow.  The opposite color of red is cyan, not green.  (Hence the other related color system based on the opposites of rgb: cyan, magenta, and yellow or cmy.)  It makes sense to anyone who understands light wavelengths, like a scientist.  But to a graphical artist trying to do work on a computer it can be downright confusing if not insanely ludicrous.  I mean just try taking your painting and doing a color inversion.  It doesn’t come out anything like you’d expect.  Your years of artistic knowledge completely fail you when you hop onto a computer.  All because computer monitors are based on light, so computers have always, from the very beginning, been designed in a way to display the proper images on your monitor; not to help you paint a picture.

Now you’d think that every graphics program ever written would therefor have a way to switch from the rgb color system to the ryb color system, because surely graphical artists use graphics programs, right?

Strangely, I’ve yet to see it.  Granted, it’s been a while since I looked at the biggies like Photoshop and Paint Shop Pro (I have used both in the past).  These days I’ve been using GIMP, because it’s free, and once you get used to the eccentricities, it’s darn near as good as Photoshop at nearly everything.

But where I’ve really needed it is in writing GUIs.  Say you’ve got a GUI where you’re describing a crystal.  You want a way to pick the crystal’s color.  You make buttons to choose colors.  Well the names of the colors on the buttons is great, but wouldn’t it be even neater to colorize the buttons themselves?  It’s easy enough to do.  (At least when using Trolltech’s Qt.  MFC makes it a tad more of a challenge.)  So you set the background color of the button widgets to the color defined by the button text.  It’s insanely easy, and pretty effective … for most colors.  But then there’s that nagging problem, some background colors make black text kind of hard to read.  Especially, you know, black.  Black on black is a bit of a challenge to read.  So you want to make the text always a good color.

Now, you can write an algorithm to calculate the luminosity of the rgb value and determine if white or black would contrast more against the button.  Which works.  But it’s kind of a … kluge.  It doesn’t look nearly as professional as it should.

So you take it one step further.  You use an algorithm to get the contrasting color of the rgb value.  It works.  But looks positively awful.  Because scientifically we know the opposing light wavelength to red is cyan, artistically, our whole life tells us that the opposite color of red is green.  And so the rgb-inverse method grates on our sensibilities.  It makes for readable text, but psychologically drives us nuts.

Which is what brings us to the ultimate solution: a rgb to ryb color system change.  Because once we work in an ryb color system, then the inverse of red really is green.  It does wonders for our GUIs, making the text readable and comforting in its simple “rightness”.  And maybe one day it’ll bring relief to graphical artists on computers when you can switch from rgb to ryb in GIMP or Photoshop and suddenly everything makes sense.

So that’s the explanation.  What’s the solution?  I did it once before.  I know I can solve it again.  Here’s what I’ve got so far just scrawling on some paper:

Step 1: Remove the luminosity.   I remember this clearly.  I remember in my first attempt at solving this years back, it took me a while to figure out that you really absolutely need to do this first and foremost, or else your colors will come out in all of the wrong shades.  This part is simple.  Given that red, green, and blue are input variables for your rgb color that you’re converting into an ryb system:


white = min(red, green, blue)
red -= white
green -= white
blue -= white

Now your rgb values contain no white value in them.  You’re working on converting pure color.  So you can take the next step, determining how much raw yellow there is, and how much of the green value is actually representative of the color green:


yellow_part = min(red, green) # In rgb red and green combine in equal parts to make yellow.  So we have to determine how much yellow there is.
green_part = max(0, green - yellow_part) # Now that we know how much yellow there is, we can take the raw yellow away from the green value to determine how much raw green is truly in the green value.

This next step I haven’t tested out yet.  I know that I’m not 100% certain that it’s a final solution because I know that at the very least I haven’t normalized the end values back into the proper scale.  What do I mean?  Well in an ryb system green is essentially yellow plus blue.  But we also have a blue value.  So in a worst-case scenario, we have a maximum blue value of 1/2 green plus blue.  In OpenGL where you’ve got a component scale of 1.0 maximum in rgb, this means blue could have a maximum value of 1.5 in ryb.  So you’ve got to re-scale the values after converting their components.  As I said, I don’t have that worked into the formula yet, but I do have part of the formula:


half_green = green_part / 2 # We know that green needs to be divided into equal parts of blue and yellow, so to optimize the code we calculate half of the remaining green component.
red = red - yellow_part
yellow = yellow_part + half_green
blue = blue + half_green

So at this point you should have the raw component color parts of a red, yellow, and blue color system.  Next up is normalizing the values back to the same scale as was used in the rgb system, and then putting the luminosity back in by re-adding the white value.  Do this and you should be done converting rgb to ryb.  Sometime when I get around to reinstalling Python + PyQt and/or some version of Visual Studio on my computer I may even get around to finishing the conversion code (and testing) in a follow-up Part 2 blog entry.