1

我可以这样采样 HSV 空间(固定sv

hue_gradient = np.linspace(0, 360,16)#sample 16 different equally spread hues
hsv = np.ones(shape=(1, len(hue_gradient), 3), dtype=float)*0.75#set sat and brightness to 0.75
hsv[:, :, 0] = hue_gradient#make one array
hsv


array([[[  0.  ,   0.75,   0.75],
        [ 24.  ,   0.75,   0.75],
        [ 48.  ,   0.75,   0.75],
        [ 72.  ,   0.75,   0.75],
        [ 96.  ,   0.75,   0.75],
        [120.  ,   0.75,   0.75],
        [144.  ,   0.75,   0.75],
        [168.  ,   0.75,   0.75],
        [192.  ,   0.75,   0.75],
        [216.  ,   0.75,   0.75],
        [240.  ,   0.75,   0.75],
        [264.  ,   0.75,   0.75],
        [288.  ,   0.75,   0.75],
        [312.  ,   0.75,   0.75],
        [336.  ,   0.75,   0.75],
        [360.  ,   0.75,   0.75]]])

然而,所有这些颜色在感知上并不统一

在此处输入图像描述

我可以通过运行 colormath 包中的 deltaE2000 方程 (delta_e_cie2000) 来确认这一点。结果如下所示:

在此处输入图像描述

这些值是 deltaE 值,颜色 0-15 对应于色调角度位置。如您所见,有些颜色低于感知阈值

在此处输入图像描述

所以,问题是,我是否可以用sv固定对 hsv 空间进行统一采样?如果不是,我怎样才能对空间进行采样,使颜色排列为具有色调相似性的邻居,s并且v尽可能少地变化?

4

1 回答 1

1

我尝试了一些东西,但最终这似乎奏效了。它均匀地间隔色调值,然后轻推它们,直到它们在感知上是均匀的。

from colormath import color_objects, color_diff, color_conversions

SAT = 1.0
VAL = 1.0
COLOR_COUNT = 16
NUDGE_SIZE = 0.2


def hue_to_lab(hue):
    return color_conversions.convert_color(
        color_objects.HSVColor(hue, SAT, VAL), color_objects.LabColor
    )


def get_equally_spaced(number, iters=100):
    # Create hues with evenly spaced values in hue space
    hues = [360 * x / number for x in range(number)]
    for _ in range(iters):
        # Convert hues to CIELAB colours
        cols = [hue_to_lab(h) for h in hues]
        # Work out the perceptual differences between pairs of adjacent
        # colours
        deltas = [
            color_diff.delta_e_cie2000(cols[i], cols[i - 1]) for i in range(len(cols))
        ]
        # Nudge each hue towards whichever adjacent colour is furthest
        # away perceptually
        nudges = [
            (deltas[(i + 1) % len(deltas)] - deltas[i]) * NUDGE_SIZE
            for i in range(len(deltas))
        ]
        hues = [(h + d) % 360 for (h, d) in zip(hues, nudges)]
    return hues


print(get_equally_spaced(COLOR_COUNT, iters=1000))

NUDGE_SIZE如果设置错误可能会搞砸(将其更改为2此处不会产生类似彩虹的效果),我认为最佳值取决于您正在执行多少次迭代以及您正在生成多少种颜色。相邻颜色的delta_e_cie2000值(使用给定的设置)[16.290288769191324, 16.290288766871242, 16.290288753399196, 16.290288726186013, 16.290288645469946, 16.290288040904777, 16.290288035037598, 16.290288051426675, 16.290288079361915, 16.290288122430887, 16.290288180738187, 16.290288265350803, 16.290288469198916, 16.29028866254433, 16.2902887136652]是非常统一的:我认为iters=1000这几种颜色有点过分了。我在这里使用的是普通列表,但它应该转换为 NumPy 数组——并且可能运行得更快一些。

该算法的工作原理如下:

  1. 从一组天真的均匀分布的色调开始。
  2. 计算相邻颜色对之间的感知差异。
  3. 将每个色调稍微移向它的邻居中与它在感知上最不同的那个。这种运动的大小与 成正比NUDGE_SIZE
  4. 重复 2-3 直到色调被轻推iters几次。
于 2020-06-18T11:03:56.657 回答