这篇关于颜色差异的维基百科文章值得一读,其中链接了CompuPhase的“低成本逼近”文章。我将以后者为基础进行尝试。
你没有指定语言,所以我将使用非优化的Python(除了参考文章中已经存在的整数优化),以便它可以轻松地翻译成其他语言。
n_colors = 25
n_global_moves = 32
class Color:
max_weighted_square_distance = (((512 + 127) * 65025) >> 8) + 4 * 65025 + (((767 - 127) * 65025) >> 8)
def __init__(self, r, g, b):
self.r, self.g, self.b = r, g, b
def weighted_square_distance(self, other):
rm = (self.r + other.r) // 2 # integer division
dr = self.r - other.r
dg = self.g - other.g
db = self.b - other.b
return (((512 + rm) * dr*dr) >> 8) + 4 * dg*dg + (((767 - rm) * db*db) >> 8)
def min_weighted_square_distance(self, index, others):
min_wsd = self.max_weighted_square_distance
for i in range(0, len(others)):
if i != index:
wsd = self.weighted_square_distance(others[i])
if min_wsd > wsd:
min_wsd = wsd
return min_wsd
def is_valid(self):
return 0 <= self.r <= 255 and 0 <= self.g <= 255 and 0 <= self.b <= 255
def add(self, other):
return Color(self.r + other.r, self.g + other.g, self.b + other.b)
def __repr__(self):
return f"({self.r}, {self.g}, {self.b})"
colors = [Color(127, 127, 127) for i in range(0, n_colors)]
steps = [Color(dr, dg, db) for dr in [-1, 0, 1]
for dg in [-1, 0, 1]
for db in [-1, 0, 1] if dr or dg or db] # i.e., except 0,0,0
moved = True
global_move_phase = False
global_move_count = 0
while moved or global_move_phase:
moved = False
for index in range(0, len(colors)):
color = colors[index]
if global_move_phase:
best_min_wsd = -1
else:
best_min_wsd = color.min_weighted_square_distance(index, colors)
for step in steps:
new_color = color.add(step)
if new_color.is_valid():
new_min_wsd = new_color.min_weighted_square_distance(index, colors)
if best_min_wsd < new_min_wsd:
best_min_wsd = new_min_wsd
colors[index] = new_color
moved = True
if not moved:
if global_move_count < n_global_moves:
global_move_count += 1
global_move_phase = True
else:
global_move_phase = False
print(f"n_colors: {n_colors}")
print(f"n_global_moves: {n_global_moves}")
print(colors)
rd * rd + gd * gd + bd * bd
:配置变为[(2, 0, 0), (0, 253, 255), (255, 255, 2)]
通过添加两个全局移动,配置变为预期的配置。
[(0, 0, 0), (0, 255, 255), (255, 255, 0)]
r
→255-r
和/或g
和/或b
)以获得等效的解决方案。最好是在尝试颜色移动步骤的顺序中引入随机性,并改变随机种子。(L*a*b*)
中就是欧几里得距离。
如果你想要使用极坐标(即色调角度),那么可以在CIELAB的基础上再进一步,转而使用CIELCh。
我建议参考布鲁斯·林德布卢姆的网站,了解相关数学知识。
简化步骤如下:
将LAB转换为XYZ。
将XYZ转换为sRGB。
将sRGB伽马曲线添加回每个通道。
以下是两种讨论过的方法的比较:
相同的起始颜色,但使用CIELAB L* C* h*(只旋转色调180度,不调整L*)。
这次在LCh中再次调整,同时也将L*调整为(100 - L*firstcolor)
现在你会注意到这些色相角度的变化很大——事实上,虽然LAB是“有点均匀”的,但在蓝色方面却相当不稳定。
N
个波长/颜色,使您拥有N种不同的颜色(也可以用作多波段渲染的原色,因为它们相加得到白色,并且通过它们的线性组合可以实现任何颜色)。 - Spektre