RGB中混合颜色的计算

37

我想要能够获取两个RGB-256向量并计算它们混合的结果,同时我也想为每个向量分配不同的权重。我已经使用Word颜色板进行过实验,并发现一些颜色确实按照加权平均值混合:

0.5*红(255,0,0) + 0.5*黄(255,255,0) = 橙(255,127,0)

但有些颜色则不是这样:

0.5*黄(255,255,0) + 0.5*蓝(0,0,255) = 灰(127,127,127)而不是绿(0,255,0)

是否存在一个精确计算所有颜色的算法或者我只能使用查找表进行操作?

13个回答

34
最好的解释是,RGB颜色模型对我们人类来说有些不直观。对于仅通过混合三种预定义颜色(红、绿和蓝)来显示颜色的视频显示设备(如监视器或电视),这是完全合理的。但这不是我们在小学时学习混合颜色的方式。
在RGB中,白色表示为(255, 255, 255),相当于“全部开启”。显示了红色、绿色和蓝色三个颜色分量的完整值,产生了如此高的光强度,以至于我们感知到的颜色是白色。相反,颜色黑色(0, 0, 0)是显示设备的“默认”状态——当没有颜色光被显示时(“0”),结果是黑色或缺少颜色。
当你完全混合黄色(255, 255, 0)和蓝色(0, 0, 255)时,你得到由(255, 255, 255)表示的颜色,即白色。当你将白色乘以0.5时,你会得到灰色,因为255 * 0.5 = 127。
当混合红色和黄色时,得到期望的结果可能更多的是异常情况。红色+黄色是(510, 255, 0),因此当你将其乘以0.5时,你会得到橙色(255, 127, 0)。
原来我们在小学里学到的是减色模型,而不是RGB使用的加色模型。看一下底部的两个图表,你会发现左边是RGB颜色模型(加色),右边是CMYK颜色模型(减色)。你应该能立即看出问题所在。使用减色模型将会产生你想要的结果。

         RGB Color Model                                 CMYK Color Model

编辑: 当然,说起来容易做起来难。也就是说,即使你采用CMYK颜色模型而不是RGB(这本身就很困难,因为从RGB到CMYK的转换极其依赖设备,并且远非直接),这仍然可能无法满足将纯蓝色(0, 0, 255)与纯黄色(255, 255, 0)混合以得到绿色的愿望。CMYK使用青色、洋红色和黄色作为三个原色,而不是红色、黄色和蓝色。如果您想要用您选择的编程语言实现RYB color model,那么您需要做很多工作。

我不知道有没有这样的算法可以真实地组合RGB颜色。在我的回答中,我试图解释为什么这是不可能的,或者至少极其困难。如果你必须坚持使用RGB模型,你可以再等几天看看是否有其他人有什么想法,但我建议你开始制作那个查找表。;-)


1
我正在硬件上实现它,而且我不想改变颜色模型,因为我的输出和输入都是RGB模型。是否有一些算法能够真实地组合RGB颜色,或者我应该使用一个处理所有异常的查找表? - SIMEL
1
@Ilya:我不知道有这样的算法。在我的回答中,我试图解释为什么这是不可能的,或者至少非常困难。你可以再开放几天这个问题,看看是否还有其他人有想法,但如果你需要坚持使用RGB模型,我建议你开始制作查找表。;-) - Cody Gray
1
@cody-gray @ilya-melamed 我不知道有什么算法可以真实地组合RGB颜色。我曾经调查过这个问题,并找到了这篇论文:为真实图像合成建模有色材料。不过我没有读过它... - wip
1
看来 Kubelka-Munk 理论是解决油漆混合问题的唯一可靠的理论框架。 - Davor Josipovic
相关地,最近我偶然发现了这个着色器玩具实现2015年论文“RYB颜色合成” - wip

5

我需要对我的一个库做同样的操作。我采用了这篇论文中提出的建议方法,结果相当可接受。

这个过程非常简单。需要将颜色转换到RYB颜色空间,进行混合,然后将结果转换回RGB。他们提出了一种转换方程,与下表一致:

RGB 颜色 RGB 值 RYB 值
黑色 R: 0 | G: 0 | B: 0 R: 255 | Y: 255 | B: 255
红色 R: 255 | G: 0 | B: 0 R: 255 | Y: 0 | B: 0
绿色 R: 0 | G: 255 | B: 0 R: 0 | Y: 255 | B: 255
蓝色 R: 0 | G: 0 | B: 255 R: 0 | Y: 0 | B: 255
黄色 R: 255 | G: 255 | B: 0 R: 0 | Y: 255 | B: 0
品红 R: 255 | G: 0 | B: 255 R: 255 | Y: 0 | B: 127.5
青色 R: 0 | G: 255 | B: 255 R: 0 | Y: 127.5 | B: 255
白色 R: 255 | G: 255 | B: 255 R: 0 | Y: 0 | B: 0

这里提出了一些公式(以TypeScript代码作为伪代码):

type RYBObject = {
    r: number;
    y: number;
    b: number;
};

export const rgbToRYB = (r: number, g: number, b: number): RYBObject => {
    const Iw = Math.min(r, g, b);
    const Ib = Math.min(255 - r, 255 - g, 255 - b);
    const rRGB = r - Iw;
    const gRGB = g - Iw;
    const bRGB = b - Iw;
    const minRG = Math.min(rRGB, gRGB);
    const rRYB = rRGB - minRG;
    const yRYB = (gRGB + minRG) / 2;
    const bRYB = (bRGB + gRGB - minRG) / 2;
    const n = Math.max(rRYB, yRYB, bRYB, 1) / Math.max(rRGB, gRGB, bRGB, 1);
    return {
        r: rRYB / n + Ib,
        y: yRYB / n + Ib,
        b: bRYB / n + Ib
    };
};

type RGBObject = {
    r: number;
    g: number;
    b: number;
};

export const rybToRGB = (r: number, y: number, b: number): RGBObject => {
    const Iw = Math.min(r, y, b);
    const Ib = Math.min(255 - r, 255 - y, 255 - b);
    const rRYB = r - Iw;
    const yRYB = y - Iw;
    const bRYB = b - Iw;
    const minYB = Math.min(yRYB, bRYB);
    const rRGB = rRYB + yRYB - minYB;
    const gRGB = yRYB + minYB;
    const bRGB = 2 * (bRYB - minYB);
    const n = Math.max(rRGB, gRGB, bRGB, 1) / Math.max(rRYB, yRYB, bRYB, 1);
    return {
        r: rRGB / n + Ib,
        g: gRGB / n + Ib,
        b: bRGB / n + Ib
    };
};

