寻找N个不同的RGB颜色

10

我正在尝试以图形方式显示N条线的图表,我正在寻找一种动态分配不同颜色的方法,这取决于我有多少条线。 RGB值在0到1范围内。 我不能使用白色,因为背景是白色。 对于N小于7,我发现很容易实现:

r=(h&0x4)/4;
g=(h&0x2)/2;
b=h&0x1;
这给了我黑色,蓝色,绿色,青色,红色,洋红色和黄色。但是在此之后它会使用白色并循环。有人知道为索引分配RGB值的好方法吗?我还有一个不透明度值可供使用。

也许一个好的答案要求是颜色彼此之间尽可能地远离。 (如果你可以选择像0xF00、0x0F0和0x00F这样的颜色,你不想只选择0x001、0x002和0x003) - Jeremy Powell
5
你实际上没有一个可以操纵的不透明度值 :) 在白色背景下,透明度为50%的0,0,0与不透明度为100%的127,127,127相同。换句话说,透明度并不独立于其他参数。 - Pascal Cuoq
3个回答

5

我喜欢使用的方法是在色轮上找到n个等间距点。

我们将颜色轮表示为0到360之间的值范围。因此,我们将使用的值是360 / n * 0360 / n * 1,...,360 / n * (n - 1)。通过这样做,我们定义了每种颜色的色调。我们可以将每种颜色描述为Hue-Saturation-Value(HSV)颜色,将饱和度设置为1,亮度设置为1。

(更高的饱和度意味着颜色更“丰富”;较低的饱和度意味着颜色更接近灰色。更高的亮度意味着颜色更“明亮”;较低的亮度意味着颜色更“暗”。)

现在,一个简单的计算给出了每种颜色的RGB值。

http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_HSV_to_RGB

请注意,所给出的方程可以简化:

  • p = v *(1-s)= 1 *(1-1)= 1 * 0 = 0
  • q = v *(1-f * s)= 1 *(1-f * 1)= 1-f
  • t = v *(1-(1-f)* s)= 1 *(1-(1-f)* 1)= 1-(1-f)= 1-1 + f = f

Python伪代码实现

注意:这是一个故意低效的实现。在Python中给出这个例子的重点基本上是为了能够给出可执行的伪代码。

import math

def uniquecolors(n):
    """Compute a list of distinct colors, each of which is represented as an RGB 3-tuple."""
    hues = []
    # i is in the range 0, 1, ..., n - 1
    for i in range(n):
        hues.append(360.0 / i)

    hs = []
    for hue in hues:
        h = math.floor(hue / 60) % 6
        hs.append(h)

    fs = []
    for hue in hues:
        f = hue / 60 - math.floor(hue / 60)
        fs.append(f)

    rgbcolors = []
    for h, f in zip(hs, fs):
        v = 1
        p = 0
        q = 1 - f
        t = f
        if h == 0:
            color = v, t, p
        elif h == 1:
            color = q, v, p
        elif h == 2:
            color = p, v, t
        elif h == 3:
            color = p, q, v
        elif h == 4:
            color = t, p, v
        elif h == 5:
            color = v, p, q
        rgbcolors.append(color)

    return rgbcolors

Python的简洁实现

import math

v = 1.0
s = 1.0
p = 0.0
def rgbcolor(h, f):
    """Convert a color specified by h-value and f-value to an RGB
    three-tuple."""
    # q = 1 - f
    # t = f
    if h == 0:
        return v, f, p
    elif h == 1:
        return 1 - f, v, p
    elif h == 2:
        return p, v, f
    elif h == 3:
        return p, 1 - f, v
    elif h == 4:
        return f, p, v
    elif h == 5:
        return v, p, 1 - f

def uniquecolors(n):
    """Compute a list of distinct colors, ecah of which is
    represented as an RGB three-tuple"""
    hues = (360.0 / n * i for i in range(n))
    hs = (math.floor(hue / 60) % 6 for hue in hues)
    fs = (hue / 60 - math.floor(hue / 60) for hue in hues)
    return [rgbcolor(h, f) for h, f in zip(hs, fs)]

2
在前20种颜色后,不利用饱和度和/或亮度不为1的颜色有点浪费。 - Pascal Cuoq
这是绝对正确的。为 s = 1,v = 1 生成一组颜色会更好,然后可能是 s = 0.5,v = 1 等等。想必,可能有一种算法方式来实现这一点,但必须要有检查机制以避免生成大量难以区分的近灰色或近黑色。 - Wesley
1
如果 f = (h / 60 - math.floor(h / 60)),那么 floor(h / 60) 不会始终为0吗?因为 h 的值在0到5之间。如果是这样的话,f 的值应该在0到5/60之间。对吗? - Stuart
太好了,Suart - 我本来想写“色调(hue)”的。谢谢! - Wesley
1
在uniquecolors的简洁实现中,hues对象不应该是一个生成器,因为其他生成器将消耗相同的迭代器,导致预期颜色数量减半。将此行更改为hues = [...]即可解决此问题。 - pkit

0
for r from 0 to 255 step (255*3/N):
  for g from 0 to 255 step (255*3/N):
    for b from 0 to 255 step (255*3/N):
      ...

0

我曾经写过这段代码,用来解决你描述的问题(背景也是白色)。它和你的想法一样,只是更加通用。从OCaml转换到你的语言应该很容易。

使用方法

你不需要告诉函数你需要多少种颜色。调用函数时,输入1、2、...以获取第1个、第2个颜色等。小数字的颜色相距较远,后面的颜色当然越来越接近。

代码

lsl表示“逻辑左移”,lsr表示“逻辑右移”,!简单地表示“访问引用”。在OCaml中,RGB颜色用单个整数表示,每个颜色一个字节。

let number_to_color n = let color = ref 0 in let number = ref n in for i = 0 to 7 do color := (!color lsl 1) + (if !number land 1 <> 0 then 1 else 0) + (if !number land 2 <> 0 then 256 else 0) + (if !number land 4 <> 0 then 65536 else 0); number := !number lsr 3 done; !color

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接