【问题标题】:How to generate close colors to a rgb value?如何生成接近 rgb 值的颜色?
【发布时间】:2018-01-13 08:56:59
【问题描述】:

我希望能够生成接近一种 RGB 颜色的多种颜色,如下图所示。

这是我使用 Python 所做的:

def similarColors(rgb, loop=6):
    difference = 30
    colors = []
    for i in range(loop):
        red = rgb[0]
        red_highest = red + difference
        red_lowest = red - difference
        red = randint(red_lowest, red_highest)

        green = rgb[1]
        green_highest = green + difference
        green_lowest = green - difference
        green = randint(green_lowest, green_highest)

        blue = rgb[2]
        blue_highest = blue + difference
        blue_lowest = blue - difference
        blue = randint(blue_lowest, blue_highest)

        colors.append([red, green, blue])
    return colors

palette = similarColors([244, 83, 28])

问题:我觉得我用这种方法过于复杂了有没有办法让上面的代码更简洁更短?

我想避免对每种颜色(红色、蓝色、绿色)分别进行相同的处理,我也不确定这种方法是否真的适合我想要实现的目标。

【问题讨论】:

  • 我在我的答案中添加了一个新版本,它(部分)弥补了人类视觉系统对红色、绿色和蓝色的敏感性不同这一事实。

标签: python colors


【解决方案1】:

我们可以通过循环 RGB 组件来压缩代码。但是,您当前的算法存在一个错误:它可以生成 255 的颜色通道值,因此我们需要修复它。

from random import randint

def similarColors(rgb, loop=6):
    colors = []
    delta = 30
    for i in range(loop):
        new_rgb = [randint(max(0, x - delta), min(x + delta, 255)) for x in rgb]  
        colors.append(new_rgb)                
    return colors

colors = similarColors([244, 83, 28])
print(colors)

典型输出

[[249, 75, 28], [226, 111, 34], [235, 85, 46], [228, 66, 28], [244, 62, 8], [233, 102, 21]]

您说:“我也不确定这种方法是否真的适合我想要实现的目标”。我不确切知道您要达到的目标,但我可以看到的一个问题是人类视觉系统对 R、G 和 B 的敏感性不同。因此,一个通道中给定数量的变化不会与另一个通道中的相同更改具有相同的效果。要正确处理这个问题,您需要在更接近人类视觉系统的色彩空间中工作,例如Lab color space。但是,我们可以通过在通道增量上使用比例因子来获得合理的近似值。

Grayscale 上的维基百科文章提供了一个可用于计算 RGB 颜色亮度的公式:

y = 0.299*R + 0.587*G + 0.114*B

此公式用于模拟 NTSC 和 PAL 电视。

这是使用这些比例因子的上述代码的一个版本。我们将基础delta 除以这些比例因子,因此蓝色增量最大,绿色增量最小,因为眼睛对绿色最敏感,对蓝色最不敏感。

def similarColors(rgb, loop=6):
    colors = []
    delta = 10
    deltas = [round(delta / u) for u in (0.299, 0.587, 0.114)]
    for i in range(loop):
        new_rgb = [randint(max(0, x - delta), min(x + delta, 255)) 
            for x, delta in zip(rgb, deltas)]
        colors.append(new_rgb)
    return colors

colors = similarColors([244, 83, 28])
print(colors)

典型输出

[[236, 84, 65], [233, 74, 78], [226, 93, 73], [249, 88, 89], [240, 84, 40], [226, 75, 22]]

为了使代码更高效,因为我们使用的是固定基址 delta,我们可以预先计算 deltas 数组,而不是每次调用 similarColors 时都重新计算它。

【讨论】:

  • 现在让它就位,我会说它更容易 - 没有返回值,并且将它应用于图片的每个像素会自动改变图片
  • @Sanitiy 每个 Python 函数都会返回一些内容:如果没有明确返回对象,则返回 None。当然,该函数可以接受一个列表参数,我们可以用新的颜色列表扩展它。这比扩展全局colors 列表要好。我不知道您所说的“将其应用于图片的每个像素”究竟是什么意思,因为similarColor 将单个颜色值作为其 arg 并返回 6 个颜色值。
  • 为了精确,我的意思是如果颜色是橙色,它将显示橙色阴影而不是其他颜色。
  • @Lindow 啊,好的。新版本在这方面有点更好。但如果我们在 HSV 或 HLS 颜色空间中工作,我们可以做得更好。通过使色调增量变小,新颜色将具有与原始颜色相似的色调。看看colorsys 模块,它有你需要的转换功能,试着写点东西,如果你卡住了,问一个新问题。
【解决方案2】:

无需复制粘贴每种颜色,您可以像这样使用 for 循环:

def similarColors(rgb, loop=6, difference=30):
    colors = []
    for _ in range(loop):
        color = []
        for curr_color in rgb:
            color.append(randint(curr_color - difference, curr_color + difference))
        colors.append(color)

    return colors

注意我还在参数中输入了difference

还有一个错误,即 rgb 部分可能 255,您可以改用 max(0, min(255, randint(curr_color - difference, curr_color + difference))) 来修复它。

【讨论】:

    【解决方案3】:

    如果您可以使用numpy更紧凑的解决方案是这样的:

    import numpy as np
    
    def similarColors(rgb, loop=6):
        delta = 30
        origClrs = np.tile(np.array(rgb), (loop, 1))
        randOffsets = np.random.randint(-delta, delta, size=(loop, 3))
        return origClrs + randomOffsets
    

    【讨论】:

      猜你喜欢
      • 2012-07-15
      • 2019-07-02
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      • 2011-05-27
      • 1970-01-01
      相关资源
      最近更新 更多