Алгоритм нахождения цвета между двумя другими - в цветовом пространстве окрашенных цветов - PullRequest
27 голосов
/ 26 мая 2011

При смешивании синей и желтой краски получается зеленый цвет.

У меня есть два цвета RGB:

синий = (0, 0, 255)

и желтый = (255, 255, 0)

Каков алгоритм для нахождения цвета RGB, который является результатом смешивания двух цветов, как они будут выглядеть при использовании краски? Получающиеся цвета из алгоритма не должны быть ужасно точными. Для приведенного выше примера он должен выглядеть только как зеленый.

Заранее спасибо.

Редактировать: Эта функция, написанная на Go, работала для меня, основываясь на ответе LaC.

func paintMix(c1, c2 image.RGBAColor) image.RGBAColor { 
    r := 255 - ((255 - c1.R) + (255 - c2.R))
    g := 255 - ((255 - c1.G) + (255 - c2.G))
    b := 255 - ((255 - c1.B) + (255 - c2.B))
    return image.RGBAColor{r, g, b, 255}
}

Edit # 2 Все это позволяет смешать голубой и желтый, смесь между синим и желтым становится черным, что кажется неправильным. Я все еще ищу работающий алгоритм.

Edit # 3 Вот полный рабочий пример в Go с использованием цветового пространства HLS: http://go.pastie.org/1976031. Спасибо Mark Ransom.

Редактировать # 4 Кажется, что путь к еще лучшему смешиванию цветов состоит в использовании уравнения Кубелки-Мунка

Ответы [ 5 ]

12 голосов
/ 26 мая 2011

Краска работает по всасыванию.Вы начинаете с белого света (255 255 255) и умножаете его на коэффициенты поглощения.

Синяя краска поглощает весь красный и зеленый свет, который попадает на него.

Желтая краска поглощает весь синий свет, который попадает на него.

В идеальном мире это означает, что сочетание желтой и синей краски приведет к черной краске или, в лучшем случае, к мутной серой.На практике «синяя» краска имеет уклон в сторону зеленого, поэтому вы получаете грязно-зеленый.Я никогда не видел пример смешивания желтого и синего, которое дает удовлетворительный зеленый.Википедия описывает некоторые сложности этого процесса: http://en.wikipedia.org/wiki/Primary_color#Subtractive_primaries

Я думаю, что вы действительно спрашиваете, как интерполировать цвета вдоль цветового круга.Это не должно зависеть от того, являются ли цвета поглощающими, как на краске, или излучающими, как на дисплеях RGB.

Редактировать: Работая в цветовом пространстве HSL, вы можете получать результаты, которые выищу.Вот некоторый код на Python, который реализует алгоритм;Усреднение оттенков сложно, и основано на моем предыдущем ответе для усреднения углов .

from colorsys import rgb_to_hls,hls_to_rgb
from math import sin,cos,atan2,pi

def average_colors(rgb1, rgb2):
    h1, l1, s1 = rgb_to_hls(rgb1[0]/255., rgb1[1]/255., rgb1[2]/255.)
    h2, l2, s2 = rgb_to_hls(rgb2[0]/255., rgb2[1]/255., rgb2[2]/255.)
    s = 0.5 * (s1 + s2)
    l = 0.5 * (l1 + l2)
    x = cos(2*pi*h1) + cos(2*pi*h2)
    y = sin(2*pi*h1) + sin(2*pi*h2)
    if x != 0.0 or y != 0.0:
        h = atan2(y, x) / (2*pi)
    else:
        h = 0.0
        s = 0.0
    r, g, b = hls_to_rgb(h, l, s)
    return (int(r*255.), int(g*255.), int(b*255.))

>>> average_colors((255,255,0),(0,0,255))
(0, 255, 111)
>>> average_colors((255,255,0),(0,255,255))
(0, 255, 0)

Обратите внимание, что этот ответ не эмулирует смешивание краски, дляпричины, изложенные выше.Скорее, это дает интуитивное смешение цветов, не основанное ни на какой реальности физического мира.

9 голосов
/ 26 мая 2011

На самом деле, вы получаете зеленый, смешивая (вычитая) желтый и голубой. Желтый - красный + зеленый (255, 255, 0), голубой - зеленый + синий (0, 255, 255). Теперь сделайте их противоположные цвета: синий (0, 0, 255) и красный (255, 0, 0). Смешайте их аддитивно, и вы получите фиолетовый (255, 0, 255). Сделайте его противоположным, и вы получите зеленый (0, 255, 0).

Другими словами, вы можете получить субтрактивную смесь как противоположность аддитивной смеси противоположностей ваших двух цветов.

4 голосов
/ 26 мая 2011

Цветовое пространство RBG основано на световом излучении , цветовое пространство красителей и пигментов основано на световом поглощении .