你可以使用这种方法混合颜色:

const mixColors = (c1: RYBObject, c2: RYBObject): RYBObject => ({
    r: Math.min(255, c1.r + c2.r),
    y: Math.min(255, c1.y + c2.y),
    b: Math.min(255, c1.b + c2.b)
});

// color1 and color2 are the input colors in the shape of RGBObject
const mixedColor = rybToRGB(
    mixColors(
        rgbToRYB(color1),
        rgbToRYB(color2)
    )
);

在这里,您可以看到使用我构建的库所得到的结果,该库使用上述方法来实现混合效果:

const { ColorTranslator, Mix } = colortranslator;

const mixes = [
  '#FF0000',
  '#FFFF00',
  '#0000FF',
  [1, 3],
  [1, 2],
  [2, 3],
  [1, 2, 3]
];

const paths = document.querySelectorAll('#planes path');

paths.forEach((path, index) => {
    let color = '#CCCCCC';
    if (mixes[index]) {
      if (typeof mixes[index] === 'string') {
        color = mixes[index];
      } else {
        const colors = mixes[index].map((i) => mixes[i - 1]);
        color = mixes[index] = ColorTranslator.getMixHEX(colors, Mix.SUBTRACTIVE);           
      }
    }  
    path.setAttribute('fill', color);
});
body, html {
  height: 100%;
}

svg {
  height: 100%;
  width: 100%;
}
<script src="https://unpkg.com/colortranslator@1.10.1/web/colortranslator.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
    <g id="planes">
        <path d="M250,210.9929A144.2657,144.2657,0,0,1,392.9611,192.67a144.125,144.125,0,1,0-287.0788-18.3437,145.5121,145.5121,0,0,0,1.1566,18.3437A144.2657,144.2657,0,0,1,250,210.9929Z"/>
        <path d="M409.4255,200.84a145.5235,145.5235,0,0,0-16.4644-8.17,144.2654,144.2654,0,0,1-87.3487,114.6464A144.2658,144.2658,0,0,1,250,440.2858,144.125,144.125,0,1,0,409.4255,200.84Z"/>
        <path d="M194.3876,307.3163A144.2654,144.2654,0,0,1,107.0389,192.67,144.1177,144.1177,0,1,0,250,440.2858,144.2658,144.2658,0,0,1,194.3876,307.3163Z"/>
        <path d="M194.3876,307.3163A144.5321,144.5321,0,0,1,250,210.9929,144.2657,144.2657,0,0,0,107.0389,192.67,144.2654,144.2654,0,0,0,194.3876,307.3163Z"/>
        <path d="M250,210.9929a144.5321,144.5321,0,0,1,55.6124,96.3234A144.2654,144.2654,0,0,0,392.9611,192.67,144.2657,144.2657,0,0,0,250,210.9929Z"/>
        <path d="M305.6124,307.3163a144.532,144.532,0,0,1-111.2248,0A144.2658,144.2658,0,0,0,250,440.2858,144.2658,144.2658,0,0,0,305.6124,307.3163Z"/>
        <path d="M250,210.9929a144.5321,144.5321,0,0,0-55.6124,96.3234,144.532,144.532,0,0,0,111.2248,0A144.5321,144.5321,0,0,0,250,210.9929Z"/>
    </g>
    <g id="letters">
        <path d="M249.5908,115.1084h-.04l-2.2608,1.22-.34-1.34,2.8408-1.52h1.5v13.0029h-1.7Z"/>
        <path d="M254.2119,265.5859v1.16l-5.6611,11.8428h-1.82l5.6406-11.503v-.04H246.01v-1.46Z"/>
        <path d="M377.5254,347.1016v-1.08l1.38-1.34c3.32-3.1611,4.8213-4.8418,4.8408-6.8017a2.32,2.32,0,0,0-2.58-2.541,4.427,4.427,0,0,0-2.7607,1.1006l-.5606-1.24a5.7088,5.7088,0,0,1,3.6807-1.32,3.6594,3.6594,0,0,1,3.9814,3.7813c0,2.4-1.74,4.3408-4.4814,6.9814l-1.04.96v.04h5.8417v1.46Z"/>
        <path d="M109.436,345.08a5.88,5.88,0,0,0,2.88.82c2.2607,0,2.9609-1.44,2.9409-2.5195-.02-1.82-1.6606-2.6016-3.3608-2.6016h-.98v-1.32h.98c1.28,0,2.9009-.66,2.9009-2.2,0-1.04-.66-1.96-2.2808-1.96a4.7821,4.7821,0,0,0-2.6006.8594l-.46-1.2793a6.1819,6.1819,0,0,1,3.4008-1c2.5606,0,3.7207,1.5195,3.7207,3.1a3.2286,3.2286,0,0,1-2.4,3.0606v.041a3.3856,3.3856,0,0,1,2.9,3.34c0,2.0811-1.62,3.9014-4.7412,3.9014a6.6111,6.6111,0,0,1-3.38-.88Z"/>
        <path d="M169.7305,235.2827v-3.5405H163.69v-1.1607L169.49,222.28h1.9v8.082h1.8208v1.38h-1.8208v3.5405Zm0-4.9209v-4.3413q0-1.02.06-2.04h-.06c-.4.76-.72,1.32-1.08,1.92l-3.1807,4.4209v.04Z"/>
        <path d="M325.0127,223.76h-4.9609l-.5,3.3408a6.9313,6.9313,0,0,1,1.06-.08,5.4945,5.4945,0,0,1,2.8008.7,3.7056,3.7056,0,0,1,1.86,3.3408,4.511,4.511,0,0,1-4.8409,4.4409,6.3659,6.3659,0,0,1-3.24-.8l.44-1.34a5.8208,5.8208,0,0,0,2.7812.72,2.8686,2.8686,0,0,0,3.08-2.8208c-.02-1.68-1.14-2.88-3.74-2.88a13.4421,13.4421,0,0,0-1.8008.14l.84-6.2417h6.2217Z"/>
        <path d="M253.1924,362.9092a6.3162,6.3162,0,0,0-1.32.08,5.2845,5.2845,0,0,0-4.5215,4.6211h.06a3.9634,3.9634,0,0,1,7.0621,2.7,4.3479,4.3479,0,0,1-4.3213,4.5811c-2.7808,0-4.6011-2.16-4.6011-5.541a8.1752,8.1752,0,0,1,2.2-5.8613,7.08,7.08,0,0,1,4.1616-1.9209,8.557,8.557,0,0,1,1.28-.1Zm-.5,7.5019c0-1.86-1.0606-2.9814-2.6812-2.9814a2.8967,2.8967,0,0,0-2.52,1.6006,1.4976,1.4976,0,0,0-.2.78c.04,2.1407,1.02,3.7207,2.8609,3.7207C251.6719,373.5312,252.6924,372.2715,252.6924,370.4111Z"/>
     </g>
 </svg>

