Color Theory References
Lately I've been doing a deep dive into color theory. It's a vast space with wisdom accumulated over centuries, whole libraries full of books, and armies of experts inventing (sometimes conflicting) definitions, crafting competing algorithms, and arguing even over basic principles.
Along the way I've come across a few sources that are particularly useful: insightful, well-written, actionable, and short enough to digest in one sitting.
Here are two:
Subtractive Color Mixture Computation - a 5-part post by Scott Allen Burns
http://scottburns.us/subtractive-color-mixture-1/
What Every Coder Should Know About Gamma - a post by John Novak
https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-...
If any of you have other particularly good color theory links, please reply and post them here. OR if you have any particular things you want to do with color and wish Nodebox could do better, please post those ideas/suggestions here as well.
Perhaps together we can start a thought-provoking conversation and build a useful resource for everyone.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
Support Staff 1 Posted by john on 29 Nov, 2023 01:33 PM
I am going to keep pasting especially good color theory links as I find them.
Mastering Multi-Hued Color Scales by Gregor Aisch:
http://www.vis4.net/blog/mastering-multi-hued-color-scales
A Perceputual Color Space for Image Processing by Björn Ottosson
https://bottosson.github.io/posts/oklab/
How software gets color wrong by Björn Ottosson
https://bottosson.github.io/posts/colorwrong/#what-can-we-do%3F
Chroma.js Interactive Docs
https://gka.github.io/chroma.js/
Hat tip to Nick Rougeux for pointing me to some of these.
Support Staff 2 Posted by john on 04 Dec, 2023 10:18 PM
Here is another helpful color reference:
Math behind colorspace conversions, RGB-HSL by Nikolai Waldman
https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-...
Support Staff 3 Posted by john on 08 Dec, 2023 03:57 AM
Some links about the LCH (or HCL) color space:
LCH is the best color space! by Vojtěch Vidra and Ondřej Pešička
https://atmos.style/blog/lch-color-space
sRGB↔L*a*b*↔LChab conversions by Michał Nazarewicz
https://mina86.com/2021/srgb-lab-lchab-conversions/
A table of useful color conversions by Bruce Lindbloom:
http://www.brucelindbloom.com/index.html?Math.html
HCL color to RGB and backward (Stack Overflow):
https://stackoverflow.com/questions/7530627/hcl-color-to-rgb-and-ba...
Support Staff 4 Posted by john on 11 Dec, 2023 12:09 PM
Easy RGB, code for general purpose color space conversions
http://www.easyrgb.com/en/math.php#text2
5 Posted by florisdejonge on 11 Dec, 2023 06:06 PM
I've been using this one a lot a well to convert values from the image node to plottable inks: https://wizlogo.com/rgb-to-cmyk
Support Staff 6 Posted by john on 12 Dec, 2023 05:09 AM
Thanks for sharing this, Floris.
Interesting. And fairly simple to compute.
Do you think it would be useful enough to be included in my node library?
If so, how would you use it? Would you want it to take in a list of colors and spit out - what? A list of comma-separated CMYK strings? That would be easy enough. And you could then use a make_strings node to turn each comma-separated sting into four individual values.
Or can you think of something else that would save you even more steps? Once you have the CMYK values, what exactly do you do with them? I presume you are not turning them into dots like an inkjet printer. How do "plottable inks" work?
7 Posted by florisdejonge on 12 Dec, 2023 07:19 PM
Hi John,
Attached is an example of how I used that specific calculation. You've made the image-node quite a while ago, and in addition a posterize-node and a plot-node. Those used luma-values if I recall correctly. In this example I used a lookup-node for the RGB-values and wanted to convert them to CMYK.
Since the first one is an additive color model (overlapping colors become white) and the latter an subtractive one (overlapping colors become almost black) this takes some calculations. I found the aformentiond website and this illustration insightful.
So, in the example every color channel in RGB is converted to a value between 0 and 1 for CMYK and Green (could also be between 0 and 255). This values can be used in different ways (with a convert node), and I have. In addition, I found it quite hard to get a sense of green when mixing/overlapping cyan and yellow. Therefore I made a separate Green-node, but I don't know where I found the calculation (I also seem to have changed it a couple of times, it's not the standard green-value from the RGB-channels apparently). I know some people and printers use the other tertiary colors Purple and Orange as well to enhance the color range.
This probably can be improved upon, but I thought it might add to the discussion on color.
Support Staff 8 Posted by john on 15 Dec, 2023 11:00 AM
Floris,
Thanks for joining this discussion!
I already understand how to make a CMYK node (that could convert any color to four CMYK values). What I REALLY want to know is WHY. Why would anyone want such a thing?
I know you've done some work with color plotting...
Given all of this, what kind of computation would be helpful to you from within Nodebox?
As it happens, your interjection into this thread is perfectly timed. I am hoping to finish my new color nodes within the next week so that I can launch v3.3 of my library. And my current focus is color mixing, both additive and subtractive. But it's hard to decide how best to "nodify" this complex area without a really clear handle on the actual use cases people might need them for.
So, again, supposing you had a standard node to produce CMYK values - what exactly would you do with it? And what other color-related things are on your wishlist?
(I know this a TON of questions, so anything at all you can contribute will be much appreciated. And all you other lurkers out there from the NodeBox plotter community - please feel free to jump in!)
Support Staff 9 Posted by john on 15 Dec, 2023 11:43 AM
More well-written color reference links:
How to Generative Art (using plotters):
https://www.dirtalleydesign.com/blogs/news/how-to-generative-art
CMYK: Process Color Experiments and my Axidraw:
https://www.dirtalleydesign.com/blogs/news/cmyk-experimenting-with-...
PANTONE: Understanding Different Color Spaces:
https://www.pantone.com/articles/color-fundamentals/understanding-d...
Blend Modes. (Wikipedia):
https://en.wikipedia.org/wiki/Blend_modes
10 Posted by florisdejonge on 16 Dec, 2023 08:11 AM
Hi John,
Thanks for your reply. These are good questions. I grouped them depending on the answer. I can expand on specific subjects. Hopefully this provides some better insight.
Looking forward to the next update of the library. It's still an indispensable tool in which I still find new possibilities and solutions.
Well, I tried a couple of things. As long as the color calculation yields the right values, one can do a variety of things. For example: if a value is between certain bounds, place one line within a square the size of the pixel, place two lines when it's another value, etc. Lines can differ in length or angle as well. But I've tried to use crosshatch patterns in the same way. And I've used dots/circle (spirals when plotting) sizes depending on color values, etc.
I try to do as much as I can in Nodebox, that's part of the challenge. I sometimes use Photoshop to enhance contrast or something, but that's pretty much it. I used to use vpype for connecting close lines and reorder them. But since I have an Axidraw and am using the Inkscape plugin to reorder paths, I am satisfied with the speed of plotting
Yes, I do. There are indeed two ways: to place different colors close side by side - an optical illusion similar to pointillism, someone called that plottilism :). The other is to draw one layer on top of each other so the inks blend (see example, this consists of 4 ink color). But as I said, I wasn't satisfied with the green sometimes.
This differs with the pen or ink. Posca is opague and doesn't blend. Staedtler Triplus does that quite well, but I tend to limit my use of pens that can't be refilled. Also, the results of the combination of colors are quite garish. I use inks to refill my Rotring pens. There are a little transparent so I can blend them. I can also experiment with different tints. For example: I use brown instead of black and a little orange yellow instead of a bright yellow, cause the colors flow better into each other and the result is a bit warmer. The green ink I currently use is a little to transparent, so I make two passes with it.
Yes. Usually I start with the lightest inks first: yellow, green, red, blue, brown.
I have used colored or grey paper in a mid range tint, and drawn shadow and highlight parts on top of that. With that reasoning one would at least need one color. The maximum is hard to say. I found that when layering inks, the paper gets saturated and will tear or the pen will scratch it and get clogged. But this depends on the density and size of the design and the weight and grain of the paper. But in theory I guess 7: cyan, magenta, yellow, brown/black, green, purple and orange (I called them tertiairy last time, but I meant secondary).
Great question. This is trial and error depending on the brand in my experience. Each manufacturer seams to have it's own naming system. So, a lot comes down to aesthetic preferences and experience I think.
Support Staff 11 Posted by john on 16 Dec, 2023 10:16 AM
Floris,
Thank you very much for these excellent answers! Very helpful.
I'm still not 100% clear, though, on what exactly you would want my new node(s) to do...
First, let me see if I understand how you've used Nodebox in the past to do color mixing.
Is that about it? So in Nodebox what you need is a table that, for each pixel, has pixel position, C amount, M amount, Y amount, maybe more. Is that right?
If so, the CMYK node might be more convenient if it took in a list of colors and positions, then spit out just such a table. That way you could have a single node and just use lookups on the same table to construct each path, with no need to have different nodes for each color, or slice a 4-tupple output into individual streams and have different subtrees for each one. Would such a table output be better for you?
Do you make a separate pass with a black pen, or do pixels filled with lines from the other three colors suffice? If you do use a separate black pass, do you treat it any differently (e.g. skip the other colors for totally black pixels and use only black to fill those)?
The above scenario could be used with either a proximity or an overlay method. For proximity you would use mostly vertical lines to cover pixels in your Cyan path, mostly horizontal lines for you Magenta path, southeast diagonal lines for Yellow and southwest diagonal lines for Black. For the overlay you would use the exact line crossings for every color and rely on the inks to blend appropriately. True? And either way you would use the same CYMK table to construct your paths. Correct?
If you use an extended gamut breakdown of CYMKOGV (adding Orange, Green, Violet) would you then need an option to do a 7-way RGB breakdown instead of a 4-way breakdown? (I haven't yet found the formulas for Orange, Green, Violet, but I assume they are out there somewhere.)
OR, would you ever want the ability to construct an arbitrary breakdown based on whatever pens you want to use? If so, would you define those pen colors by plotting a square with each pen on whatever paper you intend to use, then photograph it and use a color scanning app to get the hex values for each pen color?
Would that be a more general purpose approach that might also result in a more predictable output? I'm guessing the pens you use are not exactly Cyan, Magenta, and Yellow - true?
I'm not yet sure exactly how to calculate values for arbitrary base colors, but I'm guessing I could figure it out. One issue would be that if your arbitrary pen colors are not well balanced, fewer RGB colors could be accurately represented. But this is already true for CMYK (55% of Pantone colors) or even CMYKOGV (90% of Pantone colors). Would you still agree that using actual pen colors would be better than assuming CMYK (if I can do it)?
So far we've been talking about the use case of calculating values to construct each pen path. But perhaps another use case would be trying to predict in advance what the final plot would look like. This could be even more useful if you want to try out different pen color combinations without having to do any test plots. Would you agree?
Doing predictions would be more challenging with the overlay method. I would have to find all the subpaths containing overlaps of two or more colors, then try to predict the resulting blend colors using negative or subtractive mixing formulas. Might be doable (if there are not TOO many pixels).
USING OVERLAPPING CIRCLES INSTEAD OF PIXELS
Speaking of overlays, I was struck by the four ink pen plot you shared with overlapping circles. Were those circles all made using spiral paths? Did you use a compound node to calculate circles with bites missing for each of your four colors?
Did you even need to calculate CMYK values for your overlapping circles? Or did you just do a separate random scatter for each of your four colors with no need for any color calculations?
Even if you didn't need a new color node to do your circles, you might still benefit from some way of predicting what different outputs would look like with a given set of pen colors. In theory, I could use my overlaps node to find all the overlaps and fill each of those regions with the calculated blended color to make a prediction. The problem is that this would quickly bog down for large numbers of general purpose shapes. I would probably need to make some assumptions about the shapes used in order to constrain the computations required. May or may not be feasible.
To sum up...
Do agree that mixing calculations would only be needed for pixel-based frameworks where you need to find how many lines to cross each pixel with for a given color?
Do you agree that a table output would be the best way to make such a node?
Do you treat black differently than other colors?
Would you prefer to input arbitrary pen colors instead of always using CMYK?
Can you think of ways of mixing colors other than pixels or overlapping circles?
Thanks in advance for your patience in answering my endless questions.
12 Posted by florisdejonge on 17 Dec, 2023 01:51 PM
Thanks for the comprehensive response and the new questions. First of all, let me emphasize I didn’t meant to request a new node, I was trying to add to the conversation and show what I made. If you see possibilities for improving that, that’s great. I don’t have specific ideas or wishes, but you often come up with these surprising solutions to making things broader applicable. In regard to the questions, I've grouped them again.
Your conception of the process is correct. Currently, my separate color nodes result in lists of values. But I can imagine a single table could be a better way. But I think there should be a way to control or tweak the resulting values. I was reminded that I sometimes tweak the start or end of the convert node to amplify the effect of a color or some contrast (see example).
I use a convert node to change the list to what I am after: an amount of lines, a size of something, an index value to use with a slice-node, etc. So they can be different shapes. I have used a flow field from the perlin noise code library to dermine the rotation of the lines. See attached example for an impression of how I applied the calculation of CMYGK color (this is bit messy and complex – it takes a while to load).
I make a separate pass with black. I calculate values based on black-/darkness of pixels, but plot it with brown ink (often 2 passes). In theory, the combination of CMY ought to be quite sufficient, but in practice, it isn’t. I don’t skip the other colors, but I find the extra layer of ‘black’ enhances the images. I also sometimes used a higher image quality of the image node with this color to add a bit more of detail in the final layer.
That would be correct in regard to the described scenario. But whether lines ought to be horizontal or an other direction can vary with other scenario’s. So, I don’t think a general solution is available here, because it would limit artistic choices. One would indeed still use the CMYK table to determine those choices.
I think that would be cool: a feature to turn switches with colors on and off and choose a 3, 4, 5 or 7 color breakdown.
That’s a systematic approach, which I really like. I often have the intent to make designs or nodebox networks to make calibration of placement and such easier, but I still haven’t. Right now I am doing a lot based on intuition and just looking at results. I change the coloring within nodebox to get closer to what it would look like on paper. The colorize node is sufficient in that regard. But I like the suggestion to register the values of the actual inks. So yes, I would prefer to input arbitrary pen colors instead of always using CMYK. Because I indeed don’t have exact CMYK inks. But in regard to your other comments, I don’t have to approach the quality and accuracy of a printer with a penplotter. I guess the plotter art has it’s own qualities, which in part lies in chance and imperfections.
I tried different things. I started with spirals, but they were hard to mask. The version I shared was one where ellipses were sorted from the middle and then punched out with a selection with the compound-node. I then filled the remaining parts with a line pattern. And there is some operations to select the different colors and overlap some, but not all, etc.
I hope I replied to all the questions. Especially the one you summarized at the end. I do enjoy these discussions, so if you have any comments, I am looking forward to it.
Support Staff 13 Posted by john on 18 Dec, 2023 11:16 AM
I am still mulling over Floris's interesting response. There may or may not be an opportunity for a truly general purpose node here.
Meanwhile, here is another interesting color reference I came across:
Mixbox: Pigment-Based Color Mixing:
https://scrtwpns.com/mixbox/docs/
The PDF referenced in that link is quite interesting, and shows that it is possible to calculate the way real paints actually mix - up to a point. But it's really, really hard (involving a quasi-Newton least squares optimization solver, a 48 meg lookup table, and much more). These guys developed a software library to do it, but it's nothing I could even begin to replicate in NodeBox.
And another approach to color mixing...
The Magical Tech Behind Paper For iPad’s Color-Mixing Perfection:
https://www.fastcompany.com/3002676/magical-tech-behind-paper-ipads...
A totally different approach based on lots of trial and error. Pretty cool, but, again, nothing I could begin to replicate in NodeBox.
There are LOTS of relatively simple ways to blend or mix RGB colors. None of them simulate what happens when you mix real paint, but they might still have some useful applications. But I need convincing use cases to before I can distill all this into nodes that someone might actually want to use.
I am still thinking and will post again soon.
14 Posted by mr.mr on 19 Dec, 2023 11:01 PM
Hello.
John and Floris! Tonsa things to learn from you guys.
Thank you for florishing this place with wonders.
Tried to open Floris's file and get this error:
java.lang.RuntimeException: Could not load /Users/abdu/Downloads/imagenode_cmyk_flow_example_17122023/imagenode cmyk flow example 17122023.ndbx
at nodebox.client.NodeBoxDocument.load(NodeBoxDocument.java:211)
at nodebox.client.Application.openDocument(Application.java:437)
at nodebox.client.Application$1.done(Application.java:132)
at java.desktop/javax.swing.SwingWorker$5.run(Unknown Source)
at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(Unknown Source)
at java.desktop/sun.swing.AccumulativeRunnable.run(Unknown Source)
at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(Unknown Source)
at java.desktop/javax.swing.Timer.fireActionPerformed(Unknown Source)
at java.desktop/javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Caused by: nodebox.util.LoadException: Error while loading image.py: Library does not exist.
at nodebox.function.PythonLibrary.loadScript(PythonLibrary.java:84)
at nodebox.function.PythonLibrary.loadScript(PythonLibrary.java:52)
at nodebox.function.FunctionLibrary.load(FunctionLibrary.java:37)
at nodebox.node.NodeLibrary.parseLink(NodeLibrary.java:453)
at nodebox.node.NodeLibrary.parseNDBX(NodeLibrary.java:428)
at nodebox.node.NodeLibrary.load(NodeLibrary.java:406)
at nodebox.node.NodeLibrary.load(NodeLibrary.java:92)
at nodebox.client.NodeBoxDocument.load(NodeBoxDocument.java:200)
... 21 more
Any idea to how to open?
Support Staff 15 Posted by john on 20 Dec, 2023 02:25 AM
Dear Mr.mr,
These kind of errors happen whenever a Nodebox file contains an external code library reference with a specific file path reference. The cure is to open the NDBX file in a text editor and remove that file path reference - not hard but you do have to know what to look for...
If you open up image node cmyk flow example 17122023.ndbx in a good text editor like Sublime Text you will find 3 external library references at lines 7-9:
The problem is with the first one, on line 7. We don't want that "../Cartan Node Library 3-0/" part. Remove it, save the file, and open!
Whenever you share a Nodebox file that uses external code libraries, the best practice is as follows:
That's it. Your zipped file will now open without error on other people's computers. It's a slight pain, but once you get used to it, it becomes second nature. The universe will thank you.
(This is one reason I prefer to avoid using external libraries, BTW).
I share all of this for the illumination of the general public. But to save you the bother, I have attached a clean version of Floris's latest file.
John
16 Posted by gabriel sim-lar... on 26 Dec, 2023 07:16 PM
This is all very timely.. and very "firehosey" as in "drinking from the firehose." Timely because I just started walking down the path to color in my code. I didn't have time to read the full discussion closely yet. I'll just add my interest in color nodes. I'm sure my specific uses are very personal and won't necessarily yield some of general use. I am like Floris, always excited to see how the new nodes expand possibilities.
I come from a physical painting background. Specifically underpainting oil in monochrome, then glazing (a very weird process!), and later working more directly with hand-processing of pigments and subtle color relationships. Most of the painting color mixing relationships are incredibly subtle and complex. An example is where we know that the white underneath creates the "light" of a color differently than mixing opaque paint, and because of this we create a lower layer that is tinted with another color. When layers are placed on top, the underlayer shows through transparently, everything is like watercolor where you are effectively dyeing the paper.
Another aspect from physical painting is the idea of shadows being created by complementary (inverted hue) colors. When you mix the inverted red (some green) with the red, it imitates the way the saturation decreases in shadows, while keeping the apparent color of the object the same. Most art and design schools force students to create neutral colors using complementary paints. It's actually very hard to do because the paints are never perfectly inverted hues of each other.
Long story long, I started thinking about mixing colors in my art programming and immediately hit a wall where I could use blend modes (from wikipedia) and even calculate complementary colors, but the brightness of these additive colors is so wildly varying that I never got the effect I was looking for. I found this article
https://alienryderflex.com/hsp.html
about perceptual brightness but have yet to figure out how to implement this in code.
My hope is to be able to layer partly transparent vector shapes of specific colors and simulate how shadows form on a saturated colored object. I'm often trying to bring the tools of observational artwork into code and then let them just be weird, but also have elements of mimicking perception.
I will read this thread more carefully and come back with my questions.
Support Staff 17 Posted by john on 28 Dec, 2023 11:47 PM
Gabriel,
Your reply landed in the spam folder for some reason but I rescued it. Aggravating that this keeps happening.
Really interesting comment! I envy your painterly knowledge. After putting it off for years I finally determined to learn more about color theory and up my game in the Cartan Node Library with a whole set of new and improved color nodes. I am making good progress, but am hampered by my poor understanding of what my fellow artists really need.
Your link was interesting. There are a lot of similar proposed color spaces out there, and different ways of calculating "Luma" values. I've made my own luma node for past projects but am still not sure how useful such a thing would be - whether or not it is "library worthy". I will go back and see if this guy's luma algorithm matches mine or some of the others out there.
I did create an HCL color node for the color space (also known as CLH) at the suggestion of Nick Rougeux, and also included it as an option in my new palette node. It does something similar to your link's HSP color space. I'm pretty happy with it so far; you should check it out and tell me what you think.
I will never be "done" with new color nodes, but am now reaching enough of a critical mass to publish v3.3 of my library with a whole new color section. I hope to do that by New Years Day or shortly thereafter. If you can make a case for a luma node or an inverted hue shadow node or something, now would be the perfect time.
Anyway, please do read more of this thread (I know it's already pretty long) and come back with questions and ideas.
18 Posted by florisdejonge on 06 Apr, 2024 07:36 AM
Hi John,
As a follow-up to this thread: did you in any of the above references came across a calculation to convert RGB values to a Orange or Purple/Violet value in Nodebox?
Support Staff 19 Posted by john on 06 Apr, 2024 10:21 AM
Floris,
No I did not.
Mixing pigments (as opposed to mixing light on computer screens) is very complex, with many factors at play. I found some references to software from certain companies that use secret algorithms to do some conversions in this area for specific paint systems and printers, but nowhere could I find a simple formula to convert RGB to CYMKOGV.
It might be possible to reverse engineer the CMYK formula and the change it to produce approximations for orange, green, and violet. Last Fall I had a vague idea of how to approach that, but I have since forgotten most of that. It would take me awhile to get my head back into that space, but maybe I'll take another run at it.
Even if I could come up with a formula, I'm not confident you could use it with your pens and paper to produce predictable results. I'm not even sure how I would test it. At best I could maybe contribute part of a framework that you could then use to experiment with.
Heading to bed. I'll think about it in the morning.
20 Posted by florisdejonge on 07 Apr, 2024 05:27 PM
Thanks John. I did a quick search. I think I'll will look into this whether that's a viable direction:
Source
Support Staff 21 Posted by john on 07 Apr, 2024 11:50 PM
Floris,
This is a major find! Thanks!
I was particularly interest in this paper on the RYB color space referenced in one of the comments:
http://nishitalab.org/user/UEI/publication/Sugita_IWAIT2015.pdf
Last Fall I spent a month getting my head into color space, then allowed that house of cards to collapse in the new year. Reconstructing my earlier understanding may take a little time (and I have a guest visiting next week who will distract me further). But I am excited to start playing with what looks to be a dramatically simpler way of doing more effective and intuitive subtractive blending.
I did leave some notes to myself with an idea for a more general purpose posterize node - which should have some applications to what you are doing. That's another thing I plan to take up again soon.