Расчет смешанного цвета в RGB - PullRequest
33 голосов
/ 23 ноября 2010

Я хочу иметь возможность взять два вектора RGB-256 и вычислить результат их смешения. Также я хочу, чтобы у каждого вектора был свой вес. Я экспериментировал с ним, используя цветовую пластинку Word, и видел, что некоторые цвета смешиваются в соответствии со средневзвешенным значением:

0.5*red(255,0,0) + 0.5*yellow(255,255,0) = orange(255,127,0)

другие не делают:

0.5*yellow(255,255,0) + 0.5*blue(0,0,255) = gray (127,127,127), а не green (0,255,0)

Существует ли алгоритм точного расчета для всех цветов или я вынужден сделать это с помощью справочной таблицы?

Ответы [ 11 ]

31 голосов
/ 23 ноября 2010

Лучшее объяснение состоит в том, что цветовая модель 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

РЕДАКТИРОВАТЬ: Конечно, это легче сказать, чем сделать.То есть, даже если вместо RGB принять цветовую модель CMYK (что уже сложно, поскольку преобразования из RGB в CMYK сильно зависят от устройства и далеко не однозначны), это, вероятно, все равно не удовлетворитнастоятельно рекомендуем смешать чистый синий (0, 0, 255) с чистым желтым (255, 255, 0) и получить зеленый.CMYK использует голубой, пурпурный и желтый в качестве 3 основных цветов вместо красного, желтого и синего.И у вас есть много работы впереди вас, если вы хотите приступить к реализации RYB цветовой модели на выбранном вами языке.

Я незнать любой такой алгоритм для реалистичного сочетания цветов RGB.В своем ответе я пытался объяснить, почему это было бы невозможно или, по крайней мере, крайне сложно.Вы можете оставить этот вопрос открытым еще несколько дней и посмотреть, есть ли у кого-нибудь еще какие-либо идеи, но я бы пошел дальше и начал бы с этой справочной таблицы, если вам нужно придерживаться модели RGB.; -)

3 голосов
/ 11 января 2017

РЕАЛЬНЫЙ ответ - изменить цветовое векторное пространство RGB на аддитивное, а затем изменить его на RGB.В этом новом векторном пространстве при добавлении двух векторов света учитываются аддитивные свойства света и наше восприятие цвета для получения аддитивного цвета.

Оказывается, векторное пространство CIE XYZ хорошо для этого подходит.цель.

Векторы XYZ аддитивны в этом пространстве и смешиваются, как и источники света.

См. этот документ о смешивании цветов от Cree:

X_mix = X1 + X2 + ...

Y_mix = Y1 + Y2 + ...

Z_mix = Z1 + Z2 + ...

Затем вы можете изменить базу обратно на RGB.Для изменения цвета между векторными пространствами доступно много библиотек, и CIEXYZ стандартизирован и широко поддерживается.

Этот метод дает реалистичные результаты, которые подходят для большинства моих целей.

Дополнительная информация о CIE1931 цветовое пространство .

3 голосов
/ 30 января 2013

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

Вы должны подтвердитьчто первичные цвета 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;
    }
}

Color Mixing Interface

В основном, эти операции аналогичны логическому И и логическому ИЛИ.(Ну, не совсем)

  • На аддитивном алгоритме цвета перекрываются, но для каждого основного он может быть только 255 (логическая операция ИЛИ)
  • На субстративном алгоритме, если какой-то основнойотсутствует, результат не будет иметь (CYAN не имеет КРАСНЫЙ, ЖЕЛТЫЙ не имеет СИНИЙ: вы получаете ЗЕЛЕНЫЙ) (Логика И Операция)

На основе это , которое вы можете получитьтретичные цвета из сочетания первичных и вторичных цветов, поэтому я делаю крошечную реализацию, которая работает довольно хорошо:

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

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

2 голосов
/ 23 ноября 2010

Глядя на ответ Коди Грея, я думаю, что могу предложить, как сочетать цвета. Преобразование цветового круга в 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