这个 CodePen中,您可以查看混合颜色时加法模式和减法模式之间的区别。


5
根据这个文档中的回答和这个算法感知中的回答,我尝试使用加性和减性方法混合颜色的简单接口。
您必须确认RGB和CMYK的主要颜色在第一个响应图中给出了二次颜色:
  • 红+蓝=洋红(在加性中)
  • 黄+青=绿(在减性中)
  • 依此类推...
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Color Mixing alghoritms
 * User: alberto
 * Date: 29/01/13
 * Time: 21:28
 */
public class ColorMix {

    Vector<JLabel> firstMixColors;
    Vector<JLabel> secondMixColors;
    JComboBox/*<Mixer>*/ comboBox;
    JLabel firstMixColor;
    JLabel firstSel;
    JLabel secondSel;
    JLabel finalColor;

    public ColorMix() {
        firstMixColors = new Vector<JLabel>();
        Vector<Mixer> mixers = new Vector<Mixer>();
        mixers.add(new AdditiveMixer());
        mixers.add(new SustractiveMixer());
        mixers.add(new TertiaryMixer());
        mixers.add(new DilutingSustractiveMixer());

        comboBox = new JComboBox(new DefaultComboBoxModel(mixers));
        firstMixColor = buildColorLabel();
        firstSel = buildColorLabel();
        secondSel = buildColorLabel();
        secondMixColors = new Vector<JLabel>();
        secondMixColors.add(firstSel);
        secondMixColors.add(secondSel);
        finalColor = buildColorLabel();
        comboBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                calculateMixes();
            }
        });
        buildGUI();
    }

    private JLabel buildColorLabel() {
        JLabel label = new JLabel();
        label.setOpaque(true);
        label.setHorizontalAlignment(SwingConstants.CENTER);
        label.setHorizontalTextPosition(SwingConstants.CENTER);
        label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        label.setPreferredSize(new Dimension(100,25));
        return label;
    }

    public void buildGUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setTitle("Mixing colors");

        frame.setLayout(new GridBagLayout());
        GridBagConstraints cc = new GridBagConstraints();
        cc.fill = GridBagConstraints.BOTH;
        cc.insets = new Insets(5, 5, 5, 5);
        cc.weightx = .2;
        cc.weighty = 1;
        frame.getContentPane().add(buildColorPanel(0), cc);
        frame.getContentPane().add(buildColorPanel(1), cc);
        cc.gridy = 1;
        JPanel firstMix = new JPanel(new GridBagLayout());
        GridBagConstraints ccCol = new GridBagConstraints();
        ccCol.fill = GridBagConstraints.BOTH;
        ccCol.insets = new Insets(5, 5, 5, 5);
        ccCol.weightx = 1;
        ccCol.weighty = 1;

        ccCol.gridx = 0;
        ccCol.gridy = 0;
        ccCol.gridheight = 2;
        firstMix.add(firstMixColor, ccCol);
        ccCol.fill = GridBagConstraints.HORIZONTAL;
        ccCol.weightx = 0.2;
        ccCol.weighty = 0.5;
        ccCol.gridx = 1;
        ccCol.gridy = 0;
        ccCol.gridheight = 1;
        ccCol.gridwidth = 1;
        firstMix.add(new JButton(new AbstractAction("Set First") {
            @Override
            public void actionPerformed(ActionEvent e) {
                setBackgroundToLabel(firstSel, firstMixColor.getBackground());
                calculateMixes();
            }
        }), ccCol);
        ccCol.gridx = 1;
        ccCol.gridy = 1;
        firstMix.add(new JButton(new AbstractAction("Set Second") {
            @Override
            public void actionPerformed(ActionEvent e) {
                setBackgroundToLabel(secondSel, firstMixColor.getBackground());
                calculateMixes();
            }
        }), ccCol);
        firstMix.setBorder(BorderFactory.createTitledBorder("Secondary Colors"));
        frame.getContentPane().add(firstMix, cc);
        cc.weightx = .6;

        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints ccColor = new GridBagConstraints();
        ccColor.fill = GridBagConstraints.BOTH;
        ccColor.insets = new Insets(5, 5, 5, 5);
        ccColor.weightx = 1;
        ccColor.weighty = 1;
        panel.add(firstSel, ccColor);
        ccColor.gridx = 1;
        panel.add(secondSel, ccColor);
        ccColor.gridx = 0;
        ccColor.gridy = 1;
        ccColor.weighty = 0;
        ccColor.gridwidth = 2;
        panel.add(finalColor, ccColor);
        ccColor.gridy = 2;
        panel.add(comboBox, ccColor);
        panel.setBorder(BorderFactory.createTitledBorder("Tertiary Colors"));
        frame.getContentPane().add(panel, cc);
        frame.pack();
        frame.setVisible(true);
    }


    public static void main(String[] args) {
        new ColorMix();
    }

    private JComponent buildColorPanel(int selectedIndex) {
        final JLabel pColor = buildColorLabel();
        firstMixColors.add(pColor);
        JPanel pSelectColor = new JPanel(new GridBagLayout());
        GridBagConstraints cc = new GridBagConstraints();
        cc.fill = GridBagConstraints.BOTH;
        cc.insets = new Insets(5, 5, 5, 5);
        cc.weightx = 1;
        cc.weighty = 1;
        final JSlider slidRed = buildSlider(pSelectColor, cc);
        final JSlider slidGreen = buildSlider(pSelectColor, cc);
        final JSlider slidBlue = buildSlider(pSelectColor, cc);
        pSelectColor.add(pColor, cc);
        final JComboBox comboColores = buildColorCombo();
        comboColores.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Color color = (Color) comboColores.getSelectedItem();
                slidRed.setValue(color.getRed());
                slidGreen.setValue(color.getGreen());
                slidBlue.setValue(color.getBlue());
            }
        });
        comboColores.setSelectedIndex(selectedIndex);
        cc.gridy = 1;
        cc.gridwidth = 4;
        cc.weighty = 0;
        pSelectColor.add(comboColores, cc);
        ChangeListener changeListener = new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                setBackgroundToLabel(pColor, new Color(slidRed.getValue(), slidGreen.getValue(), slidBlue.getValue()));
                calculateMixes();
            }
        };
        slidRed.addChangeListener(changeListener);
        slidGreen.addChangeListener(changeListener);
        slidBlue.addChangeListener(changeListener);
        pSelectColor.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
        changeListener.stateChanged(null);
        return pSelectColor;
    }

    private JComboBox buildColorCombo() {
        Color TRANSPARENT = new Color(0, 0, 0, 0);

        Vector<Color> colors = new Vector<Color>();

        colors.add(new NamedColor(Color.RED, "Red"));
        colors.add(new NamedColor(Color.GREEN, "Green"));
        colors.add(new NamedColor(Color.BLUE, "Blue"));

        colors.add(new NamedColor(Color.YELLOW, "Yellow"));
        colors.add(new NamedColor(Color.MAGENTA, "Magenta"));
        colors.add(new NamedColor(Color.CYAN, "Cyan"));

        colors.add(new NamedColor(Color.WHITE, "White"));
        colors.add(new NamedColor(Color.LIGHT_GRAY, "Light Gray"));
        colors.add(new NamedColor(Color.GRAY, "Gray"));
        colors.add(new NamedColor(Color.DARK_GRAY, "Dark Gray"));
        colors.add(new NamedColor(Color.BLACK, "Black"));
        colors.add(new NamedColor(Color.PINK, "Pink"));
        colors.add(new NamedColor(Color.ORANGE, "Orange"));

        colors.add(new NamedColor(TRANSPARENT, "transparent"));
        //http://www.w3schools.com/css/css_colornames.asp
        colors.add(new NamedColor(new Color(0xf0f8ff), "aliceblue"));
        colors.add(new NamedColor(new Color(0xfaebd7), "antiquewhite"));
        colors.add(new NamedColor(new Color(0x00ffff), "aqua"));
        colors.add(new NamedColor(new Color(0x7fffd4), "aquamarine"));
        colors.add(new NamedColor(new Color(0xf0ffff), "azure"));
        colors.add(new NamedColor(new Color(0xf5f5dc), "beige"));
        colors.add(new NamedColor(new Color(0xffe4c4), "bisque"));
        colors.add(new NamedColor(new Color(0x000000), "black"));
        colors.add(new NamedColor(new Color(0xffebcd), "blanchedalmond"));
        colors.add(new NamedColor(new Color(0x0000ff), "blue"));
        colors.add(new NamedColor(new Color(0x8a2be2), "blueviolet"));
        colors.add(new NamedColor(new Color(0xa52a2a), "brown"));
        colors.add(new NamedColor(new Color(0xdeb887), "burlywood"));
        colors.add(new NamedColor(new Color(0x5f9ea0), "cadetblue"));
        colors.add(new NamedColor(new Color(0x7fff00), "chartreuse"));
        colors.add(new NamedColor(new Color(0xd2691e), "chocolate"));
        colors.add(new NamedColor(new Color(0xff7f50), "coral"));
        colors.add(new NamedColor(new Color(0x6495ed), "cornflowerblue"));
        colors.add(new NamedColor(new Color(0xfff8dc), "cornsilk"));
        colors.add(new NamedColor(new Color(0xdc143c), "crimson"));
        colors.add(new NamedColor(new Color(0x00ffff), "cyan"));
        colors.add(new NamedColor(new Color(0x00008b), "darkblue"));
        colors.add(new NamedColor(new Color(0x008b8b), "darkcyan"));
        colors.add(new NamedColor(new Color(0xb8860b), "darkgoldenrod"));
        colors.add(new NamedColor(new Color(0xa9a9a9), "darkgray"));
        colors.add(new NamedColor(new Color(0xa9a9a9), "darkgrey"));
        colors.add(new NamedColor(new Color(0x006400), "darkgreen"));
        colors.add(new NamedColor(new Color(0xbdb76b), "darkkhaki"));
        colors.add(new NamedColor(new Color(0x8b008b), "darkmagenta"));
        colors.add(new NamedColor(new Color(0x556b2f), "darkolivegreen"));
        colors.add(new NamedColor(new Color(0xff8c00), "darkorange"));
        colors.add(new NamedColor(new Color(0x9932cc), "darkorchid"));
        colors.add(new NamedColor(new Color(0x8b0000), "darkred"));
        colors.add(new NamedColor(new Color(0xe9967a), "darksalmon"));
        colors.add(new NamedColor(new Color(0x8fbc8f), "darkseagreen"));
        colors.add(new NamedColor(new Color(0x483d8b), "darkslateblue"));
        colors.add(new NamedColor(new Color(0x2f4f4f), "darkslategray"));
        colors.add(new NamedColor(new Color(0x2f4f4f), "darkslategrey"));
        colors.add(new NamedColor(new Color(0x00ced1), "darkturquoise"));
        colors.add(new NamedColor(new Color(0x9400d3), "darkviolet"));
        colors.add(new NamedColor(new Color(0xff1493), "deeppink"));
        colors.add(new NamedColor(new Color(0x00bfff), "deepskyblue"));
        colors.add(new NamedColor(new Color(0x696969), "dimgray"));
        colors.add(new NamedColor(new Color(0x696969), "dimgrey"));
        colors.add(new NamedColor(new Color(0x1e90ff), "dodgerblue"));
        colors.add(new NamedColor(new Color(0xb22222), "firebrick"));
        colors.add(new NamedColor(new Color(0xfffaf0), "floralwhite"));
        colors.add(new NamedColor(new Color(0x228b22), "forestgreen"));
        colors.add(new NamedColor(new Color(0xff00ff), "fuchsia"));
        colors.add(new NamedColor(new Color(0xdcdcdc), "gainsboro"));
        colors.add(new NamedColor(new Color(0xf8f8ff), "ghostwhite"));
        colors.add(new NamedColor(new Color(0xffd700), "gold"));
        colors.add(new NamedColor(new Color(0xdaa520), "goldenrod"));
        colors.add(new NamedColor(new Color(0x808080), "gray"));
        colors.add(new NamedColor(new Color(0x808080), "grey"));
        colors.add(new NamedColor(new Color(0x008000), "green"));
        colors.add(new NamedColor(new Color(0xadff2f), "greenyellow"));
        colors.add(new NamedColor(new Color(0xf0fff0), "honeydew"));
        colors.add(new NamedColor(new Color(0xff69b4), "hotpink"));
        colors.add(new NamedColor(new Color(0xcd5c5c), "indianred"));
        colors.add(new NamedColor(new Color(0x4b0082), "indigo"));
        colors.add(new NamedColor(new Color(0xfffff0), "ivory"));
        colors.add(new NamedColor(new Color(0xf0e68c), "khaki"));
        colors.add(new NamedColor(new Color(0xe6e6fa), "lavender"));
        colors.add(new NamedColor(new Color(0xfff0f5), "lavenderblush"));
        colors.add(new NamedColor(new Color(0x7cfc00), "lawngreen"));
        colors.add(new NamedColor(new Color(0xfffacd), "lemonchiffon"));
        colors.add(new NamedColor(new Color(0xadd8e6), "lightblue"));
        colors.add(new NamedColor(new Color(0xf08080), "lightcoral"));
        colors.add(new NamedColor(new Color(0xe0ffff), "lightcyan"));
        colors.add(new NamedColor(new Color(0xfafad2), "lightgoldenrodyellow"));
        colors.add(new NamedColor(new Color(0xd3d3d3), "lightgray"));
        colors.add(new NamedColor(new Color(0xd3d3d3), "lightgrey"));
        colors.add(new NamedColor(new Color(0x90ee90), "lightgreen"));
        colors.add(new NamedColor(new Color(0xffb6c1), "lightpink"));
        colors.add(new NamedColor(new Color(0xffa07a), "lightsalmon"));
        colors.add(new NamedColor(new Color(0x20b2aa), "lightseagreen"));
        colors.add(new NamedColor(new Color(0x87cefa), "lightskyblue"));
        colors.add(new NamedColor(new Color(0x778899), "lightslategray"));
        colors.add(new NamedColor(new Color(0x778899), "lightslategrey"));
        colors.add(new NamedColor(new Color(0xb0c4de), "lightsteelblue"));
        colors.add(new NamedColor(new Color(0xffffe0), "lightyellow"));
        colors.add(new NamedColor(new Color(0x00ff00), "lime"));
        colors.add(new NamedColor(new Color(0x32cd32), "limegreen"));
        colors.add(new NamedColor(new Color(0xfaf0e6), "linen"));
        colors.add(new NamedColor(new Color(0xff00ff), "magenta"));
        colors.add(new NamedColor(new Color(0x800000), "maroon"));
        colors.add(new NamedColor(new Color(0x66cdaa), "mediumaquamarine"));
        colors.add(new NamedColor(new Color(0x0000cd), "mediumblue"));
        colors.add(new NamedColor(new Color(0xba55d3), "mediumorchid"));
        colors.add(new NamedColor(new Color(0x9370d8), "mediumpurple"));
        colors.add(new NamedColor(new Color(0x3cb371), "mediumseagreen"));
        colors.add(new NamedColor(new Color(0x7b68ee), "mediumslateblue"));
        colors.add(new NamedColor(new Color(0x00fa9a), "mediumspringgreen"));
        colors.add(new NamedColor(new Color(0x48d1cc), "mediumturquoise"));
        colors.add(new NamedColor(new Color(0xc71585), "mediumvioletred"));
        colors.add(new NamedColor(new Color(0x191970), "midnightblue"));
        colors.add(new NamedColor(new Color(0xf5fffa), "mintcream"));
        colors.add(new NamedColor(new Color(0xffe4e1), "mistyrose"));
        colors.add(new NamedColor(new Color(0xffe4b5), "moccasin"));
        colors.add(new NamedColor(new Color(0xffdead), "navajowhite"));
        colors.add(new NamedColor(new Color(0x000080), "navy"));
        colors.add(new NamedColor(new Color(0xfdf5e6), "oldlace"));
        colors.add(new NamedColor(new Color(0x808000), "olive"));
        colors.add(new NamedColor(new Color(0x6b8e23), "olivedrab"));
        colors.add(new NamedColor(new Color(0xffa500), "orange"));
        colors.add(new NamedColor(new Color(0xff4500), "orangered"));
        colors.add(new NamedColor(new Color(0xda70d6), "orchid"));
        colors.add(new NamedColor(new Color(0xeee8aa), "palegoldenrod"));
        colors.add(new NamedColor(new Color(0x98fb98), "palegreen"));
        colors.add(new NamedColor(new Color(0xafeeee), "paleturquoise"));
        colors.add(new NamedColor(new Color(0xd87093), "palevioletred"));
        colors.add(new NamedColor(new Color(0xffefd5), "papayawhip"));
        colors.add(new NamedColor(new Color(0xffdab9), "peachpuff"));
        colors.add(new NamedColor(new Color(0xcd853f), "peru"));
        colors.add(new NamedColor(new Color(0xffc0cb), "pink"));
        colors.add(new NamedColor(new Color(0xdda0dd), "plum"));
        colors.add(new NamedColor(new Color(0xb0e0e6), "powderblue"));
        colors.add(new NamedColor(new Color(0x800080), "purple"));
        colors.add(new NamedColor(new Color(0xff0000), "red"));
        colors.add(new NamedColor(new Color(0xbc8f8f), "rosybrown"));
        colors.add(new NamedColor(new Color(0x4169e1), "royalblue"));
        colors.add(new NamedColor(new Color(0x8b4513), "saddlebrown"));
        colors.add(new NamedColor(new Color(0xfa8072), "salmon"));
        colors.add(new NamedColor(new Color(0xf4a460), "sandybrown"));
        colors.add(new NamedColor(new Color(0x2e8b57), "seagreen"));
        colors.add(new NamedColor(new Color(0xfff5ee), "seashell"));
        colors.add(new NamedColor(new Color(0xa0522d), "sienna"));
        colors.add(new NamedColor(new Color(0xc0c0c0), "silver"));
        colors.add(new NamedColor(new Color(0x87ceeb), "skyblue"));
        colors.add(new NamedColor(new Color(0x6a5acd), "slateblue"));
        colors.add(new NamedColor(new Color(0x708090), "slategray"));
        colors.add(new NamedColor(new Color(0x708090), "slategrey"));
        colors.add(new NamedColor(new Color(0xfffafa), "snow"));
        colors.add(new NamedColor(new Color(0x00ff7f), "springgreen"));
        colors.add(new NamedColor(new Color(0x4682b4), "steelblue"));
        colors.add(new NamedColor(new Color(0xd2b48c), "tan"));
        colors.add(new NamedColor(new Color(0x008080), "teal"));
        colors.add(new NamedColor(new Color(0xd8bfd8), "thistle"));
        colors.add(new NamedColor(new Color(0xff6347), "tomato"));
        colors.add(new NamedColor(new Color(0x40e0d0), "turquoise"));
        colors.add(new NamedColor(new Color(0xee82ee), "violet"));
        colors.add(new NamedColor(new Color(0xf5deb3), "wheat"));
        colors.add(new NamedColor(new Color(0xffffff), "white"));
        colors.add(new NamedColor(new Color(0xf5f5f5), "whitesmoke"));
        colors.add(new NamedColor(new Color(0xffff00), "yellow"));
        colors.add(new NamedColor(new Color(0x9acd32), "yellowgreen"));

        JComboBox comboBox = new JComboBox(new DefaultComboBoxModel(colors));
        comboBox.setRenderer(new DefaultListCellRenderer() {
            protected Color backgroundColor = Color.BLACK;

            {
                setBorder(new CompoundBorder(
                        new MatteBorder(2, 5, 2, 5, Color.white)
                        , new LineBorder(Color.black)));
            }

            public Component getListCellRendererComponent(JList list, Object obj,
                                                          int row, boolean sel, boolean hasFocus) {
                if (obj instanceof Color)
                    backgroundColor = (Color) obj;
                setText(obj.toString());
                return this;
            }

            public void paint(Graphics g) {
                setBackground(backgroundColor);
                super.paint(g);
            }
        });


        return comboBox;
    }

    class NamedColor extends Color {
        private String name;

        NamedColor(Color color, String name) {
            super(color.getRed(), color.getGreen(), color.getBlue());
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    private void calculateMixes() {
        calculateFirstMix();
        calculateSecondMix();
    }

    private void calculateFirstMix() {
        calculateMix(firstMixColors, firstMixColor);
    }

    private void calculateSecondMix() {
        calculateMix(secondMixColors, finalColor);
    }

    private void calculateMix(Vector<JLabel> mixColors, JLabel finalColor) {
        Color bg = ((Mixer) comboBox.getSelectedItem()).calculateMix(mixColors);
        setBackgroundToLabel(finalColor, bg);
    }

    private void setBackgroundToLabel(JLabel label, Color color) {
        label.setBackground(color);
        label.setText(color.getRed() + "," + color.getGreen() + "," + color.getBlue());
    }

    interface Mixer {
        Color calculateMix(Vector<JLabel> colores);
    }

    /**
     * Implement a additive mix of colors
     */
    static class AdditiveMixer implements Mixer {
        public Color calculateMix(Vector<JLabel> colores) {
            int red = 0;
            int green = 0;
            int blue = 0;
            for (int i = 0; i < colores.size(); i++) {
                Color background = colores.get(i).getBackground();
                red += background.getRed();
                green += background.getGreen();
                blue += background.getBlue();
            }
            return new Color(Math.min(255, red), Math.min(255, green), Math.min(255, blue));
        }

        @Override
        public String toString() {
            return "Additive";
        }
    }

    /**
     * Implement a sustractive mix of colors
     */
    static class SustractiveMixer implements Mixer {
        public Color calculateMix(Vector<JLabel> colores) {
            int red = 1;
            int green = 1;
            int blue = 1;
            for (int i = 0; i < colores.size(); i++) {
                Color background = colores.get(i).getBackground();
                red *= background.getRed();
                green *= background.getGreen();
                blue *= background.getBlue();
            }
            return new Color(Math.min(255, red / 255), Math.min(255, green / 255), Math.min(255, blue / 255));
        }

        @Override
        public String toString() {
            return "Sustractive";
        }
    }

    /**
     * Implement a diluting/sustractive mix of colors
     */
    static class DilutingSustractiveMixer implements Mixer {
        public Color calculateMix(Vector<JLabel> colores) {
            int red = 0;
            int green = 0;
            int blue = 0;
            for (int i = 0; i < colores.size(); i++) {
                Color background = colores.get(i).getBackground();
                red += Math.pow(255 - background.getRed(), 2);
                green += Math.pow(255 - background.getGreen(), 2);
                blue += Math.pow(255 - background.getBlue(), 2);
            }
            return new Color(Math.min(255, (int)Math.sqrt(red / colores.size())), Math.min(255, (int)Math.sqrt(green / colores.size())), Math.min(255, (int)Math.sqrt(blue / colores.size())));
        }

        @Override
        public String toString() {
            return "Diluting/Sustractive";
        }
    }

    /**
     * Implement a diluting/sustractive mix of colors
     */
    static class TertiaryMixer implements Mixer {
        public Color calculateMix(Vector<JLabel> colores) {
            Color background1 = colores.get(0).getBackground();
            int red = background1.getRed();
            int green = background1.getGreen();
            int blue = background1.getBlue();
            Color background2 = colores.get(1).getBackground();
            red -= background2.getRed();
            green -= background2.getGreen();
            blue -= background2.getBlue();
            return new Color(Math.min(255, background1.getRed() - (red/2)), Math.min(255, background1.getGreen() - (green/2)), background1.getBlue() - (blue/2));
        }

        @Override
        public String toString() {
            return "Tertiary";
        }
    }

    private JSlider buildSlider(JPanel container, GridBagConstraints upperCC) {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints cc = new GridBagConstraints();
        cc.fill = GridBagConstraints.BOTH;
        cc.insets = new Insets(5, 5, 5, 5);
        cc.weightx = 1;
        cc.weighty = 0.7;

        final JSlider slider = new JSlider(JSlider.VERTICAL, 0, 255, 0);
        slider.setFont(new Font("Serif", Font.PLAIN, 4));

        Hashtable<Integer, JLabel> labels = new Hashtable<Integer, JLabel>();
        labels.put(0, new JLabel("0"));
        labels.put(128, new JLabel("128"));
        labels.put(255, new JLabel("255"));
        panel.add(slider, cc);
        final JTextField field = new JTextField();
        field.setEditable(false);
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                field.setText(String.valueOf(slider.getValue()));
            }
        });
        cc.gridx = 0;
        cc.gridy = 1;
        cc.weighty = 0;

        panel.add(field, cc);
        slider.setLabelTable(labels);
        slider.setPaintLabels(true);

        container.add(panel, upperCC);

        return slider;
    }
}

