it-swarm.com.ru

Расчет смешанного цвета в RGB

Я хочу иметь возможность взять два вектора 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)

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

30
SIMEL

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

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

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

30
Cody Gray

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

Вы должны подтвердить, что основные цвета 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 (логическая операция OR)
  • На Субстративном алгоритме, если какой-то первичный элемент отсутствует, результат не будет иметь этого (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

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

3
albfan

НАСТОЯЩИЙ ответ - изменить цветовое векторное пространство RGB на аддитивное, а затем изменить его на RGB. В этом новом векторном пространстве при добавлении двух световых векторов учитываются аддитивные свойства света и наше восприятие цвета для получения аддитивного цвета.

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

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

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

X_mix = X1 + X2 + ...

Y_mix = Y1 + Y2 + ...

Z_mix = Z1 + Z2 + ...

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

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

Больше информации о цветовое пространство CIE 1931 .

3
nh43de

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

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

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

2
alxx

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

enter image description here

  • Если вы добавите Cyan в желтый, вы получите зеленый
  • Если вы добавите синий (т.е. голубой + magents) к желтому, вы получите серый.

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

Yellow + (Cyan          ) = Green  
Yellow + (Cyan + Magenta) = Gray
Yellow + (Blue)           = Gray

Вы добавляете Blue , когда вы хотели добавить Cyan .

0.5*Yellow(255,255,0) + 0.5*Cyan(0,255,255) = VeryLightLimeGreen(128,255,128)
1
Ian Boyd

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

https://github.com/benjholla/ColorMixer

1
Ben Holland

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

Я работал над этой проблемой как с RGB, так и с RYB (после конвертации из RGB). Преобразование для RGB в RYB здесь хорошо: http://www.insanit.net/tag/rgb-to-ryb/ (я поделюсь своим кодом по запросу).

Если смешивать как свет, это не так уж плохо (см. Ниже). Если вы хотите смешивать физические материалы, такие как Paint, то это немного хитрее - я работаю над приложением, чтобы изучить его. 

Вернемся к первоначальному вопросу - вот мой код для микширования 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;
}
1
Damien Del Russo

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

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

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

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

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

В светлую тему:

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

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

0
3c71

«Желтый» в модели 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 может быть легче найти).

0
JP19

Смешивание желтого (= красный + зеленый) и синего действительно дает белый цвет в соответствии с физикой, см. http://en.wikipedia.org/wiki/Additive_color .

0
user502515

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

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

смешиваниецветадобавлениесветrgbpython

0
SMFSW