我希望能够获取两个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)
是否有精确计算所有颜色的算法,或者我是否被迫使用查找表进行计算?
答案 0 :(得分:31)
最好的解释是RGB color model对于我们人来说有点不直观。
对于视频显示设备(例如显示器或电视机只知道如何通过混合不同数量的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)。
事实证明,你和我在小学时学到的东西实际上更准确地称为subtractive color model,而不是RGB使用的additive color model。查看底部的两个图表,您将在左侧看到RGB颜色模型(添加剂),而在右侧看到CMYK颜色模型(减法)。您应该能够立即看到问题。使用减色颜色模型将产生您想要的结果。
编辑:当然,说起来容易做起来难。也就是说,即使您采用CMYK颜色模型而不是RGB(这已经很难了,因为从RGB到CMYK的转换严重设备相关且远非直截了当),这可能仍然不能满足将纯蓝色(0,0,255)与纯黄色(255,255,0)混合并变绿的冲动。 CMYK使用青色,品红色和黄色作为3原色,而不是红色,黄色和蓝色。如果你想用你选择的语言实现RYB color model,你就会有一个很多的工作。
我不知道任何这样的算法可以逼真地组合RGB颜色。我试图在我的回答中解释为什么它是不可能的,或者至少是非常困难的。您可以将这个问题保持开放几天,看看是否有其他人有任何想法,但如果您需要坚持使用RGB模型,我会继续在该查找表上开始。 ; - )
答案 1 :(得分:3)
基于此documented response和此alghoritm aware response,我尝试了一个简单的界面,使用加法和减法方法混合颜色。
您必须确认RGB和CMYK的原色在第一个响应图中为您提供了二次色:
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import java.util.Vector;
/**
* Color Mixing alghoritms
* User: alberto
* Date: 29/01/13
* Time: 21:28
*/
public class ColorMix {
Vector<JLabel> firstMixColors;
Vector<JLabel> secondMixColors;
JComboBox/*<Mixer>*/ comboBox;
JLabel firstMixColor;
JLabel firstSel;
JLabel secondSel;
JLabel finalColor;
public ColorMix() {
firstMixColors = new Vector<JLabel>();
Vector<Mixer> mixers = new Vector<Mixer>();
mixers.add(new AdditiveMixer());
mixers.add(new SustractiveMixer());
mixers.add(new TertiaryMixer());
mixers.add(new DilutingSustractiveMixer());
comboBox = new JComboBox(new DefaultComboBoxModel(mixers));
firstMixColor = buildColorLabel();
firstSel = buildColorLabel();
secondSel = buildColorLabel();
secondMixColors = new Vector<JLabel>();
secondMixColors.add(firstSel);
secondMixColors.add(secondSel);
finalColor = buildColorLabel();
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
calculateMixes();
}
});
buildGUI();
}
private JLabel buildColorLabel() {
JLabel label = new JLabel();
label.setOpaque(true);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setHorizontalTextPosition(SwingConstants.CENTER);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
label.setPreferredSize(new Dimension(100,25));
return label;
}
public void buildGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setTitle("Mixing colors");
frame.setLayout(new GridBagLayout());
GridBagConstraints cc = new GridBagConstraints();
cc.fill = GridBagConstraints.BOTH;
cc.insets = new Insets(5, 5, 5, 5);
cc.weightx = .2;
cc.weighty = 1;
frame.getContentPane().add(buildColorPanel(0), cc);
frame.getContentPane().add(buildColorPanel(1), cc);
cc.gridy = 1;
JPanel firstMix = new JPanel(new GridBagLayout());
GridBagConstraints ccCol = new GridBagConstraints();
ccCol.fill = GridBagConstraints.BOTH;
ccCol.insets = new Insets(5, 5, 5, 5);
ccCol.weightx = 1;
ccCol.weighty = 1;
ccCol.gridx = 0;
ccCol.gridy = 0;
ccCol.gridheight = 2;
firstMix.add(firstMixColor, ccCol);
ccCol.fill = GridBagConstraints.HORIZONTAL;
ccCol.weightx = 0.2;
ccCol.weighty = 0.5;
ccCol.gridx = 1;
ccCol.gridy = 0;
ccCol.gridheight = 1;
ccCol.gridwidth = 1;
firstMix.add(new JButton(new AbstractAction("Set First") {
@Override
public void actionPerformed(ActionEvent e) {
setBackgroundToLabel(firstSel, firstMixColor.getBackground());
calculateMixes();
}
}), ccCol);
ccCol.gridx = 1;
ccCol.gridy = 1;
firstMix.add(new JButton(new AbstractAction("Set Second") {
@Override
public void actionPerformed(ActionEvent e) {
setBackgroundToLabel(secondSel, firstMixColor.getBackground());
calculateMixes();
}
}), ccCol);
firstMix.setBorder(BorderFactory.createTitledBorder("Secondary Colors"));
frame.getContentPane().add(firstMix, cc);
cc.weightx = .6;
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints ccColor = new GridBagConstraints();
ccColor.fill = GridBagConstraints.BOTH;
ccColor.insets = new Insets(5, 5, 5, 5);
ccColor.weightx = 1;
ccColor.weighty = 1;
panel.add(firstSel, ccColor);
ccColor.gridx = 1;
panel.add(secondSel, ccColor);
ccColor.gridx = 0;
ccColor.gridy = 1;
ccColor.weighty = 0;
ccColor.gridwidth = 2;
panel.add(finalColor, ccColor);
ccColor.gridy = 2;
panel.add(comboBox, ccColor);
panel.setBorder(BorderFactory.createTitledBorder("Tertiary Colors"));
frame.getContentPane().add(panel, cc);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new ColorMix();
}
private JComponent buildColorPanel(int selectedIndex) {
final JLabel pColor = buildColorLabel();
firstMixColors.add(pColor);
JPanel pSelectColor = new JPanel(new GridBagLayout());
GridBagConstraints cc = new GridBagConstraints();
cc.fill = GridBagConstraints.BOTH;
cc.insets = new Insets(5, 5, 5, 5);
cc.weightx = 1;
cc.weighty = 1;
final JSlider slidRed = buildSlider(pSelectColor, cc);
final JSlider slidGreen = buildSlider(pSelectColor, cc);
final JSlider slidBlue = buildSlider(pSelectColor, cc);
pSelectColor.add(pColor, cc);
final JComboBox comboColores = buildColorCombo();
comboColores.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Color color = (Color) comboColores.getSelectedItem();
slidRed.setValue(color.getRed());
slidGreen.setValue(color.getGreen());
slidBlue.setValue(color.getBlue());
}
});
comboColores.setSelectedIndex(selectedIndex);
cc.gridy = 1;
cc.gridwidth = 4;
cc.weighty = 0;
pSelectColor.add(comboColores, cc);
ChangeListener changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
setBackgroundToLabel(pColor, new Color(slidRed.getValue(), slidGreen.getValue(), slidBlue.getValue()));
calculateMixes();
}
};
slidRed.addChangeListener(changeListener);
slidGreen.addChangeListener(changeListener);
slidBlue.addChangeListener(changeListener);
pSelectColor.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
changeListener.stateChanged(null);
return pSelectColor;
}
private JComboBox buildColorCombo() {
Color TRANSPARENT = new Color(0, 0, 0, 0);
Vector<Color> colors = new Vector<Color>();
colors.add(new NamedColor(Color.RED, "Red"));
colors.add(new NamedColor(Color.GREEN, "Green"));
colors.add(new NamedColor(Color.BLUE, "Blue"));
colors.add(new NamedColor(Color.YELLOW, "Yellow"));
colors.add(new NamedColor(Color.MAGENTA, "Magenta"));
colors.add(new NamedColor(Color.CYAN, "Cyan"));
colors.add(new NamedColor(Color.WHITE, "White"));
colors.add(new NamedColor(Color.LIGHT_GRAY, "Light Gray"));
colors.add(new NamedColor(Color.GRAY, "Gray"));
colors.add(new NamedColor(Color.DARK_GRAY, "Dark Gray"));
colors.add(new NamedColor(Color.BLACK, "Black"));
colors.add(new NamedColor(Color.PINK, "Pink"));
colors.add(new NamedColor(Color.ORANGE, "Orange"));
colors.add(new NamedColor(TRANSPARENT, "transparent"));
//http://www.w3schools.com/css/css_colornames.asp
colors.add(new NamedColor(new Color(0xf0f8ff), "aliceblue"));
colors.add(new NamedColor(new Color(0xfaebd7), "antiquewhite"));
colors.add(new NamedColor(new Color(0x00ffff), "aqua"));
colors.add(new NamedColor(new Color(0x7fffd4), "aquamarine"));
colors.add(new NamedColor(new Color(0xf0ffff), "azure"));
colors.add(new NamedColor(new Color(0xf5f5dc), "beige"));
colors.add(new NamedColor(new Color(0xffe4c4), "bisque"));
colors.add(new NamedColor(new Color(0x000000), "black"));
colors.add(new NamedColor(new Color(0xffebcd), "blanchedalmond"));
colors.add(new NamedColor(new Color(0x0000ff), "blue"));
colors.add(new NamedColor(new Color(0x8a2be2), "blueviolet"));
colors.add(new NamedColor(new Color(0xa52a2a), "brown"));
colors.add(new NamedColor(new Color(0xdeb887), "burlywood"));
colors.add(new NamedColor(new Color(0x5f9ea0), "cadetblue"));
colors.add(new NamedColor(new Color(0x7fff00), "chartreuse"));
colors.add(new NamedColor(new Color(0xd2691e), "chocolate"));
colors.add(new NamedColor(new Color(0xff7f50), "coral"));
colors.add(new NamedColor(new Color(0x6495ed), "cornflowerblue"));
colors.add(new NamedColor(new Color(0xfff8dc), "cornsilk"));
colors.add(new NamedColor(new Color(0xdc143c), "crimson"));
colors.add(new NamedColor(new Color(0x00ffff), "cyan"));
colors.add(new NamedColor(new Color(0x00008b), "darkblue"));
colors.add(new NamedColor(new Color(0x008b8b), "darkcyan"));
colors.add(new NamedColor(new Color(0xb8860b), "darkgoldenrod"));
colors.add(new NamedColor(new Color(0xa9a9a9), "darkgray"));
colors.add(new NamedColor(new Color(0xa9a9a9), "darkgrey"));
colors.add(new NamedColor(new Color(0x006400), "darkgreen"));
colors.add(new NamedColor(new Color(0xbdb76b), "darkkhaki"));
colors.add(new NamedColor(new Color(0x8b008b), "darkmagenta"));
colors.add(new NamedColor(new Color(0x556b2f), "darkolivegreen"));
colors.add(new NamedColor(new Color(0xff8c00), "darkorange"));
colors.add(new NamedColor(new Color(0x9932cc), "darkorchid"));
colors.add(new NamedColor(new Color(0x8b0000), "darkred"));
colors.add(new NamedColor(new Color(0xe9967a), "darksalmon"));
colors.add(new NamedColor(new Color(0x8fbc8f), "darkseagreen"));
colors.add(new NamedColor(new Color(0x483d8b), "darkslateblue"));
colors.add(new NamedColor(new Color(0x2f4f4f), "darkslategray"));
colors.add(new NamedColor(new Color(0x2f4f4f), "darkslategrey"));
colors.add(new NamedColor(new Color(0x00ced1), "darkturquoise"));
colors.add(new NamedColor(new Color(0x9400d3), "darkviolet"));
colors.add(new NamedColor(new Color(0xff1493), "deeppink"));
colors.add(new NamedColor(new Color(0x00bfff), "deepskyblue"));
colors.add(new NamedColor(new Color(0x696969), "dimgray"));
colors.add(new NamedColor(new Color(0x696969), "dimgrey"));
colors.add(new NamedColor(new Color(0x1e90ff), "dodgerblue"));
colors.add(new NamedColor(new Color(0xb22222), "firebrick"));
colors.add(new NamedColor(new Color(0xfffaf0), "floralwhite"));
colors.add(new NamedColor(new Color(0x228b22), "forestgreen"));
colors.add(new NamedColor(new Color(0xff00ff), "fuchsia"));
colors.add(new NamedColor(new Color(0xdcdcdc), "gainsboro"));
colors.add(new NamedColor(new Color(0xf8f8ff), "ghostwhite"));
colors.add(new NamedColor(new Color(0xffd700), "gold"));
colors.add(new NamedColor(new Color(0xdaa520), "goldenrod"));
colors.add(new NamedColor(new Color(0x808080), "gray"));
colors.add(new NamedColor(new Color(0x808080), "grey"));
colors.add(new NamedColor(new Color(0x008000), "green"));
colors.add(new NamedColor(new Color(0xadff2f), "greenyellow"));
colors.add(new NamedColor(new Color(0xf0fff0), "honeydew"));
colors.add(new NamedColor(new Color(0xff69b4), "hotpink"));
colors.add(new NamedColor(new Color(0xcd5c5c), "indianred"));
colors.add(new NamedColor(new Color(0x4b0082), "indigo"));
colors.add(new NamedColor(new Color(0xfffff0), "ivory"));
colors.add(new NamedColor(new Color(0xf0e68c), "khaki"));
colors.add(new NamedColor(new Color(0xe6e6fa), "lavender"));
colors.add(new NamedColor(new Color(0xfff0f5), "lavenderblush"));
colors.add(new NamedColor(new Color(0x7cfc00), "lawngreen"));
colors.add(new NamedColor(new Color(0xfffacd), "lemonchiffon"));
colors.add(new NamedColor(new Color(0xadd8e6), "lightblue"));
colors.add(new NamedColor(new Color(0xf08080), "lightcoral"));
colors.add(new NamedColor(new Color(0xe0ffff), "lightcyan"));
colors.add(new NamedColor(new Color(0xfafad2), "lightgoldenrodyellow"));
colors.add(new NamedColor(new Color(0xd3d3d3), "lightgray"));
colors.add(new NamedColor(new Color(0xd3d3d3), "lightgrey"));
colors.add(new NamedColor(new Color(0x90ee90), "lightgreen"));
colors.add(new NamedColor(new Color(0xffb6c1), "lightpink"));
colors.add(new NamedColor(new Color(0xffa07a), "lightsalmon"));
colors.add(new NamedColor(new Color(0x20b2aa), "lightseagreen"));
colors.add(new NamedColor(new Color(0x87cefa), "lightskyblue"));
colors.add(new NamedColor(new Color(0x778899), "lightslategray"));
colors.add(new NamedColor(new Color(0x778899), "lightslategrey"));
colors.add(new NamedColor(new Color(0xb0c4de), "lightsteelblue"));
colors.add(new NamedColor(new Color(0xffffe0), "lightyellow"));
colors.add(new NamedColor(new Color(0x00ff00), "lime"));
colors.add(new NamedColor(new Color(0x32cd32), "limegreen"));
colors.add(new NamedColor(new Color(0xfaf0e6), "linen"));
colors.add(new NamedColor(new Color(0xff00ff), "magenta"));
colors.add(new NamedColor(new Color(0x800000), "maroon"));
colors.add(new NamedColor(new Color(0x66cdaa), "mediumaquamarine"));
colors.add(new NamedColor(new Color(0x0000cd), "mediumblue"));
colors.add(new NamedColor(new Color(0xba55d3), "mediumorchid"));
colors.add(new NamedColor(new Color(0x9370d8), "mediumpurple"));
colors.add(new NamedColor(new Color(0x3cb371), "mediumseagreen"));
colors.add(new NamedColor(new Color(0x7b68ee), "mediumslateblue"));
colors.add(new NamedColor(new Color(0x00fa9a), "mediumspringgreen"));
colors.add(new NamedColor(new Color(0x48d1cc), "mediumturquoise"));
colors.add(new NamedColor(new Color(0xc71585), "mediumvioletred"));
colors.add(new NamedColor(new Color(0x191970), "midnightblue"));
colors.add(new NamedColor(new Color(0xf5fffa), "mintcream"));
colors.add(new NamedColor(new Color(0xffe4e1), "mistyrose"));
colors.add(new NamedColor(new Color(0xffe4b5), "moccasin"));
colors.add(new NamedColor(new Color(0xffdead), "navajowhite"));
colors.add(new NamedColor(new Color(0x000080), "navy"));
colors.add(new NamedColor(new Color(0xfdf5e6), "oldlace"));
colors.add(new NamedColor(new Color(0x808000), "olive"));
colors.add(new NamedColor(new Color(0x6b8e23), "olivedrab"));
colors.add(new NamedColor(new Color(0xffa500), "orange"));
colors.add(new NamedColor(new Color(0xff4500), "orangered"));
colors.add(new NamedColor(new Color(0xda70d6), "orchid"));
colors.add(new NamedColor(new Color(0xeee8aa), "palegoldenrod"));
colors.add(new NamedColor(new Color(0x98fb98), "palegreen"));
colors.add(new NamedColor(new Color(0xafeeee), "paleturquoise"));
colors.add(new NamedColor(new Color(0xd87093), "palevioletred"));
colors.add(new NamedColor(new Color(0xffefd5), "papayawhip"));
colors.add(new NamedColor(new Color(0xffdab9), "peachpuff"));
colors.add(new NamedColor(new Color(0xcd853f), "peru"));
colors.add(new NamedColor(new Color(0xffc0cb), "pink"));
colors.add(new NamedColor(new Color(0xdda0dd), "plum"));
colors.add(new NamedColor(new Color(0xb0e0e6), "powderblue"));
colors.add(new NamedColor(new Color(0x800080), "purple"));
colors.add(new NamedColor(new Color(0xff0000), "red"));
colors.add(new NamedColor(new Color(0xbc8f8f), "rosybrown"));
colors.add(new NamedColor(new Color(0x4169e1), "royalblue"));
colors.add(new NamedColor(new Color(0x8b4513), "saddlebrown"));
colors.add(new NamedColor(new Color(0xfa8072), "salmon"));
colors.add(new NamedColor(new Color(0xf4a460), "sandybrown"));
colors.add(new NamedColor(new Color(0x2e8b57), "seagreen"));
colors.add(new NamedColor(new Color(0xfff5ee), "seashell"));
colors.add(new NamedColor(new Color(0xa0522d), "sienna"));
colors.add(new NamedColor(new Color(0xc0c0c0), "silver"));
colors.add(new NamedColor(new Color(0x87ceeb), "skyblue"));
colors.add(new NamedColor(new Color(0x6a5acd), "slateblue"));
colors.add(new NamedColor(new Color(0x708090), "slategray"));
colors.add(new NamedColor(new Color(0x708090), "slategrey"));
colors.add(new NamedColor(new Color(0xfffafa), "snow"));
colors.add(new NamedColor(new Color(0x00ff7f), "springgreen"));
colors.add(new NamedColor(new Color(0x4682b4), "steelblue"));
colors.add(new NamedColor(new Color(0xd2b48c), "tan"));
colors.add(new NamedColor(new Color(0x008080), "teal"));
colors.add(new NamedColor(new Color(0xd8bfd8), "thistle"));
colors.add(new NamedColor(new Color(0xff6347), "tomato"));
colors.add(new NamedColor(new Color(0x40e0d0), "turquoise"));
colors.add(new NamedColor(new Color(0xee82ee), "violet"));
colors.add(new NamedColor(new Color(0xf5deb3), "wheat"));
colors.add(new NamedColor(new Color(0xffffff), "white"));
colors.add(new NamedColor(new Color(0xf5f5f5), "whitesmoke"));
colors.add(new NamedColor(new Color(0xffff00), "yellow"));
colors.add(new NamedColor(new Color(0x9acd32), "yellowgreen"));
JComboBox comboBox = new JComboBox(new DefaultComboBoxModel(colors));
comboBox.setRenderer(new DefaultListCellRenderer() {
protected Color backgroundColor = Color.BLACK;
{
setBorder(new CompoundBorder(
new MatteBorder(2, 5, 2, 5, Color.white)
, new LineBorder(Color.black)));
}
public Component getListCellRendererComponent(JList list, Object obj,
int row, boolean sel, boolean hasFocus) {
if (obj instanceof Color)
backgroundColor = (Color) obj;
setText(obj.toString());
return this;
}
public void paint(Graphics g) {
setBackground(backgroundColor);
super.paint(g);
}
});
return comboBox;
}
class NamedColor extends Color {
private String name;
NamedColor(Color color, String name) {
super(color.getRed(), color.getGreen(), color.getBlue());
this.name = name;
}
@Override
public String toString() {
return name;
}
}
private void calculateMixes() {
calculateFirstMix();
calculateSecondMix();
}
private void calculateFirstMix() {
calculateMix(firstMixColors, firstMixColor);
}
private void calculateSecondMix() {
calculateMix(secondMixColors, finalColor);
}
private void calculateMix(Vector<JLabel> mixColors, JLabel finalColor) {
Color bg = ((Mixer) comboBox.getSelectedItem()).calculateMix(mixColors);
setBackgroundToLabel(finalColor, bg);
}
private void setBackgroundToLabel(JLabel label, Color color) {
label.setBackground(color);
label.setText(color.getRed() + "," + color.getGreen() + "," + color.getBlue());
}
interface Mixer {
Color calculateMix(Vector<JLabel> colores);
}
/**
* Implement a additive mix of colors
*/
static class AdditiveMixer implements Mixer {
public Color calculateMix(Vector<JLabel> colores) {
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < colores.size(); i++) {
Color background = colores.get(i).getBackground();
red += background.getRed();
green += background.getGreen();
blue += background.getBlue();
}
return new Color(Math.min(255, red), Math.min(255, green), Math.min(255, blue));
}
@Override
public String toString() {
return "Additive";
}
}
/**
* Implement a sustractive mix of colors
*/
static class SustractiveMixer implements Mixer {
public Color calculateMix(Vector<JLabel> colores) {
int red = 1;
int green = 1;
int blue = 1;
for (int i = 0; i < colores.size(); i++) {
Color background = colores.get(i).getBackground();
red *= background.getRed();
green *= background.getGreen();
blue *= background.getBlue();
}
return new Color(Math.min(255, red / 255), Math.min(255, green / 255), Math.min(255, blue / 255));
}
@Override
public String toString() {
return "Sustractive";
}
}
/**
* Implement a diluting/sustractive mix of colors
*/
static class DilutingSustractiveMixer implements Mixer {
public Color calculateMix(Vector<JLabel> colores) {
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < colores.size(); i++) {
Color background = colores.get(i).getBackground();
red += Math.pow(255 - background.getRed(), 2);
green += Math.pow(255 - background.getGreen(), 2);
blue += Math.pow(255 - background.getBlue(), 2);
}
return new Color(Math.min(255, (int)Math.sqrt(red / colores.size())), Math.min(255, (int)Math.sqrt(green / colores.size())), Math.min(255, (int)Math.sqrt(blue / colores.size())));
}
@Override
public String toString() {
return "Diluting/Sustractive";
}
}
/**
* Implement a diluting/sustractive mix of colors
*/
static class TertiaryMixer implements Mixer {
public Color calculateMix(Vector<JLabel> colores) {
Color background1 = colores.get(0).getBackground();
int red = background1.getRed();
int green = background1.getGreen();
int blue = background1.getBlue();
Color background2 = colores.get(1).getBackground();
red -= background2.getRed();
green -= background2.getGreen();
blue -= background2.getBlue();
return new Color(Math.min(255, background1.getRed() - (red/2)), Math.min(255, background1.getGreen() - (green/2)), background1.getBlue() - (blue/2));
}
@Override
public String toString() {
return "Tertiary";
}
}
private JSlider buildSlider(JPanel container, GridBagConstraints upperCC) {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints cc = new GridBagConstraints();
cc.fill = GridBagConstraints.BOTH;
cc.insets = new Insets(5, 5, 5, 5);
cc.weightx = 1;
cc.weighty = 0.7;
final JSlider slider = new JSlider(JSlider.VERTICAL, 0, 255, 0);
slider.setFont(new Font("Serif", Font.PLAIN, 4));
Hashtable<Integer, JLabel> labels = new Hashtable<Integer, JLabel>();
labels.put(0, new JLabel("0"));
labels.put(128, new JLabel("128"));
labels.put(255, new JLabel("255"));
panel.add(slider, cc);
final JTextField field = new JTextField();
field.setEditable(false);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
field.setText(String.valueOf(slider.getValue()));
}
});
cc.gridx = 0;
cc.gridy = 1;
cc.weighty = 0;
panel.add(field, cc);
slider.setLabelTable(labels);
slider.setPaintLabels(true);
container.add(panel, upperCC);
return slider;
}
}
基本上,此操作类似于逻辑AND和逻辑OR。 (嗯,不完全是)
基于this,您可以从主要颜色和辅助颜色的混合中获得三级颜色,因此我做了一个非常好的实现:
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,但我不能说它是基于什么,只是添加到测试中。
答案 2 :(得分:3)
真正的答案是将RGB颜色矢量空间更改为添加剂,然后将其更改为RGB。在这个新的矢量空间中,当你添加两个光矢量时,它会考虑光的附加属性和我们对颜色的感知来产生一种加色。
事实证明,CIE XYZ向量空间可以很好地用于此目的。
XYZ矢量在这个空间中是加性的,并且作为光源混合。
请参阅Cree的this paper on color mixing:
X_mix = X1 + X2 + ...
Y_mix = Y1 + Y2 + ...
Z_mix = Z1 + Z2 + ...
然后您可以将基础更改回RGB。有许多库可用于在矢量空间之间改变颜色,CIEXYZ已经标准化并得到广泛支持。
这种方法可以产生符合我大多数目的的逼真结果。
有关CIE 1931 color space的更多信息。
答案 3 :(得分:2)
看看Cody Gray的回答,我想我可以建议如何组合颜色。将色轮转换为RGB:
cyan(0, 255, 255)
blue(0, 0, 255) green(0, 255, 0)
magenta(255, 0, 255) red(255, 0, 0) yellow(255, 255, 0)
没有额外的复杂性,颜色可以像这样组合:反转两种颜色,将它们加在一起并反转结果(ActionScript):
sum(0, 255, 255, 255, 0, 255, "cyan + magenta =");
sum(255, 0, 0, 0, 255, 0, "red + green =");
sum(0, 0, 0, 0, 0, 0, "black + black =");
sum(0, 0, 0, 255, 255, 255, "black + white =");
function sum(c1:int, c2:int, c3:int, b1:int, b2:int, b3:int, m:String):void {
c1 = 255 - c1; c2 = 255 - c2; c3 = 255 - c3;
b1 = 255 - b1; b2 = 255 - b2; b3 = 255 - b3;
var d1:int = c1 + b1;
var d2:int = c2 + b2;
var d3:int = c3 + b3;
d1 = 255 - d1; d2 = 255 - d2; d3 = 255 - d3;
d1 = clamp(d1); d2 = clamp(d2); d3 = clamp(d3);
trace(m, d1, d2, d3);
}
function clamp(value:int):int {
if (value < 0) return 0;
if (value > 255) return 255;
return value;
}
输出:
cyan + magenta = 0 0 255
red + green = 0 0 0
black + black = 0 0 0
black + white = 0 0 0
看看是否适合你。
编辑:我不是假装这是物理上正确的,它只是一种近似的尝试。查找表的想法对我来说听起来很疯狂有两个原因:它取决于两个参数,所以它的大小会非常大;自然法则通常是连续的,没有或罕见的角落案件。如果你可以填写查找表,你应该知道算法 - 所以只需为它编写一个函数。
答案 4 :(得分:1)
我不认为上面的答案会给出足够的混音效果。
我一直在用RGB和RYB(从RGB转换后)处理这个问题。这里将RGB转换为RYB是好的:http://www.insanit.net/tag/rgb-to-ryb/(我将根据请求分享我的代码)。
如果混合为光,则不太糟糕(见下文)。如果你想混合作为物理材料,比如油漆,它是一个小技巧 - 我正在开发一个应用程序来探索它。
回到原来的问题 - 这是我的RGB混音代码。 RgbColor是一个自定义类,但我认为这本身就有意义:
-(RgbColor*)mixWith:(RgbColor *)aColor {
int r1, g1, b1, r2, g2, b2, r3, g3, b3, m1, m2, w1, w2, w3; //colors and maxes, white
float br; // brightness of resulting color
r1 = self.redVal;
g1 = self.greenVal;
b1 = self.blueVal;
r2 = aColor.redVal;
g2 = aColor.greenVal;
b2 = aColor.blueVal;
w1 = MIN(r1, MIN(g1, b1));
w2 = MIN(r2, MIN(g2, b2));
// remove white before mixing
r1 -= w1;
g1 -= w1;
b1 -= w1;
r2 -= w2;
g2 -= w2;
b2 -= w2;
m1 = MAX(r1, MAX(g1, b1));
m2 = MAX(r2, MAX(g2, b2));
br = (m1+m2)/(2*255.0);
r3 = (r1+r2)*br;
g3 = (g1+g2)*br;
b3 = (b1+b2)*br;
// average whiteness and add into final color
w3 = (w1+w2)/2;
r3 += w3;
g3 += w3;
b3 += w3;
[self setRedVal:[[NSNumber numberWithFloat:r3] intValue]];
[self setGreenVal:[[NSNumber numberWithFloat:g3] intValue]];
[self setBlueVal:[[NSNumber numberWithFloat:b3] intValue]];
return self;
}
答案 5 :(得分:1)
这是用于混合RGB颜色的Kubelka-Munk反射理论的Java实现。此实现使用Kubelka-Munk模型的简化版本,假设所有颜色在混合时具有相同的浓度,并且所有颜色都是不透明的。
答案 6 :(得分:1)
我只是想指出为什么在添加蓝色时会变灰。这是因为您要添加蓝色,而不是青色:
或者,更加数学化:
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)
答案 7 :(得分:1)
我需要为我的一个库做同样的事情。我应用了 this paper 的建议方法,结果是可以接受的。
这个过程非常简单。它需要将颜色转换为 RYB 颜色空间,进行混合,然后将结果转换回 RGB。他们提出了一个与下表一致的转换方程:
RGB 颜色 | RGB 值 | RYB 值 |
---|---|---|
黑色 | R: 0 | G: 0 |乙:0 | R:255 |是:255 |乙:255 |
红色 | R:255 | G: 0 |乙:0 | R:255 |是:0 |乙:0 |
绿色 | R: 0 | G: 255 |乙:0 | R: 0 |是:255 |乙:255 |
蓝色 | R: 0 | G: 0 |乙:255 | R: 0 |是:0 |乙:255 |
黄色 | R:255 | G: 255 |乙:0 | R: 0 |是:255 |乙:0 |
洋红色 | R:255 | G: 0 |乙:255 | R:255 |是:0 |乙:127.5 |
青色 | R: 0 | G: 255 |乙:255 | R: 0 | Y:127.5 |乙:255 |
白色 | R:255 | G: 255 |乙:255 | R: 0 |是:0 |乙:0 |
以下是建议的公式(以 TypeScript
代码为伪代码):
type RYBObject = {
r: number;
y: number;
b: number;
};
export const rgbToRYB = (r: number, g: number, b: number): RYBObject => {
const Iw = Math.min(r, g, b);
const Ib = Math.min(255 - r, 255 - g, 255 - b);
const rRGB = r - Iw;
const gRGB = g - Iw;
const bRGB = b - Iw;
const minRG = Math.min(rRGB, gRGB);
const rRYB = rRGB - minRG;
const yRYB = (gRGB + minRG) / 2;
const bRYB = (bRGB + gRGB - minRG) / 2;
const n = Math.max(rRYB, yRYB, bRYB, 1) / Math.max(rRGB, gRGB, bRGB, 1);
return {
r: rRYB / n + Ib,
y: yRYB / n + Ib,
b: bRYB / n + Ib
};
};
type RGBObject = {
r: number;
g: number;
b: number;
};
export const rybToRGB = (r: number, y: number, b: number): RGBObject => {
const Iw = Math.min(r, y, b);
const Ib = Math.min(255 - r, 255 - y, 255 - b);
const rRYB = r - Iw;
const yRYB = y - Iw;
const bRYB = b - Iw;
const minYB = Math.min(yRYB, bRYB);
const rRGB = rRYB + yRYB - minYB;
const gRGB = yRYB + 2 * minYB;
const bRGB = 2 * (bRYB - minYB);
const n = Math.max(rRGB, gRGB, bRGB, 1) / Math.max(rRYB, yRYB, bRYB, 1);
return {
r: rRGB / n + Ib,
g: gRGB / n + Ib,
b: bRGB / n + Ib
};
};
你可以用这个方法来混合颜色:
const mixColors = (c1: RYBObject, c2: RYBObject): RYBObject => ({
r: Math.min(255, c1.r + c2.r),
y: Math.min(255, c1.y + c2.y),
b: Math.min(255, c1.b + c2.b)
});
// color1 and color2 are the input colors in the shape of RGBObject
const mixedColor = rybToRGB(
mixColors(
rgbToRYB(color1),
rgbToRYB(color2)
)
);
在这里您可以看到使用我构建的库的结果,该库使用上述方法实现混合:
const mixes = [
'#FF0000',
'#FFFF00',
'#0000FF',
[1, 3],
[1, 2],
[2, 3],
[1, 2, 3]
];
const paths = document.querySelectorAll('#planes path');
paths.forEach((path, index) => {
let color = '#CCCCCC';
if (mixes[index]) {
if (typeof mixes[index] === 'string') {
color = mixes[index];
} else {
const colors = mixes[index].map((i) => mixes[i - 1]);
color = mixes[index] = ColorTranslator.getMixHEX(colors, Mix.SUBTRACTIVE);
}
}
path.setAttribute('fill', color);
});
body, html {
height: 100%;
}
svg {
height: 100%;
width: 100%;
}
<script src="https://unpkg.com/colortranslator@1.7.0/dist/colortranslator.web.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<g id="planes">
<path d="M250,210.9929A144.2657,144.2657,0,0,1,392.9611,192.67a144.125,144.125,0,1,0-287.0788-18.3437,145.5121,145.5121,0,0,0,1.1566,18.3437A144.2657,144.2657,0,0,1,250,210.9929Z"/>
<path d="M409.4255,200.84a145.5235,145.5235,0,0,0-16.4644-8.17,144.2654,144.2654,0,0,1-87.3487,114.6464A144.2658,144.2658,0,0,1,250,440.2858,144.125,144.125,0,1,0,409.4255,200.84Z"/>
<path d="M194.3876,307.3163A144.2654,144.2654,0,0,1,107.0389,192.67,144.1177,144.1177,0,1,0,250,440.2858,144.2658,144.2658,0,0,1,194.3876,307.3163Z"/>
<path d="M194.3876,307.3163A144.5321,144.5321,0,0,1,250,210.9929,144.2657,144.2657,0,0,0,107.0389,192.67,144.2654,144.2654,0,0,0,194.3876,307.3163Z"/>
<path d="M250,210.9929a144.5321,144.5321,0,0,1,55.6124,96.3234A144.2654,144.2654,0,0,0,392.9611,192.67,144.2657,144.2657,0,0,0,250,210.9929Z"/>
<path d="M305.6124,307.3163a144.532,144.532,0,0,1-111.2248,0A144.2658,144.2658,0,0,0,250,440.2858,144.2658,144.2658,0,0,0,305.6124,307.3163Z"/>
<path d="M250,210.9929a144.5321,144.5321,0,0,0-55.6124,96.3234,144.532,144.532,0,0,0,111.2248,0A144.5321,144.5321,0,0,0,250,210.9929Z"/>
</g>
<g id="letters">
<path d="M249.5908,115.1084h-.04l-2.2608,1.22-.34-1.34,2.8408-1.52h1.5v13.0029h-1.7Z"/>
<path d="M254.2119,265.5859v1.16l-5.6611,11.8428h-1.82l5.6406-11.503v-.04H246.01v-1.46Z"/>
<path d="M377.5254,347.1016v-1.08l1.38-1.34c3.32-3.1611,4.8213-4.8418,4.8408-6.8017a2.32,2.32,0,0,0-2.58-2.541,4.427,4.427,0,0,0-2.7607,1.1006l-.5606-1.24a5.7088,5.7088,0,0,1,3.6807-1.32,3.6594,3.6594,0,0,1,3.9814,3.7813c0,2.4-1.74,4.3408-4.4814,6.9814l-1.04.96v.04h5.8417v1.46Z"/>
<path d="M109.436,345.08a5.88,5.88,0,0,0,2.88.82c2.2607,0,2.9609-1.44,2.9409-2.5195-.02-1.82-1.6606-2.6016-3.3608-2.6016h-.98v-1.32h.98c1.28,0,2.9009-.66,2.9009-2.2,0-1.04-.66-1.96-2.2808-1.96a4.7821,4.7821,0,0,0-2.6006.8594l-.46-1.2793a6.1819,6.1819,0,0,1,3.4008-1c2.5606,0,3.7207,1.5195,3.7207,3.1a3.2286,3.2286,0,0,1-2.4,3.0606v.041a3.3856,3.3856,0,0,1,2.9,3.34c0,2.0811-1.62,3.9014-4.7412,3.9014a6.6111,6.6111,0,0,1-3.38-.88Z"/>
<path d="M169.7305,235.2827v-3.5405H163.69v-1.1607L169.49,222.28h1.9v8.082h1.8208v1.38h-1.8208v3.5405Zm0-4.9209v-4.3413q0-1.02.06-2.04h-.06c-.4.76-.72,1.32-1.08,1.92l-3.1807,4.4209v.04Z"/>
<path d="M325.0127,223.76h-4.9609l-.5,3.3408a6.9313,6.9313,0,0,1,1.06-.08,5.4945,5.4945,0,0,1,2.8008.7,3.7056,3.7056,0,0,1,1.86,3.3408,4.511,4.511,0,0,1-4.8409,4.4409,6.3659,6.3659,0,0,1-3.24-.8l.44-1.34a5.8208,5.8208,0,0,0,2.7812.72,2.8686,2.8686,0,0,0,3.08-2.8208c-.02-1.68-1.14-2.88-3.74-2.88a13.4421,13.4421,0,0,0-1.8008.14l.84-6.2417h6.2217Z"/>
<path d="M253.1924,362.9092a6.3162,6.3162,0,0,0-1.32.08,5.2845,5.2845,0,0,0-4.5215,4.6211h.06a3.9634,3.9634,0,0,1,7.0621,2.7,4.3479,4.3479,0,0,1-4.3213,4.5811c-2.7808,0-4.6011-2.16-4.6011-5.541a8.1752,8.1752,0,0,1,2.2-5.8613,7.08,7.08,0,0,1,4.1616-1.9209,8.557,8.557,0,0,1,1.28-.1Zm-.5,7.5019c0-1.86-1.0606-2.9814-2.6812-2.9814a2.8967,2.8967,0,0,0-2.52,1.6006,1.4976,1.4976,0,0,0-.2.78c.04,2.1407,1.02,3.7207,2.8609,3.7207C251.6719,373.5312,252.6924,372.2715,252.6924,370.4111Z"/>
</g>
</svg>
并且 in this CodePen 您可以检查在加色模式和减色模式下混合颜色之间的差异。
答案 8 :(得分:0)
根据物理特性,混合黄色(=红色+绿色)和蓝色 会产生白色,请参阅http://en.wikipedia.org/wiki/Additive_color。
答案 9 :(得分:0)
RGB模型中的“黄色”与RYB模型中的黄色不同,当与蓝色混合时,应该给出绿色。
作为一个例子:(255,255,0)在RGB模型中(大约)是“强烈”的两倍(0,0,255),而在RYB模型中,黄色和蓝色的EQUAL量应该给出绿色。 同样,两个模型中的红色和蓝色也不同。
将它们视为向量空间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个方程式(这2个空间中有3个颜色等式)。
不幸的是,我认为模型不能线性扩展,因此为了精确,你可能不得不使用查找表。
另一个好主意可能是转换为HSV或YCbCr空间,因为颜色信息在这些空间中更清晰地被抽象出来。 (如果确实存在RGB到RYB转换,则可能更容易找到RGB-&gt; YCbCr-&gt; RYB路径。)
答案 10 :(得分:0)
在我的应用程序中,在黑暗或光线主题中混合颜色存在同样的问题,我一直在寻找一种快速简便的解决方案。
在黑暗的主题中,我只是简单地或者RGB颜色,结果非常好,但是在浅色主题中,这导致非常浅的颜色变得不可见。
我只是尝试了颜色并且效果非常好。蓝色+黄色给了我绿色,品红色+青色给了我至少蓝色。
所以,在黑暗的主题(背景)我做:
mixed_color = color1 | color2; // Dark theme, like RGB mixing
在光明主题中:
mixed_color = color1 & color2; // Light theme, like CMY mixing
混合中不太可能有任何现实主义,但我的需求(远离摄影软件)非常令人满意。
答案 11 :(得分:0)
在这个问题上已经说了很多,但我只是想分享一种混合颜色的方式(考虑使用光照:加法方案)。
我尝试了Damien Del Russo的示例代码,根据我自己的口味,使用白色平均值计算rgb混合似乎是一个不错的方法。我想将结果与我自己的(基本和线性)代码进行比较。
不幸的是,前代码在某些情况下可以返回超过255的值...但在这些情况下,如果应用比率以回到0-255范围,结果对我来说是相同的。
对于其他情况(主要是白色成分),我可以看到结果的一些差异。差异更多的是关于光度而不是色度。 如果我尝试缩小我获得的值,我会非常接近前代码结果......
我不确定哪种方式计算它会在光度方面给出更接近的结果,但如果我得到答案,我会更新此帖子以分享结果。
知道,这里是我未完成的代码(在python中,因为它是我的原则测试平台)混合n个rgb颜色的元组:
def rgb_mix_colors(rgb_scale, *colors):
""" color mix
:param rgb_scale: scale of values
:param colors: list of colors (tuple of rgb values)
:return: relative mix of rgb colors """
r = g = b = 0
for item in colors:
try:
if not isinstance(item, tuple):
raise TypeError
if item[0] > rgb_scale or item[1] > rgb_scale or item[2] > rgb_scale:
raise ValueError
except (TypeError, ValueError):
print "WARNING: Value is outside range or unhandled parameter given as function argument!"
else:
r += item[0] # add red value from item
g += item[1] # add green value from item
b += item[2] # add blue value from item
ratio = max(r, g, b)
if ratio > rgb_scale:
ratio = float(rgb_scale) / ratio
r *= ratio
g *= ratio
b *= ratio
return int(r), int(g), int(b)
if __name__ == "__main__":
col_list = [(512, 10, 256),
(30, 120, 50),
(50, 40, 512),
"exception", # should raise TypeError when mixing
(3800, 20, 50), # should raise ValueError when mixing
(512, 10, 512)]
# example with a scale defined at 1024 instead of default, providing list of tuples as params already packed as list
print "2 warning messages should be displayed on the next line:"
print rgb_mix_colors(1024, *col_list)
print rgb_mix_colors(255, (0, 255, 0), (0, 32, 255))
答案 12 :(得分:0)
在这种情况下,最大的问题是您基于误导性假设的期望。
黄色和蓝色混合会产生绿色的说法是一种极大的简化。因为这取决于什么黄色,什么蓝色以及比例。 此外,混合光的作用与混合油漆完全相反。
当您想象一个色轮时,混合(1:1 比例)任何两种颜色,它们直接相对,无论您使用什么模型,总是会产生白色黑色或灰色。事实上,它符合现实。
尝试将您的颜色转换为 HSV 模型(色相 - 色轮上的 0° 到 360°、饱和度、值)此模型更接近人类对颜色的感知方式,并且它还允许您制作您期望的那些不切实际的结果发生。
花一些时间熟悉模型,您会发现,例如,为了获得您想要的绿色(R:0 G:255 B:0 → H:120° S:100% V:100%)
,
你需要:
混合黄色(R:255 G:255 B:0 → H:60° S:100% V:100%)
和青色(R:0 G:255 B:255 → H:180° S:100% V:100%)
这几乎只是这些值的平均值,但请注意,存在三种不同的情况:
1:较大的 H - 较小的 H = 180°
在这种情况下,颜色相互对立 - 色调未定义
2:较大的 H - 较小的 H < 180°
(较大的 H + 较小的 H)/2 = 结果 H
例如你的情况:(60°+180°)/2 = 120°
3:较大的 H - 较小的 H > 180°
(大 H + 小 H + 360°)/2 - 360°
例如:(330° + 30° + 360°)/2 - 360° = 0