颜色混合界面

基本上,这些操作就像逻辑AND和逻辑OR。(但不完全是)

  • 在加法算法中,颜色重叠,但对于每个原色,最大只能为255(逻辑OR运算)
  • 在减法算法中,如果某个原色不存在,则结果中也不会有该颜色(CYAN没有RED,YELLOW没有BLUE:你会得到GREEN)(逻辑AND运算)

根据此处可以从主要和次要颜色的混合中获得三元颜色,所以我制作了一个很好的小实现:

NewColor.R = Color1.R - (Color1.R - Color2.R)/2
NewColor.G = Color1.G - (Color1.G - Color2.G)/2
NewColor.B = Color1.B - (Color1.B - Color2.B)/2

第二个引用回复中还提到了一种稀释/减法算法,但我不知道它基于什么,只是为了测试而添加的。


3
你所发布的全部代码是否都是回答问题所必需的?如果不是,请尽量简化代码,并在需要时提供指向扩展代码片段的链接。 - markus
是的,如果你想尝试这段代码,我认为图片已经足够了,我会尽快完成。 - albfan

4
真正的答案是将RGB颜色向量空间转换为一种加性空间,然后再转换回RGB。在这个新的向量空间中,当你添加两个光矢量时,它考虑了光的加性特性和我们对颜色的感知,产生了一种加性颜色。
结果发现CIE XYZ向量空间在这方面很有效。
在这个空间中,XYZ向量是可加的,并且像光源一样混合。
请参见Cree的这篇关于颜色混合的论文
X_mix = X1 + X2 + ...

