BEEPS AND BLIPS FROM OUTERSPACE
GENERATE N DISTINCT COLORS
colorsWhile working on a project I realized I needed to generate a specific number of colors that are visually distinct from each other so that when two colors are side-by-side, the viewer can tell they are different.  In my case, the players (of a game I am working on) need to pick a piece color so they can't be confused by another player's pieces.One could argue about what "visually distinct color" means since the human eye/brain perceives a linear hue gradient (aka rainbow) in bands.  Even a linear change in a single color is seen in bands (sudden changes of shade or saturation).  There is also the issue with color blindness...I ignored all those "what-abouts" and "what ifs" out since I wanted something quick and dirty... something finished and useful.  So, I decided to slice up the RGB color space.  Sure, I could have messed with HSL or HSV, but using RGB does the trick just fine......continued (explanation and source code)There are three channels to RGB, which unsurprisingly are Red, Green, and Blue.  An RGB number can be represented in Hexadecimal like so: #3CA6FF.  What my algorithm does is vary each channel value in large jumps.Start with each channel supporting two values: 00 and FF.  If we vary each channel with these values we get 8 different colors (2 values per channel for 3 channels: 2*2*2 or 2^3):
  1. 000000
  2. 0000FF
  3. 00FF00
  4. 00FFFF
  5. FF0000
  6. FF00FF
  7. FFFF00
  8. FFFFFF
If we need more then 8 colors we need to add another value to each channel.  Say we want 3 values: 00, 80, FF.  This means we can then have 27 colors (3*3*3).  Here's a sample of some of the values:
  1. 000000
  2. 000080
  3. 80FF00
  4. 808080
  5. FF80FF
  6. ...
Now, let's look at it from reverse.  If you need N colors, you will then need  ceil(N^(1/3)) values per channel.  It might be easier to read this as "take the cube root of N then round up".  For example, if you want 32 colors then you will need 4 values per channel.There is a potential problem when generating these numbers programatically.  If you use simple loops then you will most likely be iterating over one channel more often than the others.  This is bad if you only a subset of all possible colors (32 of the 64 colors when using 4 values per channel).  This means your red channel probably won't get a chance to contribute and all your colors will have blue and some green tints.
# this is pseudo code
total = 0
for red in range(4):
  for green in range(4):
    for blue in range(4):
      if total <= N:
        print color(red, green, blue)
      total += 1
Not only that, but your list will include more of the less-distinct colors.  For example, there isn't much difference between #000033 and #000000 or #66CC99 and #99CC99.  It would be better to include #FF0000 before including values that are "close" to each other.So, the python code included is an attempt to output colors that are more distinct first.  Take a look at these samples (generated with colortohtml.py).  You'll notice that the lower the N, the more distinct the color set is. The code is not perfect (or efficient), but it does get the job done.  I've put it in the public domain, so feel free to use the source code.
POSTED • 2011-09-16 16:52:00 • CATEGORY • ENGINEERING • TAGS • COLORPYTHON
comments powered by Disqus