计算混合颜色的RGB代码,假设红色,蓝色和黄色作为原色

dan*_*ver 2 colors

浅色和油漆之间存在不匹配:虽然物理学家会说三原色是红色,绿色和蓝色,但画家会将红色,蓝色和黄色作为原色.事实上,当用水彩画画时,你不能混合红色,绿色和蓝色的黄色,而不是混合橙色,你只会变成棕色.

这是我正在尝试做的事情:从两种给定的RGB颜色我想计算组合颜色的RGB代码,我希望颜色像水彩一样混合在纸上.据我所知,计算通常如下所示:

  • #FF0000 +#0000FF =#880088((FF + 00)/ 2 = 88,(00 + 00)/ 2 = 00,(00 + FF)/ 2 = 88),所以红色和蓝色给出紫色(因为它应该)
  • #FF0000 +#FFFF00 =#FF8800((FF + FF)/ 2 = FF,(00 + FF)/ 2 = 88,(00 + 00)/ 2 = 00),所以红色和黄色给出橙色(因为它应该)

但是,当混合蓝色和黄色时,结果是灰色的:

  • #0000FF +#FFFF00 =#888888((00 + FF)/ 2 = 88,(00 + FF)/ 2 = 88,(FF + 00)/ 2 = 88)=灰色

在纸上你会期望变绿(#008800)并且在混合颜色时永远不会变灰.

所以我的问题是,我怎么能用绿色交换绿色作为原色,然后我怎样才能计算出符合油漆定律而不是浅色定律的混合色?

Mar*_*som 5

没有简单的物理模型可以做到这一点,画家的颜色与光有非常精细的相互作用.幸运的是,我们有计算机,不仅限于对物理世界进行建模 - 我们可以让它们做任何我们想要的任意事情!

第一步是创建一个具有我们需要的色调分布的色轮,红色,黄色和蓝色以120度的增量.网上有很多例子.我在这里创建了一个只有完全饱和的颜色,以便它可以用来生成完整的RGB色域.车轮上的颜色完全是任意的; 我将橙色(60°)设置为(255,160,0),因为红色和黄色之间的中点太红,我将纯蓝色(0,0,255)移动到250°而不是240°,因此240°蓝色会更好看.

RYB色调色轮

记住我童年的实验,当你将等量的红色,黄色和蓝色混合在一起时,你会得到一个模糊的棕灰色.我选择了一种合适的颜色,你可以在色轮的中心看到它; 在代码中我亲切地称它为"泥".

为了获得比红色,黄色和蓝色更多的可想象的颜色,你还需要混合白色和黑色.例如,你通过混合红色和白色获得粉红色,然后通过将橙色(黄色+红色)与黑色混合来获得棕色.

转换使用比率,而不是绝对数字.与真正的油漆一样,混合1份红色和1份黄色,而100份红色和100份黄色没有区别.

代码以Python格式呈现,但转换为其他语言并不难.最棘手的部分是添加红色,黄色和蓝色以创建色调角度.我使用矢量加法并转换回角度atan2.几乎所有其他事情都是通过线性插值(lerp)完成的.

# elementary_colors.py
from math import degrees, radians, atan2, sin, cos

red = (255, 0, 0)
orange = (255, 160, 0)
yellow = (255, 255, 0)
green = (0, 255, 0)
cyan = (0, 255, 255)
blue = (0, 0, 255)
magenta = (255, 0, 255)
white = (255, 255, 255)
black = (0, 0, 0)
mud = (94, 81, 74)

colorwheel = [(0, red), (60, orange), (120, yellow), (180, green),
              (215, cyan), (250, blue), (330, magenta), (360, red)]

red_x, red_y = cos(radians(0)), sin(radians(0))
yellow_x, yellow_y = cos(radians(120)), sin(radians(120))
blue_x, blue_y = cos(radians(240)), sin(radians(240))

def lerp(left, right, left_part, total):
    if total == 0:
        return left
    ratio = float(left_part) / total
    return [l * ratio + r * (1.0 - ratio) for l,r in zip(left, right)]

def hue_to_rgb(deg):
    deg = deg % 360
    previous_angle, previous_color = colorwheel[0]
    for angle, color in colorwheel:
        if deg <= angle:
            return lerp(previous_color, color, angle - deg, angle - previous_angle)
        previous_angle = angle
        previous_color = color

def int_rgb(rgb):
    return tuple(int(c * 255.99 / 255) for c in rgb)

def rybwk_to_rgb(r, y, b, w, k):
    if r == 0 and y == 0 and b == 0:
        rgb = white
    else:
        hue = degrees(atan2(r * red_y + y * yellow_y + b * blue_y,
                            r * red_x + y * yellow_x + b * blue_x))
        rgb = hue_to_rgb(hue)
        rgb = lerp(mud, rgb, min(r, y, b), max(r, y, b))
    gray = lerp(white, black, w, w+k)
    rgb = lerp(rgb, gray, r+y+b, r+y+b+w+k)
    return int_rgb(rgb)
Run Code Online (Sandbox Code Playgroud)