Y_mix = Y1 + Y2 + ...

Z_mix = Z1 + Z2 + ...

你可以将基础色彩空间改回RGB。有许多库可用于在向量空间之间更改颜色,而CIEXYZ是标准化且得到广泛支持的。
这种方法产生逼真的结果,适合我大部分的需求。
有关CIE 1931色彩空间的更多信息。

3
我想指出为什么你在添加蓝色时会变成灰色。这是因为你添加的是蓝色,而不是青色。
- 如果向黄色中加入青色,你会得到绿色。 - 如果向黄色中加入蓝色(即青色和洋红色),你会得到灰色。
更数学地说:
Yellow + (Cyan          ) = Green  
Yellow + (Cyan + Magenta) = Gray
Yellow + (Blue)           = Gray

您正在添加蓝色,而您实际想要添加的是青色
0.5*Yellow(255,255,0) + 0.5*Cyan(0,255,255) = VeryLightLimeGreen(128,255,128)

如果您使用 CMYK 颜色模型,那么这种情况就会发生。在 RYB 颜色模型中,蓝色 + 黄色 = 绿色 - ElChiniNet
我正在研究一个 Delphi 实现的问题,真巧! - user30478

3

看了Cody Gray的回答,我认为我可以建议如何组合颜色。将色轮转换为RGB:

                cyan(0, 255, 255)
        blue(0, 0, 255) green(0, 255, 0)
