Algorithm for finding the color between two others - in the colorspace of painted colors

前端 未结 5 1412
长情又很酷
长情又很酷 2020-12-13 07:02

When mixing blue and yellow paint, the result is some sort of green.

I have two rgb colors:

blue = (0, 0, 255)

and yellow = (255, 255, 0)

Wha

相关标签:
5条回答
  • 2020-12-13 07:09

    Actually, you get green from mixing (subtractively) yellow and cyan. Yellow is red + green (255, 255, 0), cyan is green + blue (0, 255, 255). Now make their opposite colors: blue (0, 0, 255) and red (255, 0, 0). Mix them additively and you get purple (255, 0, 255). Make its opposite and you get green (0, 255, 0).

    In other words, you can get a subtractive mix as the opposite of the additive mix of the opposites of your two colors.

    0 讨论(0)
  • 2020-12-13 07:09

    Use Convert::Color to produce this sort of output:

    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] 
    

    When running this sort of code:

    #!/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;;
    }
    
    0 讨论(0)
  • 2020-12-13 07:20

    You wanna use subtractive CMY-colors (Cyan, Magenta, Yellow) (as LaC is doing, whithout using the term)

    The conversion back and forth is simple: (C,M,Y) = (-R,-G,-B).
    So CMY(0,0,0) is white and CMY(FF,FF,FF) is black.

    When you add two CMY colors, there are different ways to calculate the new values. You can take the average, max or something in between for each color value.
    Eg. for light-filters you always use the max value. For paint you properly want to use, something closer to the average value.

    As LaC points out, you don't get green from mixing yellow and blue, but from mixing yellow and cyan. Yellow and blue actually gives black, when mixing by max value (eg. light filters). This is why, you might want to use something closer to the average value for paint mixing.

    You don't wanna use CMYK, unless you want to print something. The black "K" color is primarily used in printers to save ink, but it's not needed to represent colors.

    0 讨论(0)
  • 2020-12-13 07:24

    Paint works by absorption. You start with white light (255,255,255) and multiply it by the absorption factors.

    Blue paint absorbs all red and green light that hits it.

    Yellow paint absorbs all blue light that hits it.

    In a perfect world, that means that combining yellow and blue paint would result in black paint, or at best a muddy gray. In practice the "blue" paint has a bias towards green, so you get a muddy green. I've never seen an example of mixing yellow and blue that produces a satisfactory green. Wikipedia goes into some of the complexities of this process: http://en.wikipedia.org/wiki/Primary_color#Subtractive_primaries

    I think what you are really asking is how to interpolate colors along a color wheel. This should be independent of whether the colors are absorptive as in paint, or emissive as in RGB displays.

    Edit: By working in the HSL color space you can get the kind of results you're looking for. Here's some code in Python that implements the algorithm; averaging hues is tricky, and is based on a previous answer of mine for averaging angles.

    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)
    

    Note that this answer does not emulate paint mixing, for the reasons stated above. Rather it gives an intuitive mixing of colors that is not grounded in any physical world reality.

    0 讨论(0)
  • 2020-12-13 07:33

    The colour space RBG is based on light emission, the colour space of dyes and pigments is based on light absorption.

    e.g. Plant's don't look green because they emit green light, but because they absorb all the other colours of light, reflecting only green.

    Based on this, you should be able to get pretty close by doing a conversion from RGB to an absorptive colour space, doing the "mix" and then back again.

    0 讨论(0)
提交回复
热议问题