我需要生成用于突出显示内容类型的颜色。在一个文档中可能有10个色调。
我的用例是,我希望告知科学家如何从输入文档中提取数据。颜色编码的背景着色(带有描述性)工具提示将用于高亮显示导入的块。下面是一个模拟输入文件:
这里是一个模拟版本,展示了高亮显示以指示导入了哪些字段时的外观。每个突出显示的块上的工具提示会提供识别它的工具的更多详细信息,以及推送到数据库的值(带单位):
每次我遇到一种新类型的内容,我都需要生成一种新的颜色。该颜色应与现有颜色具有最大对比度。显然,我们走得越远,对比度就越小。
在尝试想象一个解决方案的过程中,我想象了一个色轮。我们从一种颜色开始。为了让下一种颜色具有最大的对比度,它将与轮子上的第一种颜色相对。
对于每一种连续的颜色,算法必须在色轮上寻找最大的“未占用”弧线,并在其中点生成颜色。
这看起来像是现有的颜色生成策略吗?
如果是这样的话,是否有记录在案的算法来实现它?
(我的目标环境是Python,但这似乎只是一个实现细节)
发布于 2019-10-28 19:49:20
啊,我已经想出了一个解决这个问题的替代策略。
颜色编码可以推迟到过程结束,而不是动态生成颜色。
一旦我们知道需要多少种颜色,我们就可以在HSB/HSV颜色谱中生成均匀分布在色调中的许多排列。我认为,这将提供最大的反差。
发布于 2019-10-28 21:08:46
您希望颜色等距,并且彼此之间尽可能远,并且白色和黑色已按使用方式插入。
mean-red是一个简单但出人意料的好指标:
如果你在运行时,你必须重新计算你添加的每一种新颜色的位置,如果你事先知道有多少种颜色,你可以一次计算出它们的位置。
下面是一个用python实现的示例:
import numpy as np
from itertools import combinations
from scipy.optimize import minimize, Bounds
BLACK_AND_WHITE = np.array((0.0, 0.0, 0.0, 255.0, 255.0, 255.0))
我们认为数组中的三个连续数字表示一种颜色,给定两个这样的三元组,并使用上面定义的距离,我们的距离函数为
def distance(c1, c2):
r = (c1[0] + c2[0]) / 2.0
coeffs = np.array(((2.0 + r/256), 4, (2.0 + (255 - r)/256.0)))
diff = c1 - c2
return np.sqrt(np.sum(coeffs * diff ** 2))
我们希望最大化所有颜色对之间的最小距离,这与最小化负值的最小距离相同。为了获得颜色对,我们使用combinations(..., 2)
,它就是这样做的,并且为了使它迭代三元组,我们重塑了颜色数组,以便每一行都包含一种颜色:
def cost_function(x):
colors = np.concatenate((BLACK_AND_WHITE, x)).reshape(-1, 3)
return -min(mean_red_distance(color_pairs[0], color_pairs[1]) for color_pairs in combinations(colors, 2))
现在是最小化我们的成本函数的时候了,允许颜色的范围在0到255之间:
def get_new_colors_after_adding(existing_colors):
if len(existing_colors):
guess = np.mod(existing_colors.reshape(-1, 3)[0] + np.array((100, 100, 100)), 256)
else:
guess = np.array((0, 255, 255))
guess = np.concatenate((guess, existing_colors))
# let all colors range between 0 and 255
result = minimize(cost_function, guess, bounds=Bounds(0, 255))
if not result.success:
raise ValueError('Failed adding new color')
return result.x
最后,我们在每个步骤中添加10种颜色,并打印生成的三元组:
if __name__ == '__main__':
# start with no colors
existing_colors = np.empty(0, dtype=np.int32)
# example of consequently adding colors.
for i in range(10):
existing_colors = get_new_colors_after_adding(existing_colors)
print(np.round(existing_colors.reshape(-1, 3)).astype(np.int))
https://stackoverflow.com/questions/58572030
复制相似问题