magenta(255, 0, 255) red(255, 0, 0) yellow(255, 255, 0)

不需要额外的复杂操作,可以将颜色组合如下:反转两种颜色,将它们加在一起,然后再次反转结果(ActionScript):

sum(0, 255, 255,   255, 0, 255, "cyan + magenta =");
sum(255, 0, 0,     0, 255, 0,   "red + green =");
sum(0, 0, 0,       0, 0, 0,     "black + black =");
sum(0, 0, 0,       255, 255, 255, "black + white =");

function sum(c1:int, c2:int, c3:int, b1:int, b2:int, b3:int, m:String):void {
    c1 = 255 - c1; c2 = 255 - c2; c3 = 255 - c3;
    b1 = 255 - b1; b2 = 255 - b2; b3 = 255 - b3;
    var d1:int = c1 + b1;
    var d2:int = c2 + b2;
    var d3:int = c3 + b3;
    d1 = 255 - d1; d2 = 255 - d2; d3 = 255 - d3;
    d1 = clamp(d1); d2 = clamp(d2); d3 = clamp(d3);
    trace(m, d1, d2, d3);
}

function clamp(value:int):int {
    if (value < 0) return 0;
    if (value > 255) return 255;
    return value;
}

输出:

cyan + magenta = 0 0 255
red + green = 0 0 0
black + black = 0 0 0
black + white = 0 0 0