Посмотри, подходит ли тебе это.

Редактировать: Я не притворяюсь, что это физически правильно, это просто попытка приблизиться. Идея таблицы поиска звучит для меня безумно по двум причинам: она зависит от двух аргументов, поэтому ее размер будет очень большим; и законы природы обычно непрерывны без каких-либо или редких угловых случаев. Если вы можете заполнить справочную таблицу, вы должны знать алгоритм - просто напишите для нее функцию.

1 голос
/ 07 апреля 2015

Я просто хотел указать, почему вы становитесь серыми, когда добавляете Синий . Это потому, что вы добавляете Blue , а не Cyan :

enter image description here

  • Если вы добавите Голубой к Желтому, вы получите Зеленый
  • Если вы добавите Синий (т. Е. Голубой + магенты) к Желтому, вы получите Серый.

Или, более математически:

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)
1 голос
/ 12 февраля 2013

Вот Java-реализация Теории Отражения Кубелки-Мунка для смешивания цветов RGB.Эта реализация использует упрощенную версию модели Кубелка-Мунка, которая предполагает, что все цвета имеют одинаковую концентрацию при смешивании, и что все цвета непрозрачны.

https://github.com/benjholla/ColorMixer

1 голос
/ 15 ноября 2011

Я не думаю, что ответы выше дают адекватные результаты микширования.

Я работал над этой проблемой как с 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;
}
0 голосов
/ 21 сентября 2016

Многое уже было сказано по этому вопросу, но я просто хотел поделиться способом смешивания цветов (учитывая работу со светом: схема добавления).

Я попробовал пример кода от Дэмиена Дель Руссо, которыймне показался хорошим подходом, использующим среднее значение белого для вычисления 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))

0 голосов
/ 02 августа 2015

Имея ту же проблему со смешиванием цветов в темной или светлой тематике в моем приложении, я искал быстрое и простое решение.

В темной теме я просто использовал цвета RGB, и результат был довольно хорошим, однако в светлой теме это приводило к тому, что очень светлые цвета становились невидимыми.

Я просто пробовал и делал цвета, и это работало довольно хорошо. синий + желтый дал мне зеленый, пурпурный + голубой дал мне, по крайней мере, синий.

Итак, в темной теме (задний фон) я делаю:

mixed_color = color1 | color2; // Dark theme, like RGB mixing

В светлой теме:

mixed_color = color1 & color2; // Light theme, like CMY mixing

В миксе вряд ли есть какой-либо реализм, но для моей потребности (вдали от программного обеспечения для фотографии) это было вполне удовлетворительно.

0 голосов
/ 23 ноября 2010

«Желтый» в модели RGB отличается от желтого в модели RYB, которая при смешивании с синим должна давать зеленый цвет.

В качестве примера: (255, 255, 0) (приблизительно) вдвое "интенсивнее", чем (0, 0, 255) в модели RGB, тогда как в модели RYB предполагается, что РАВНЫЕ количества желтого и синего Зеленый. Точно так же красный и синий у двух моделей разные.

Думайте о них как о векторных пространствах RGB и R'Y'B '.

Если какое-то отношение вроде:

R = i1*R' + j1*Y' + k1*B';
G = i2*R' + j2*Y' + k2*B';
B = i3*R' + j3*Y' + k3*B';

верно, вы можете сделать свою алгебру, сначала преобразовав отдельные цвета (операнды) из RGB в пространство R'Y'B '.

Существует 9 неизвестных (переменные i, j, k), поэтому вам нужно 9 уравнений (3 цветовых равенства в этих двух пространствах).

К сожалению, Я думаю , что модели не масштабируются линейно, и, следовательно, для точности вам, возможно, придется использовать справочные таблицы.

Другой хорошей идеей может быть преобразование в пространство HSV или YCbCr, поскольку информация о цвете более четко абстрагируется в этом пространстве. (Если преобразование RGB в RYB существует, маршрут RGB-> YCbCr-> RYB может быть легче найти).

...