например. Растения выглядят не зелеными, потому что они излучают зеленый свет, а потому, что они поглощают все другие цвета света, отражая только зеленый.

Исходя из этого, вы должны быть в состоянии приблизиться, выполнив преобразование из RGB в поглощающее цветовое пространство, выполнив "микс", а затем вернитесь обратно.

2 голосов
/ 26 мая 2011

Вы хотите использовать вычитающие цвета CMY (голубой, пурпурный, желтый) (как это делает LaC, без использования термина)

Преобразование назад и вперед простое: (C, M, Y) =(-R, -G, -B).
Таким образом, CMY (0,0,0) - белый, а CMY (FF, FF, FF) - черный.

При добавлении двух цветов CMYСуществуют разные способы расчета новых значений.Вы можете взять среднее, максимальное или что-то среднее между каждым значением цвета.
Например.для светофильтров вы всегда используете максимальное значение.Для краски, которую вы правильно хотите использовать, что-то ближе к среднему значению.

Как указывает LaC, вы получаете зеленый не от смешения желтого и синего, а от смешения желтого и голубого.Желтый и синий фактически дают черный цвет при смешивании по максимальному значению (например, светофильтры).Вот почему вы можете использовать что-то ближе к среднему значению для смешивания краски.

Вы не хотите использовать CMYK, если не хотите что-то напечатать.Черный «K» цвет в основном используется в принтерах для экономии чернил, но не обязательно для представления цветов.

1 голос
/ 26 мая 2011

Используйте Convert :: Color для получения такого вида вывода:

mauve        is 0xE0B0FF  sRGB=[224,176,255]  HSV=[276, 31,100] 
vermilion    is 0xE34234  sRGB=[227, 66, 52]  HSV=[  5, 77, 89] 
mix          is 0xE2799A  sRGB=[226,121,154]  HSV=[341, 46, 89] 

red          is 0xFF0000  sRGB=[255,  0,  0]  HSV=[  0,100,100] 
blue         is 0x0000FF  sRGB=[  0,  0,255]  HSV=[240,100,100] 
red+blue     is 0x800080  sRGB=[128,  0,128]  HSV=[300,100, 50] 

black        is 0xFFFFFF  sRGB=[255,255,255]  HSV=[  0,  0,100] 
white        is 0x000000  sRGB=[  0,  0,  0]  HSV=[  0,  0,  0] 
grey         is 0x808080  sRGB=[128,128,128]  HSV=[  0,  0, 50] 

dark red     is 0xFF8080  sRGB=[255,128,128]  HSV=[  0, 50,100] 
light red    is 0x800000  sRGB=[128,  0,  0]  HSV=[  0,100, 50] 

pink         is 0x800080  sRGB=[128,  0,128]  HSV=[300,100, 50] 
deep purple  is 0xBF80FF  sRGB=[191,128,255]  HSV=[270, 50,100] 

При запуске кода такого типа:

#!/usr/bin/env perl
use strict;
use warnings;

use Convert::Color;

main();
exit;

sub rgb($$$) {
    my($r, $g, $b) = @_;
    return new Convert::Color:: "rgb8:$r,$g,$b";
}

sub show($$) {
    my ($name, $color) = @_;
    printf "%-12s is 0x%6s", $name,  uc $color->hex;
    printf "  sRGB=[%3d,%3d,%3d] ",     $color->rgb8;

    my ($h,$s,$v) = $color->as_hsv->hsv;
    for ($s, $v) { $_ *= 100 }
    printf " HSV=[%3.0f,%3.0f,%3.0f] ",  $h, $s, $v;
    print "\n";
}

sub main {
    my $vermilion = rgb 227,  66,  52;
    my $mauve     = rgb 224, 176, 255;
    show mauve      => $mauve;
    show vermilion  => $vermilion;

    my $mix = alpha_blend $mauve $vermilion;
    show mix => $mix;
    print "\n";

    my $red   = rgb 255,   0,   0;
    my $blue  = rgb   0,   0, 255;
    show red  => $red;
    show blue => $blue;

    $mix = alpha_blend $red $blue;
    show "red+blue" => $mix;
    print "\n";

    my $black = rgb 255, 255, 255;
    my $white = rgb 0,     0,   0;
    show black => $black;
    show white => $white;

    my $grey  = alpha_blend $black $white;
    show grey  => $grey;
    print "\n";

    my $dark_red  = alpha_blend $red $black;
    my $light_red = alpha_blend $red $white;

    show "dark red"  => $dark_red;
    show "light red" => $light_red;
    print "\n";

    my $magenta = rgb 255, 0, 255;
    my $violet  = rgb 127, 0, 255;

    my $pink        = alpha_blend $magenta $white;
    my $deep_purple = alpha_blend $violet  $black;

    show pink          => $pink;
    show "deep purple" => $deep_purple;;
}
...