看看这是否适合你。

编辑:我并不是在假装这是物理上正确的,只是试图近似。对于我来说,查找表的想法听起来很疯狂,因为它取决于两个参数,所以它的大小会非常大;而自然规律通常是连续的,没有或很少有角落情况。如果您能填写查找表,那么您应该知道算法-所以只需编写一个函数即可。


我希望它很简单,但我认为它并不简单。我在这里做错了什么?假设我有蓝色 (0, 0, 255) + 黄色 (255, 255, 0)。反转两种颜色:(255, 255, 0) + (0, 0, 255)。将它们相加:(255, 255, 255)。反转结果:(0, 0, 0)。最终得到的是黑色,而不是预期的绿色。 - Cody Gray
(0, 0, 255)和(255, 255, 0)不能产生绿色 - 它们没有共同的成分。可以将其视为两层遮盖白光的油漆,没有共同的光谱线 - 结果是黑色。在你的色轮(右侧),青色明显是(0, 255, 255),而不是(0, 0, 255)。 - alxx
1
青色加黄色会得到绿色,而不是蓝色加黄色。 - alxx
1
当然,我同意这就是它的工作原理。我的观点只是你的算法仍然不能满足最初的请求,即像在艺术课上绘画一样混合颜色。我不会尝试混合青色和黄色来得到绿色。 - Cody Gray
@alxx - 这个算法适用于4种颜色混合吗:A+B(=X),C+D(=Y),然后将这些结果组合在一起得到X+Y作为最终颜色?还是适用于3种颜色混合:A+B(=X),然后C+X? - Ωmega
如果三个或四个颜色有共同的组成部分,为什么不考虑使用它们...否则每次迭代的结果会越来越接近黑色。 - alxx

2
这里是使用Java实现的Kubelka-Munk反射理论,用于混合RGB颜色。该实现使用了一个简化版本的Kubelka-Munk模型,假设在混合时所有颜色的浓度相同且所有颜色都不透明。 https://github.com/benjholla/ColorMixer

