使用 CIEDE2000 找到真正相反颜色的更好算法

Better algorithm with CIEDE2000 to find true opposite colors

使用 Python 3.7 和 colormath 模块,我在尝试找到一种颜色的完全相反颜色时获得了一些乐趣(例如,黑色 [0, 0, 0] 的相反颜色是黄色 [255, 255, 0] 的 DE 为 101.20397657762743)或试图找到色差最大的两种颜色(即“海军蓝”[0, 0, 110] 和“黄绿色”[143, 255, 0] 的 DE 为 119.4740815993416 ,来自我可能不准确的测试)。

不幸的是,我发现找到与给定颜色相反的唯一方法就是通过将给定颜色与(几乎)每个 sRGB 颜色组合(或 [0 , 0, 0] 到 [255, 255, 255]).

Python 3.7代码:

from colormath.color_objects import sRGBColor as RGBC, LabColor as LabC
from colormath.color_conversions import convert_color as cv_c
from colormath.color_diff import delta_e_cie2000 as de2k
from time import perf_counter as clock

# Example: X11's "Midnight Blue", edit as 'RGBC(r, g, b,...'
reference = RGBC(25, 25, 112, is_upscaled=1)
lab_ref = cv_c(reference, LabC)

# Set max delta
max_delta = 0

# Set estimate calculation's range inverals as factors of 255 (1, 3, 5, 15, 17, 51, 85, 255)
resolution = 17

# Estimate the opposite color
for sample_r in range(0, 256, resolution):
    for sample_g in range(0, 256, resolution):
        for sample_b in range(0, 256, resolution):
        
            # Convert the sample to Lab
            sample = RGBC(sample_r, sample_g, sample_b, is_upscaled=1)
            lab_samp = cv_c(sample, LabC)
            
            # Find the color difference
            delta = de2k(lab_ref, lab_samp)
            
            # Compare current delta with previous highest delta
            if delta > max_delta:
                # Overwrite highest delta with current delta
                max_delta = delta
                
                # Save estimate for optimization
                estimate = sample.get_upscaled_value_tuple()

# Keep any 255 values from estimate, leads to 'range(255, 256)'
low_r = 0 if estimate[0] != 255 else 255
low_g = 0 if estimate[1] != 255 else 255
low_b = 0 if estimate[2] != 255 else 255

# Keep any 0 values from estimate, leads to 'range(0, 1)'
high_r = 256 if estimate[0] != 0 else 1
high_g = 256 if estimate[1] != 0 else 1
high_b = 256 if estimate[2] != 0 else 1

# Reset max delta
max_delta = 0

# Find a better opposite color from estimate
for sample_r in range(low_r, high_r):
    for sample_g in range(low_g, high_g):
        for sample_b in range(low_b, high_b):
            
            # Convert the sample color to Lab
            sample = RGBC(sample_r, sample_g, sample_b, is_upscaled=1)
            lab_samp = cv_c(sample, LabC)
            
            # Find the color difference
            delta = de2k(lab_ref, lab_samp)
            
            # Compare current delta with previous highest delta
            if delta > max_delta:
                # Overwrite highest delta with current delta
                max_delta = delta

                # Overwrite best opposite color with current sample
                opposite = sample

# Print the reference, opposite color, and delta E
print(f'{reference.get_upscaled_value_tuple()} with {opposite.get_upscaled_value_tuple()}, {max_delta}')

# Print program time
print(clock())

# Example: 
# Returns '(25, 25, 112) with (166, 255, 0), 108.95350620860522
#          2.580066949'

上面的代码将 运行 2.5 秒到大约 19 分钟(假设第二次相反的计算需要 128^3 次跳跃,returns 相同的值)到大约 2 小时 15 分钟(假设最坏的可能在我的系统 (3.00 GHz)

上,情况是 254^3 次跳跃,因为没有优化发生)

CIEDE2000 的方程可在 this site 处查看。请注意页面底部的注释。

我想知道是否有更高效的算法可以找到与给定 RGB 颜色完全相反的颜色。我希望能够在 CIEDE202X 或 CIEDE20XX 出来之前使用所述算法创建包含每种 RGB 颜色及其相反颜色的电子表格。

注意:这是我在 Whosebug 上的第一个问题

编辑 1: 创建了更好的估计优化。如果估计有一个,我不会只保留 0 或 255,我会减少限制,使它们最多与估计相差 +-32。在 3.00 GHz 上运行时间减少到最多 4 秒。

# Red channel optimization
if estimate[0] == 0 or estimate[0] == 255:
    low_r = estimate[0]
    high_r = estimate[0] + 1
elif estimate[0] > 32 and estimate[0] < 224:
    low_r = estimate[0] - 32
    high_r = estimate[0] + 32
elif estimate[0] < 33:
    low_r = 0
    high_r = estimate[0] + 32
else:
    low_r = estimate[0] - 32
    high_r = 256

# Green channel optimization
if estimate[1] == 0 or estimate[1] == 255:
    low_g = estimate[1]
    high_g = estimate[1] + 1
elif estimate[1] > 32 and estimate[1] < 224:
    low_g = estimate[1] - 32
    high_g = estimate[1] + 32
elif estimate[1] < 33:
    low_g = 0
    high_g = estimate[1] + 32
else:
    low_g = estimate[1] - 32
    high_g = 256

# Blue channel optimization
if estimate[2] == 0 or estimate[2] == 255:
    low_b = estimate[2]
    high_b = estimate[2] + 1
elif estimate[2] > 32 and estimate[2] < 224:
    low_b = estimate[2] - 32
    high_b = estimate[2] + 32
elif estimate[2] < 33:
    low_b = 0
    high_b = estimate[2] + 32
else:
    low_b = estimate[2] - 32
    high_b = 256

CIE DeltaE 2000 不适用于较大的色差,因此 [10, 20]+ 范围内的较大差异根本无法使用此准度量进行评估,您可能应该查看其他内容,例如 HyAB 色差度量: https://onlinelibrary.wiley.com/doi/abs/10.1002/col.22451 或类似的。