Расчет смешанного цвета в RGB
Я хочу иметь возможность взять два вектора RGB-256 и вычислить результат их смеси. Также я хочу, чтобы каждый вектор имел разный вес. Я экспериментировал с ним, используя слово color plate, и я видел, что в то время как некоторые цвета смешиваются согласно средневзвешенному:
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 ответов
лучшим объяснением является то, что цветовая модель RGB несколько неинтуитивными для нас, людей.
это совершенно логично для устройства отображения видео (например, монитор или телевизор), который знает, как отображать цвета, смешивая различные количества 3 заранее определенных цветов: красный, зеленый и синий. Но мы с тобой не так учились смешивать цвета в начальной школе.
в 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).
оказывается, то, что вы и я узнали в начальной школе, действительно более точно известно как субтрактивный цвета модели, против the добавка цвета модели используется RGB. Глядя на две диаграммы внизу, вы увидите цветовую модель RGB (аддитивную) слева и цветовую модель CMYK (вычитающую) справа. Вы сможете сразу увидеть проблему. Использование вычитающей цветовой модели вместо этого приведет к желаемым результатам.
изменить: конечно, это легче сказано - сделано. То есть, даже если вы примете цветовую модель CMYK вместо RGB (что уже сложно, потому что преобразования из RGB в CMYK сильно зависящий от устройства и далеко не простой), это, вероятно, все равно не удовлетворит желание смешать чистый синий (0, 0, 255) с чистым желтым (255, 255, 0) и получить зеленый. CMYK использует голубой, пурпурный и желтый в качестве 3 основных цветов вместо красного, желтого и синего. И у вас есть много работы впереди вас, если вы хотите перейти к реализации цветовая модель RYB на языке по вашему выбору.
Я не знаю такого алгоритма для реалистичного объединения цветов RGB. Я пытался в своем ответе объяснить, почему это было бы невозможно или, по крайней мере, чрезвычайно сложно. Вы можете оставить этот вопрос открытым еще несколько дней и посмотреть, есть ли у кого-нибудь еще идеи, но я бы пошел вперед и начал с этой таблицы поиска, Если вам нужно придерживаться модели RGB. ;-)
на основе этого документированный ответ и alghoritm знать ответ, у меня есть очень простой интерфейс для смешивания цветов с помощью аддитивного и тракте подход.
вы должны подтвердить, что первичные цвета 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;
}
}
в основном, эти операции похожи на логику и и логику или. (Ну не совсем)
- на аддитивном alghoritm цвета перекрываются, но для каждого первичного он может быть только 255 (логика или операция)
- на подстрочном alghoritm, если какой-то первичный отсутствует, результат не будет иметь этого (голубой не имеет красного, желтый не имеет синего: вы получаете зеленый) (логика и операция)
на основе этой вы можете получить третичные цвета из смеси основных и второстепенных цветов, поэтому я делаю крошечную реализацию, которая работает довольно хорошо:
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
существует также разбавляющий / субстративный alghoritm, упомянутый во втором процитированном ответе, но я не могу сказать, на чем он основан, просто добавлен в тест.
реальный ответ состоит в том, чтобы изменить цветовое векторное пространство RGB на аддитивное, а затем изменить его обратно на RGB. В этом новом векторном пространстве при добавлении двух векторов света учитываются аддитивные свойства света и наше восприятие цвета для получения аддитивного цвета.
оказывается, векторное пространство CIE XYZ хорошо работает для этой цели.
векторы XYZ аддитивны в этом пространстве и смешиваются, как источники света.
посмотреть этот бумага на смешивание цветов by Cree:
X_mix = X1 + X2 + ...
Y_mix = Y1 + Y2 + ...
Z_mix = Z1 + Z2 + ...
затем вы можете изменить basis обратно на RGB. Существует множество библиотек, доступных для изменения цвета между векторными пространствами, и CIEXYZ стандартизирован и широко поддерживается.
этот метод дает реалистичные результаты, которые подходят для большинства моих целей.
подробнее о МКО 1931 цветовое пространство.
глядя на ответ Коди Грея, я думаю, что могу предложить, как комбинировать цвета. Преобразование цветового колеса в 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
посмотрите, подходит ли это для вас.
Edit: я не притворяюсь, что это физически правильно, это просто попытка приблизиться. Идея поиска стол дико звучит для меня по двум причинам: она зависит от двух аргументов, поэтому его размер будет очень большим; и законы природы обычно непрерывны при отсутствии или редких случаях. Если вы можете заполнить таблицу поиска, вы должны знать алгоритм - поэтому просто напишите для нее функцию.
Я не думаю, что ответы выше дают адекватные результаты смешивания.
Я работал над этой проблемой как с 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;
}
вот реализация Java теории отражения Kubelka-Munk для смешивания цветов RGB. Эта реализация использует упрощенную версию модели Kubelka-Munk, которая предполагает, что все цвета имеют одинаковую концентрацию при смешивании и что все цвета непрозрачны.
Я просто хотел указать, почему вы получаете серый цвет, когда вы добавляете синий. Это потому что вы добавляете синий, а не голубой:
- если добавить голубой в желтый, вы получите зеленое
- если добавить синий (т. е. cyan+magents) в желтый цвет, вы получаете серый.
или, более математически:
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)
смешивание желтого (= красный+зеленый) и синего тут дайте белый цвет согласно физике, см. http://en.wikipedia.org/wiki/Additive_color .
"желтый" в модели 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 цветовых равенства в этих 2 пространствах).
к сожалению, я думаю что модели не масштабируются линейно, и, следовательно, для точности вам, возможно, придется использовать таблицы поиска.
другой хорошей идеей может быть преобразование в пространство HSV или YCbCr, потому что цветовая информация более четко абстрагируется в этом пространстве. (Если преобразование RGB в RYB существует, маршрут RGB->YCbCr->RYB может быть проще найти).
имея ту же проблему со смешиванием цветов в темной или ligth теме в моем приложении, я искал быстрое и простое решение.
в темной теме я просто или цвета RGB, и результат был довольно ок, однако в светлой теме это привело к тому, что очень светлые цвета стали невидимыми.
Я просто попробовал и цвета, и это сработало довольно хорошо. синий + желтый дали мне зеленый, пурпурный + голубой дали мне синий, по крайней мере.
Итак, в темной теме (назад фон) я делаю:
mixed_color = color1 | color2; // Dark theme, like RGB mixing
в свете темы:
mixed_color = color1 & color2; // Light theme, like CMY mixing
маловероятно, что в миксе есть реализм, но для моей потребности (вдали от программного обеспечения для фотографии) это было очень удовлетворительно.
много уже было сказано по этому вопросу, но я просто хотел поделиться способом смешивания цветов (учитывая работу со светом: схема сложения).
я попробовал пример кода от Дэмиена Дель Руссо, который казался хорошим подходом на мой вкус, используя белое среднее для расчета 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))