我是你项目的忠实粉丝。但是正如其他人指出的那样(红+黄=红),颜色混合还没有正确实现。 - Tom Pažourek
抱歉回复得这么慢。您说得对,我的实现似乎有些问题,特别是在红色方面。不幸的是,我不确定出了什么问题或如何解决它。我已经在存储库上放了一条注释警告其他人注意。 - Ben Holland

1

我认为以上的答案没有给出足够的混合结果。

我一直在使用RGB和RYB(从RGB转换而来)解决这个问题。这里的RGB到RYB的转换很好:http://www.insanit.net/tag/rgb-to-ryb/(如有需要,我可以分享我的代码)。

如果是光混合,效果还不错(见下文)。如果你想像油漆一样混合物理材料,那就有点棘手了——我正在开发一个应用程序来探索它。

回到最初的问题——这是我的RGB混合代码。RgbColor是一个自定义类,但我认为这本身就很有意义:

-(RgbColor*)mixWith:(RgbColor *)aColor {
    int r1, g1, b1, r2, g2, b2, r3, g3, b3, m1, m2, w1, w2, w3; //colors and maxes, white
    float br; // brightness of resulting color

r1 = self.redVal;
g1 = self.greenVal;
b1 = self.blueVal;
r2 = aColor.redVal;
g2 = aColor.greenVal;
b2 = aColor.blueVal;

w1 = MIN(r1, MIN(g1, b1));
w2 = MIN(r2, MIN(g2, b2));

// remove white before mixing
r1 -= w1;
g1 -= w1;
b1 -= w1;
r2 -= w2;
g2 -= w2;
b2 -= w2;

m1 = MAX(r1, MAX(g1, b1));
m2 = MAX(r2, MAX(g2, b2));

br = (m1+m2)/(2*255.0);

r3 = (r1+r2)*br;
g3 = (g1+g2)*br;
b3 = (b1+b2)*br;

// average whiteness and add into final color
w3 = (w1+w2)/2;

r3 += w3;
g3 += w3;
b3 += w3;

[self setRedVal:[[NSNumber numberWithFloat:r3] intValue]];
[self setGreenVal:[[NSNumber numberWithFloat:g3] intValue]];
[self setBlueVal:[[NSNumber numberWithFloat:b3] intValue]];
return self;
}

看Github上的代码... 当我混合4个红色(全部都是255,0,0)时,怎么会出现 c1 = c1Total/sqrt((sqrt(count))); 这种情况,你得到的结果将是 1020/sqrt((sqrt(4))) ,它是 721.2489168102785,明显超过了 255..!? - Ωmega
任何超过最大值的颜色都会被设置回最大值,所以你不能拥有高于255(或使用规范化数字时的1.0)的颜色。这种情况经常发生在只有一个组件的颜色中,但是尝试混合155红色和155红色之类的东西,并查看RGB、RYB和CMYK之间的差异,你就开始看到混合的微妙之处了。使用平方根的原因是允许混合更多的颜色而不是直接达到最大值-在github项目上,点击角落以更改那些颜色,然后更改重叠的矩形。享受吧。 - Damien Del Russo
该网站http://www.insanit.net/tag/rgb-to-ryb/的程序给出了0xfff100(黄色)的补色为0xf100ff(品红/紫红),但是在《非设计师的设计书》中,相同颜色的补色是0x5c2c91(紫色)。因此,该程序不适用于设计。 - DSblizzard
@Damien Del Russo:你好。你的网站似乎挂了。我对你的RGB转RYB代码非常感兴趣。我记得几天前在你的网站上看到了一个颜色混合器,它似乎正好符合我的需求。我能以某种方式与你联系吗? - Christoffer
我的代码仍然在Github上 - 尽管我不知道它与现在拥有新API的iOS相比如何。https://github.com/ddelruss/UIColor-Mixing - Damien Del Russo
显示剩余3条评论

0

但我想要的是,它能够知道绿色+红色=黄色,因为黄色是一种自然的基本颜色,而绿色不是。我想通过能够从其他颜色的混合中创建绿色来模仿自然。 - SIMEL
然后使用减法模型。 - user502515

0

关于这个问题已经有很多讨论了,但我想分享一种混合颜色的方法(考虑使用光:加法方案)。

我尝试了Damien Del Russo的示例代码,它似乎是一种不错的方法,使用白色平均值来计算rgb混合。我想将结果与我的(基本和线性)代码进行比较。

以前的代码在某些情况下可能会返回超过255的值...但在这些情况下,如果应用比例来回到0-255范围,结果对我来说是相同的。

对于其他情况(主要是带有白色成分的情况),我可以看到结果上的一些差异。这种差异更多地涉及亮度而不是色度。如果我尝试缩小我获得的值,我会得到非常接近以前代码结果的值...

我还不确定哪种计算方式能够给出更接近亮度方面的结果,但如果我得到答案,我会更新这篇文章并分享结果。

知道了这些,这是我的未完成代码(使用Python作为我的原则测试台)来混合n个元组的RGB颜色:

def rgb_mix_colors(rgb_scale, *colors):
    """ color mix
    :param rgb_scale: scale of values
    :param colors: list of colors (tuple of rgb values)
    :return: relative mix of rgb colors """
    r = g = b = 0

    for item in colors:
        try:
            if not isinstance(item, tuple):
                raise TypeError
            if item[0] > rgb_scale or item[1] > rgb_scale or item[2] > rgb_scale:
                raise ValueError
        except (TypeError, ValueError):
            print "WARNING: Value is outside range or unhandled parameter given as function argument!"
        else:
            r += item[0]    # add red value from item
            g += item[1]    # add green value from item
            b += item[2]    # add blue value from item

    ratio = max(r, g, b)
    if ratio > rgb_scale:
        ratio = float(rgb_scale) / ratio
        r *= ratio
        g *= ratio
        b *= ratio

    return int(r), int(g), int(b)


if __name__ == "__main__":
    col_list = [(512, 10, 256),
                (30, 120, 50),
                (50, 40, 512),
                "exception",        # should raise TypeError when mixing
                (3800, 20, 50),     # should raise ValueError when mixing
                (512, 10, 512)]

    # example with a scale defined at 1024 instead of default, providing list of tuples as params already packed as list
    print "2 warning messages should be displayed on the next line:"
    print rgb_mix_colors(1024, *col_list)
    print rgb_mix_colors(255, (0, 255, 0), (0, 32, 255))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接