Home-brewed “color spacing”
KeithHandy posted in Coding, Featured Posts, Pretty Pix on December 21st, 2008Note: apparently, not all the code below displays correctly via RSS.
Here’s a home-brewed way to get some of those expensive looking “color aware” effects.

In addition to the original hue/saturation/brightness components, I create six new variables each for hue, saturation, and value (brightness), plus six “weight” values, each corresponding with one of the six colors of a preschooler’s rainbow, ROYGBV (red, orange, yellow, green, blue — fuck “indigo”, but if you wanted me to take it seriously as a color, you should have taught it to me sooner — and violet, even though we called it “purple”):
double h, hueR, hueO, hueY, hueG, hueB, hueV;
double s, satR, satO, satY, satG, satB, satV;
double v, valR, valO, valY, valG, valB, valV;
double wR, wO, wY, wG, wB, wV;
Then at each pixel, you set up the “weight” values depending on what it’s closest to:
wR = wO = wY = wG = wB = wV = 0.0;
if (h >= 0 && h < = 21 ){wO = h /21.0; wR = 1.0 - wO;}
if (h > 21 && h < = 42 ){wY = (h - 21.0 )/21.0; wO = 1.0 - wY;}
if (h > 42 && h < = 85 ){wG = (h - 42.0 )/43.0; wY = 1.0 - wG;}
if (h > 85 && h < = 170){wB = (h - 85.0 )/85.0; wG = 1.0 - wB;}
if (h > 170 && h < = 212){wV = (h - 170.0)/42.0; wB = 1.0 - wV;}
if (h > 212 && h < = 255){wR = (h - 212.0)/43.0; wV = 1.0 - wR;}
Notice that it’s not just selecting one color and going with that; if it’s halfway between red and orange, the red weight would be 0.5, the orange weight would be 0.5, and all the other weights would be zero. After this point in the code, you’re now free to experiment with each value separately. For example, if you want to kill all saturation for the yellow areas, and just turn them grayscale, you would code it this way:
satY = 0;
Similarly, if I want to pump the heck out of the blue areas, I put a line like this:
satB *= 2;
(That’s C++ for “multiply by two”.)
Additionally, I “limit” the red saturation, so that it stays the same up to a point, but doesn’t go any higher; so that skin still looks the same, but bright red ribbons are muted:
if (satR > 96.0) satR = 96;
This example only plays with saturation. I could also mess around with brightness, contrast, etc. in the same way. After this designated “fun sandbox” section is the code that puts together the final values, using the “weight” values:
h = wR*hueR + wO*hueO + wY*hueY + wG*hueG + wB*hueB + wV*hueV;
s = wR*satR + wO*satO + wY*satY + wG*satG + wB*satB + wV*satV;
v = wR*valR + wO*valO + wY*valY + wG*valG + wB*valB + wV*valV;
setpixel(x, y, h, s, v);
I’m not sure exactly how this stacks up against the “color spacing” technology the big companies charge lots of money for, since like I said, it’s based on a Crayola-level color awareness. That considered though, it’s free in both senses of the word… free as in no expensive software to pay for, and free as in freedom to experiment on any of those 18 values with all kinds of math and logic before reducing them back to the original three components.
Much thanks to Darel Rex Finley, since I’m now using his HSP Color Model code to switch the images back and forth between RGB mode and HSP mode. “P” in this case is “perceived brightness”, and more psychovisually accurate than standard “V” or “L” values, but serves the same purpose. Check out his clear and well-illustrated HSP page for an explanation of the difference.





