Algorithms to produce unique colour depending based on index - algorithm

All,
Are there any nice algorithms out there to generate a unique colour based on index in an array?
This is of course going to be used in a UI, to set the background colour of a number of dynamic buttons.
Now with .Net (and Java off top of my head), the following methods are supported:
Color.FromArgb
Color.FromName
FromArgb can take an 32-bit integer containing the argb color.
However, the algorithmic approach might cause some colours to be too similar in order, depending upon how many items were in the array. And also, where the foreground colour is similar to the background.
The only way I can think of is to create some kind of Color array, with a set of predefined colours in. Off course, this is manual code effort, but this way you can get a different set of colours in a small range that can be visually different from each other, before repeating sequence towards the end.
The other way could be to use the following to generate the array of colours:
Enum.GetValues(typeof(KnownColor)
Any suggestions?
Cheers

Hash the index, and take the lower 32 bits of the hash for your color. This will appear random but should produce a uniform distribution of colors. Will not guarantee that the chosen colors will be visually different from each other or the background, but may serve.
You could also take the whole color spectrum, cut it into n evenly intervaled colors, and assign them to each element of the array, assuming that you know the size of the array.
https://stackoverflow.com/a/43235/684934 might also give good ideas.

RGB-colors form a 3D-cube of color-space. Begin by selecting the corners of this cube (0 or 255 values). Then subdivide the cube into a grid of 8 cubes, and take the newly formed vertices. Subdivide again, into 64 cubes, and take the newly formed vertices. This will give you progressively closer and closer colors for higher indices.
IEnumerable<Color> GeneratePalette()
{
for (int scale = 1; scale < 256; scale *= 2)
{
for (int r = 0; r <= scale; r++)
for (int g = 0; g <= scale; g++)
for (int b = 0; b <= scale; b++)
{
if (scale == 1 || (r & 1) == 1 || (g & 1) == 1 || (b & 1) == 1)
{
yield return new Color
{
A = 255,
R = (byte) (255 * r / scale),
G = (byte) (255 * g / scale),
B = (byte) (255 * b / scale),
};
}
}
}
}
The first few colors:
#FF000000
#FF0000FF
#FF00FF00
#FF00FFFF
#FFFF0000
#FFFF00FF
#FFFFFF00
#FFFFFFFF
#FF00007F
#FF007F00
#FF007F7F
#FF007FFF
...
#FFFF7FFF
#FFFFFF7F
#FF00003F

Related

How does this MATLAB code make an image into a binary image?

v = videoinput('winvideo', 1, 'YUY2_320x240');
s = serial('COM1', 'BaudRate', 9600);
fopen(s);
while(1)
h = getsnapshot(v);
rgb = ycbcr2rgb(h);
for i = 1:240
for j = 1:320
if rgb(i,j,1) > 140 && rgb(i,j,2) < 100 % use ur own conditions
bm(i, j) = 1;
else
bm(i, j) = 0;
end
end
end
This is the code i got from my senior regarding image processing using MATLAB. The above code is to convert the image to binary image, But in the code rgb(i, j, 1) > 140 I didn't understand that command. How to select that 140 and what does that rgb(i, j, 1) mean?
You have an RGB image rgb where the third dimension are the RGB color planes. Thus, rgb(i,j,1) is the red value at row i, column j.
By doing rgb(i,j,1)>140 it tests if this red value is greater than 140. The value 140 appears to be ad hoc, picked for a specific task.
The code is extremely inefficient as there is no need for a loop:
bm = rgb(:,:,1)>140 & rgb(:,:,2)<100;
Note the change from && to the element-wise operator &. Here I'm assuming that the size of rgb is 240x320x3.
Edit: The threshold values you choose completely depend on the task, but a common approach to automatic thresholding is is Otsu's method, graythresh. You can apply it to a single color plane to get a threshold:
redThresh = graythresh(rgb(:,:,1)) * 255;
Note that graythresh returns a value on [0,1], so you have to scale that by the data range.

Efficient Fast Color Extraction Emgucv

So I'm new to image processing, and i'm kinda learning emgucv right now..
..I want to track a Ball with a specific color- orange.. however..
so..what i needed was to threshold, isolate , or binarize (i don't know the right term).. the image to retain a gray image of white and black. the white being the orange colors and black the non-orange.. (sorry if this sounds kinda dumb).. there are however many considerations when binarizing an image... the shadows.. the shades of oranges...
i'm confused as to what is the best function to use..
i've tried the inRange function for Image..
imgProcessed = imgOriginal.InRange(mincolor,maxcolor);
howver,.. i find it slow..and i can't really binarize all of the ball.. (from dark oranges to light oranges).. plus i gotta adjust the values everytime light conditions changes.. are there any ways to get "all" or atleast "most" of the shades of orange? Sorry..newbie here...I'd appreciate any help..code is not necessary..thanks!:D
there are so many functions to use.. HSV.. inrange.. cvthreshold..what are the best waY? will using hsv rather than bgr be faster?
I have done this. I gave up on the OpenCV functions and did the math by hand. Here is my code:
for (i = 0; i < rows; i = i + step)
{
for (j = 0; j < cols; j = j + step)
{
closestprimary = new Bgr(0, 0, 0);
currentcolor = ImageFrame[i, j];
B = (int)currentcolor.Blue;
G = (int)currentcolor.Green;
R = (int)currentcolor.Red;
//hue = atan2(sqr(3) * (G - B), 2 * R - G - B)
hue = ((Math.Atan2(1.732050808 * (double)(G - B), (double)(2 * R - G - B)) * 57.295779513) + 360) % 360; ;
//find closest primary hue (60 degree)
if (hue >= 15 && hue < 50) {
closestprimary = new Bgr(0, 127, 255); } //orange - sorta had to eyeball this one /shrug
ImageFrame[i, j] = closestprimary;//set new color
}
}
Hopefully you can see how the orange hue is between 15 and 50, and can change the numbers to whatever you want to get whatever color you wish.
http://johndyer.name/lab/colorpicker/
helped me in deciding hues. (look at the top number, by the 'H')

How to get intermediate colors from one to another? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
android color between two colors, based on percentage?
How to find all the colors between two colors?
At the beginning, we have two colors in RGB, and a number, for the intermediate colors between them. Method must return an array with required colors. Strongly need help with an algorithm.
Suppose we have 2 Colors (R1,G1,B1) (R2,G2,B2) and N number of intermediate colors:
for i from 1 to N:
Ri = R1 + (R2-R1) * i / N
Bi = B1 + (B2-B1) * i / N
Gi = G1 + (G2-G1) * i / N
AddToArray(Ri,Gi,Bi)
Is that what you are looking for?
PS: I would recommend using the HSL color space instead of the RGB if you want to have a more natural color gradient.
Let your current cR, cG and cB value be 0%, and let the R, G, and B values be 100%, then you just have to iterate i = 1 to 100 with each iteration adding cRGB + i * (RGB - cRGB). You don't have to use 100 intermediate colors, you can use N of them.
function(currentColor, desiredColor, N) {
var colors = [],
cR = currentColor.R,
cG = currentColor.G,
cB = currentColor.B,
dR = desiredColor.R - cR,
dG = desiredColor.G - cG,
dB = desiredColor.B - cB;
for(var i = 1; i <= N; i++) {
colors.push(new Color(cR + i * dR / N, cG + i * dG / N, cB + i * dB / N));
}
return colors;
}
However, that won't give you very good intermediate colors. The first thing you should do is convert your colors into HSV or similar colorspace where intensity is separate from hue and saturation. That will give you much better intermediate colors. http://en.wikipedia.org/wiki/HSL_and_HSV
To do that, first convert your colors to HSV, and run the same algorithm as above, but with H S and V instead of RGB, but keep in mind that S and V have a min of 0 and max of 1, while H is represented in degrees between 0 and 360. You might have to do something with H if you want it to go from the current color to destination color as quickly as possible e.g. if cH = 10 and dH = 50, then going from 10 -> 50 is shortest, but if cH = 10 and dH = 350, then going from 10 -> -10 (same as 350 degrees) is shorter.

Programmatically Lighten a Color

Motivation
I'd like to find a way to take an arbitrary color and lighten it a few shades, so that I can programatically create a nice gradient from the one color to a lighter version. The gradient will be used as a background in a UI.
Possibility 1
Obviously I can just split out the RGB values and increase them individually by a certain amount. Is this actually what I want?
Possibility 2
My second thought was to convert the RGB to HSV/HSB/HSL (Hue, Saturation, Value/Brightness/Lightness), increase the brightness a bit, decrease the saturation a bit, and then convert it back to RGB. Will this have the desired effect in general?
As Wedge said, you want to multiply to make things brighter, but that only works until one of the colors becomes saturated (i.e. hits 255 or greater). At that point, you can just clamp the values to 255, but you'll be subtly changing the hue as you get lighter. To keep the hue, you want to maintain the ratio of (middle-lowest)/(highest-lowest).
Here are two functions in Python. The first implements the naive approach which just clamps the RGB values to 255 if they go over. The second redistributes the excess values to keep the hue intact.
def clamp_rgb(r, g, b):
return min(255, int(r)), min(255, int(g)), min(255, int(b))
def redistribute_rgb(r, g, b):
threshold = 255.999
m = max(r, g, b)
if m <= threshold:
return int(r), int(g), int(b)
total = r + g + b
if total >= 3 * threshold:
return int(threshold), int(threshold), int(threshold)
x = (3 * threshold - total) / (3 * m - total)
gray = threshold - x * m
return int(gray + x * r), int(gray + x * g), int(gray + x * b)
I created a gradient starting with the RGB value (224,128,0) and multiplying it by 1.0, 1.1, 1.2, etc. up to 2.0. The upper half is the result using clamp_rgb and the bottom half is the result with redistribute_rgb. I think it's easy to see that redistributing the overflows gives a much better result, without having to leave the RGB color space.
For comparison, here's the same gradient in the HLS and HSV color spaces, as implemented by Python's colorsys module. Only the L component was modified, and clamping was performed on the resulting RGB values. The results are similar, but require color space conversions for every pixel.
I would go for the second option. Generally speaking the RGB space is not really good for doing color manipulation (creating transition from one color to an other, lightening / darkening a color, etc). Below are two sites I've found with a quick search to convert from/to RGB to/from HSL:
from the "Fundamentals of Computer Graphics"
some sourcecode in C# - should be easy to adapt to other programming languages.
In C#:
public static Color Lighten(Color inColor, double inAmount)
{
return Color.FromArgb(
inColor.A,
(int) Math.Min(255, inColor.R + 255 * inAmount),
(int) Math.Min(255, inColor.G + 255 * inAmount),
(int) Math.Min(255, inColor.B + 255 * inAmount) );
}
I've used this all over the place.
ControlPaint class in System.Windows.Forms namespace has static methods Light and Dark:
public static Color Dark(Color baseColor, float percOfDarkDark);
These methods use private implementation of HLSColor. I wish this struct was public and in System.Drawing.
Alternatively, you can use GetHue, GetSaturation, GetBrightness on Color struct to get HSB components. Unfortunately, I didn't find the reverse conversion.
Convert it to RGB and linearly interpolate between the original color and the target color (often white). So, if you want 16 shades between two colors, you do:
for(i = 0; i < 16; i++)
{
colors[i].R = start.R + (i * (end.R - start.R)) / 15;
colors[i].G = start.G + (i * (end.G - start.G)) / 15;
colors[i].B = start.B + (i * (end.B - start.B)) / 15;
}
In order to get a lighter or a darker version of a given color you should modify its brightness. You can do this easily even without converting your color to HSL or HSB color. For example to make a color lighter you can use the following code:
float correctionFactor = 0.5f;
float red = (255 - color.R) * correctionFactor + color.R;
float green = (255 - color.G) * correctionFactor + color.G;
float blue = (255 - color.B) * correctionFactor + color.B;
Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue);
If you need more details, read the full story on my blog.
Converting to HS(LVB), increasing the brightness and then converting back to RGB is the only way to reliably lighten the colour without effecting the hue and saturation values (ie to only lighten the colour without changing it in any other way).
A very similar question, with useful answers, was asked previously:
How do I determine darker or lighter color variant of a given color?
Short answer: multiply the RGB values by a constant if you just need "good enough", translate to HSV if you require accuracy.
I used Andrew's answer and Mark's answer to make this (as of 1/2013 no range input for ff).
function calcLightness(l, r, g, b) {
var tmp_r = r;
var tmp_g = g;
var tmp_b = b;
tmp_r = (255 - r) * l + r;
tmp_g = (255 - g) * l + g;
tmp_b = (255 - b) * l + b;
if (tmp_r > 255 || tmp_g > 255 || tmp_b > 255)
return { r: r, g: g, b: b };
else
return { r:parseInt(tmp_r), g:parseInt(tmp_g), b:parseInt(tmp_b) }
}
I've done this both ways -- you get much better results with Possibility 2.
Any simple algorithm you construct for Possibility 1 will probably work well only for a limited range of starting saturations.
You would want to look into Poss 1 if (1) you can restrict the colors and brightnesses used, and (2) you are performing the calculation a lot in a rendering.
Generating the background for a UI won't need very many shading calculations, so I suggest Poss 2.
-Al.
IF you want to produce a gradient fade-out, I would suggest the following optimization: Rather than doing RGB->HSB->RGB for each individual color you should only calculate the target color. Once you know the target RGB, you can simply calculate the intermediate values in RGB space without having to convert back and forth. Whether you calculate a linear transition of use some sort of curve is up to you.
Method 1: Convert RGB to HSL, adjust HSL, convert back to RGB.
Method 2: Lerp the RGB colour values - http://en.wikipedia.org/wiki/Lerp_(computing)
See my answer to this similar question for a C# implementation of method 2.
Pretend that you alpha blended to white:
oneMinus = 1.0 - amount
r = amount + oneMinus * r
g = amount + oneMinus * g
b = amount + oneMinus * b
where amount is from 0 to 1, with 0 returning the original color and 1 returning white.
You might want to blend with whatever the background color is if you are lightening to display something disabled:
oneMinus = 1.0 - amount
r = amount * dest_r + oneMinus * r
g = amount * dest_g + oneMinus * g
b = amount * dest_b + oneMinus * b
where (dest_r, dest_g, dest_b) is the color being blended to and amount is from 0 to 1, with zero returning (r, g, b) and 1 returning (dest.r, dest.g, dest.b)
I didn't find this question until after it became a related question to my original question.
However, using insight from these great answers. I pieced together a nice two-liner function for this:
Programmatically Lighten or Darken a hex color (or rgb, and blend colors)
Its a version of method 1. But with over saturation taken into account. Like Keith said in his answer above; use Lerp to seemly solve the same problem Mark mentioned, but without redistribution. The results of shadeColor2 should be much closer to doing it the right way with HSL, but without the overhead.
A bit late to the party, but if you use javascript or nodejs, you can use tinycolor library, and manipulate the color the way you want:
tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"
I would have tried number #1 first, but #2 sounds pretty good. Try doing it yourself and see if you're satisfied with the results, it sounds like it'll take you maybe 10 minutes to whip up a test.
Technically, I don't think either is correct, but I believe you want a variant of option #2. The problem being that taken RGB 990000 and "lightening" it would really just add onto the Red channel (Value, Brightness, Lightness) until you got to FF. After that (solid red), it would be taking down the saturation to go all the way to solid white.
The conversions get annoying, especially since you can't go direct to and from RGB and Lab, but I think you really want to separate the chrominance and luminence values, and just modify the luminence to really achieve what you want.
Here's an example of lightening an RGB colour in Python:
def lighten(hex, amount):
""" Lighten an RGB color by an amount (between 0 and 1),
e.g. lighten('#4290e5', .5) = #C1FFFF
"""
hex = hex.replace('#','')
red = min(255, int(hex[0:2], 16) + 255 * amount)
green = min(255, int(hex[2:4], 16) + 255 * amount)
blue = min(255, int(hex[4:6], 16) + 255 * amount)
return "#%X%X%X" % (int(red), int(green), int(blue))
This is based on Mark Ransom's answer.
Where the clampRGB function tries to maintain the hue, it however miscalculates the scaling to keep the same luminance. This is because the calculation directly uses sRGB values which are not linear.
Here's a Java version that does the same as clampRGB (although with values ranging from 0 to 1) that maintains luminance as well:
private static Color convertToDesiredLuminance(Color input, double desiredLuminance) {
if(desiredLuminance > 1.0) {
return Color.WHITE;
}
if(desiredLuminance < 0.0) {
return Color.BLACK;
}
double ratio = desiredLuminance / luminance(input);
double r = Double.isInfinite(ratio) ? desiredLuminance : toLinear(input.getRed()) * ratio;
double g = Double.isInfinite(ratio) ? desiredLuminance : toLinear(input.getGreen()) * ratio;
double b = Double.isInfinite(ratio) ? desiredLuminance : toLinear(input.getBlue()) * ratio;
if(r > 1.0 || g > 1.0 || b > 1.0) { // anything outside range?
double br = Math.min(r, 1.0); // base values
double bg = Math.min(g, 1.0);
double bb = Math.min(b, 1.0);
double rr = 1.0 - br; // ratios between RGB components to maintain
double rg = 1.0 - bg;
double rb = 1.0 - bb;
double x = (desiredLuminance - luminance(br, bg, bb)) / luminance(rr, rg, rb);
r = 0.0001 * Math.round(10000.0 * (br + rr * x));
g = 0.0001 * Math.round(10000.0 * (bg + rg * x));
b = 0.0001 * Math.round(10000.0 * (bb + rb * x));
}
return Color.color(toGamma(r), toGamma(g), toGamma(b));
}
And supporting functions:
private static double toLinear(double v) { // inverse is #toGamma
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}
private static double toGamma(double v) { // inverse is #toLinear
return v <= 0.0031308 ? v * 12.92 : 1.055 * Math.pow(v, 1.0 / 2.4) - 0.055;
}
private static double luminance(Color c) {
return luminance(toLinear(c.getRed()), toLinear(c.getGreen()), toLinear(c.getBlue()));
}
private static double luminance(double r, double g, double b) {
return r * 0.2126 + g * 0.7152 + b * 0.0722;
}

Function for creating color wheels [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
This is something I've pseudo-solved many times and have never quite found a solution for.
The problem is to come up with a way to generate N colors, that are as distinguishable as possible where N is a parameter.
My first thought on this is "how to generate N vectors in a space that maximize distance from each other."
You can see that the RGB (or any other scale you use that forms a basis in color space) are just vectors. Take a look at Random Point Picking. Once you have a set of vectors that are maximized apart, you can save them in a hash table or something for later, and just perform random rotations on them to get all the colors you desire that are maximally apart from each other!
Thinking about this problem more, it would be better to map the colors in a linear manner, possibly (0,0,0) → (255,255,255) lexicographically, and then distribute them evenly.
I really don't know how well this will work, but it should since, let us say:
n = 10
we know we have 16777216 colors (256^3).
We can use Buckles Algorithm 515 to find the lexicographically indexed color.. You'll probably have to edit the algorithm to avoid overflow and probably add some minor speed improvements.
It would be best to find colors maximally distant in a "perceptually uniform" colorspace, e.g. CIELAB (using Euclidean distance between L*, a*, b* coordinates as your distance metric) and then converting to the colorspace of your choice. Perceptual uniformity is achieved by tweaking the colorspace to approximate the non-linearities in the human visual system.
Some related resources:
ColorBrewer - Sets of colours designed to be maximally distinguishable for use on maps.
Escaping RGBland: Selecting Colors for Statistical Graphics - A technical report describing a set of algorithms for generating good (i.e. maximally distinguishable) colour sets in the hcl colour space.
Here is some code to allocate RGB colors evenly around a HSL color wheel of specified luminosity.
class cColorPicker
{
public:
void Pick( vector<DWORD>&v_picked_cols, int count, int bright = 50 );
private:
DWORD HSL2RGB( int h, int s, int v );
unsigned char ToRGB1(float rm1, float rm2, float rh);
};
/**
Evenly allocate RGB colors around HSL color wheel
#param[out] v_picked_cols a vector of colors in RGB format
#param[in] count number of colors required
#param[in] bright 0 is all black, 100 is all white, defaults to 50
based on Fig 3 of http://epub.wu-wien.ac.at/dyn/virlib/wp/eng/mediate/epub-wu-01_c87.pdf?ID=epub-wu-01_c87
*/
void cColorPicker::Pick( vector<DWORD>&v_picked_cols, int count, int bright )
{
v_picked_cols.clear();
for( int k_hue = 0; k_hue < 360; k_hue += 360/count )
v_picked_cols.push_back( HSL2RGB( k_hue, 100, bright ) );
}
/**
Convert HSL to RGB
based on http://www.codeguru.com/code/legacy/gdi/colorapp_src.zip
*/
DWORD cColorPicker::HSL2RGB( int h, int s, int l )
{
DWORD ret = 0;
unsigned char r,g,b;
float saturation = s / 100.0f;
float luminance = l / 100.f;
float hue = (float)h;
if (saturation == 0.0)
{
r = g = b = unsigned char(luminance * 255.0);
}
else
{
float rm1, rm2;
if (luminance <= 0.5f) rm2 = luminance + luminance * saturation;
else rm2 = luminance + saturation - luminance * saturation;
rm1 = 2.0f * luminance - rm2;
r = ToRGB1(rm1, rm2, hue + 120.0f);
g = ToRGB1(rm1, rm2, hue);
b = ToRGB1(rm1, rm2, hue - 120.0f);
}
ret = ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)));
return ret;
}
unsigned char cColorPicker::ToRGB1(float rm1, float rm2, float rh)
{
if (rh > 360.0f) rh -= 360.0f;
else if (rh < 0.0f) rh += 360.0f;
if (rh < 60.0f) rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;
else if (rh < 180.0f) rm1 = rm2;
else if (rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;
return static_cast<unsigned char>(rm1 * 255);
}
int _tmain(int argc, _TCHAR* argv[])
{
vector<DWORD> myCols;
cColorPicker colpick;
colpick.Pick( myCols, 20 );
for( int k = 0; k < (int)myCols.size(); k++ )
printf("%d: %d %d %d\n", k+1,
( myCols[k] & 0xFF0000 ) >>16,
( myCols[k] & 0xFF00 ) >>8,
( myCols[k] & 0xFF ) );
return 0;
}
Isn't it also a factor which order you set up the colors?
Like if you use Dillie-Os idea you need to mix the colors as much as possible.
0 64 128 256 is from one to the next. but 0 256 64 128 in a wheel would be more "apart"
Does this make sense?
I've read somewhere the human eye can't distinguish between less than 4 values apart. so This is something to keep in mind. The following algorithm does not compensate for this.
I'm not sure this is exactly what you want, but this is one way to randomly generate non-repeating color values:
(beware, inconsistent pseudo-code ahead)
//colors entered as 0-255 [R, G, B]
colors = []; //holds final colors to be used
rand = new Random();
//assumes n is less than 16,777,216
randomGen(int n){
while (len(colors) < n){
//generate a random number between 0,255 for each color
newRed = rand.next(256);
newGreen = rand.next(256);
newBlue = rand.next(256);
temp = [newRed, newGreen, newBlue];
//only adds new colors to the array
if temp not in colors {
colors.append(temp);
}
}
}
One way you could optimize this for better visibility would be to compare the distance between each new color and all the colors in the array:
for item in color{
itemSq = (item[0]^2 + item[1]^2 + item[2]^2])^(.5);
tempSq = (temp[0]^2 + temp[1]^2 + temp[2]^2])^(.5);
dist = itemSq - tempSq;
dist = abs(dist);
}
//NUMBER can be your chosen distance apart.
if dist < NUMBER and temp not in colors {
colors.append(temp);
}
But this approach would significantly slow down your algorithm.
Another way would be to scrap the randomness and systematically go through every 4 values and add a color to an array in the above example.
function random_color($i = null, $n = 10, $sat = .5, $br = .7) {
$i = is_null($i) ? mt_rand(0,$n) : $i;
$rgb = hsv2rgb(array($i*(360/$n), $sat, $br));
for ($i=0 ; $i<=2 ; $i++)
$rgb[$i] = dechex(ceil($rgb[$i]));
return implode('', $rgb);
}
function hsv2rgb($c) {
list($h,$s,$v)=$c;
if ($s==0)
return array($v,$v,$v);
else {
$h=($h%=360)/60;
$i=floor($h);
$f=$h-$i;
$q[0]=$q[1]=$v*(1-$s);
$q[2]=$v*(1-$s*(1-$f));
$q[3]=$q[4]=$v;
$q[5]=$v*(1-$s*$f);
return(array($q[($i+4)%6]*255,$q[($i+2)%6]*255,$q[$i%6]*255)); //[1]
}
}
So just call the random_color() function where $i identifies the color, $n the number of possible colors, $sat the saturation and $br the brightness.
To achieve "most distinguishable" we need to use a perceptual color space like Lab (or any other perceptually linear color space) other than RGB. Also, we can quantize this space to reduce the size of the space.
Generate the full 3D space with all possible quantized entries and run the K-means algorithm with K=N. The resulting centers/"means" should be approximately most distinguishable from each other.

Resources