расчет смешанного цвета в rgb

<p>я хочу иметь возможность взять два вектора rgb-256 и рассчитать результат их смешивания. также я хочу, чтобы у каждого вектора был свой вес. я экспериментировал с этим, используя цветовую пластинку word, и видел, что некоторые цвета смешиваются в соответствии со средневзвешенным значением:</p><p><code>0.5*red(255,0,0) + 0.5*yellow(255,255,0) = orange(255,127,0)</code></p><p>другие не делают:</p><p><code>0.5*yellow(255,255,0) + 0.5*blue(0,0,255) = gray (127,127,127)</code> а не <code>green (0,255,0)</code></p><p>есть ли алгоритм для точного расчета для всех цветов, или я вынужден сделать это с помощью справочной таблицы?</p>

<p><strong>лучшее объяснение состоит в том, что <a href="http://en.wikipedia.org/wiki/rgb\_color\_model">цветовая модель rgb</a> является несколько <em>не интуитивно понятной</em> для нас, людей.</strong><br> это вполне логично для устройства отображения видео (например, монитора или телевизора), которое знает, как отображать цвета, смешивая различное количество трех предопределенных цветов: красного, зеленого и синего. но это не так, как вы и я научились смешивать цвета в начальной школе.</p><p>в rgb белый цвет представлен как (255, 255, 255), что соответствует «все включено». отображается полное значение для каждого из красного, зеленого и синего цветовых компонентов, что создает такую высокую интенсивность света, что мы воспринимаем цвет как белый. и наоборот, черный цвет (0, 0, 0) является состоянием «по умолчанию» устройства отображения - когда не отображается цветная подсветка («0»), результатом является черный или отсутствие цвета.</p><p>когда вы полностью смешаете желтый (255, 255, 0) и синий (0, 0, 255), вы получите цвет, представленный (255, 255, 255) или <em>белый</em>. когда вы умножаете белый на 0,5, вы получаете серый цвет, потому что 255 * 0,5 = 127.</p><p>вероятно, это скорее аномалия, чем что-либо, что дает ожидаемый результат при смешивании красного и желтого. красный + желтый (510, 255, 0), поэтому, если вы умножите это на 0,5, вы получите оранжевый (255, 127, 0).</p><p>оказывается, то, что вы и я узнали в начальной школе, действительно более точно известно как <a href="http://en.wikipedia.org/wiki/subtractive\_color"><em>вычитающая</em> цветовая модель</a> , в отличие от <a href="http://en.wikipedia.org/wiki/additive\_color"><em>аддитивная</em> цветовая модель</a> используемая rgb. посмотрев на две диаграммы внизу, вы увидите цветовую модель rgb (аддитивную) слева, а цветовую модель cmyk (вычитающую) справа. вы должны быть в состоянии немедленно увидеть проблему. использование вычитающей цветовой модели даст желаемые результаты.</p><p><img src="https://i.stack.imgur.com/lcbvq.gif" alt="rgb color model"><img src="https://i.stack.imgur.com/izggs.gif" alt="cmyk color model"></p><p><strong>edit:</strong> конечно, это легче сказать, чем сделать. то есть, даже если вы принимаете цветовую модель cmyk вместо rgb (что уже сложно, потому что преобразования из rgb в cmyk являются <em>сильно</em> зависимыми от устройства и далеко не простыми), это, вероятно, все еще не удовлетворит настоятельно рекомендуем смешать чистый синий (0, 0, 255) с чистым желтым (255, 255, 0) и получить зеленый. cmyk использует голубой, пурпурный и желтый в качестве 3 основных цветов вместо красного, желтого и синего. и у вас впереди <em>много</em> работы, если вы хотите реализовать <a href="http://en.wikipedia.org/wiki/ryb\_color\_model">цветовую модель ryb</a> на выбранном вами языке.</p><p>я не знаю ни одного такого алгоритма для реалистичного сочетания цветов rgb. в своем ответе я пытался объяснить, почему это было бы невозможно или, по крайней мере, крайне сложно. вы можете оставить этот вопрос открытым еще несколько дней и посмотреть, есть ли у кого-нибудь еще какие-либо идеи, но я бы пошел дальше и начал бы с этой справочной таблицы, если вам нужно придерживаться модели rgb. ;-)</p>

<p>основываясь на этом <a href="https://stackoverflow.com/a/4256156/848072">задокументированном ответе</a> и на этом <a href="https://stackoverflow.com/a/1351485/848072">ответе с учетом алгоритма</a> , я попробовал простой интерфейс для смешивания цветов с использованием аддитивного и субстративного подхода.</p><p>вы должны подтвердить, что основные цвета rgb и cmyk дают вам вторичные цвета на первых диаграммах ответов:</p><ul> <li>красный + синий = пурпурный (на добавке)</li> <li>желтый + голубой = зеленый (на субстративном)</li> <li>и так далее ...</li> </ul><pre><code>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; } } </code></pre><p><img src="https://i.stack.imgur.com/gae07.png" alt="color mixing interface"></p><p>по сути, эти операции подобны логике и и логике или. (ну не совсем) </p><ul> <li>на аддитивном алгоритме цвета перекрываются, но для каждого основного значения это может быть только 255 (логическая операция or)</li> <li>на субстративном алгоритме, если какой-то первичный элемент отсутствует, результат не будет иметь этого (cyan не имеет красного, желтый не имеет синего: вы получаете зеленый) (логика и операция)</li> </ul><p>основываясь на <a href="http://en.wikipedia.org/wiki/tertiary\_color">это</a> вы можете получить третичные цвета из смеси первичных и вторичных цветов, поэтому я делаю крошечную реализацию, которая работает довольно хорошо:</p><pre><code>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 </code></pre><p>существует также разбавляющий/субстративный алгоритм, упомянутый во втором цитируемом ответе, но я не могу сказать, на чем он основан, только что добавленный в тест.</p>

<p>настоящий ответ - изменить цветовое векторное пространство rgb на аддитивное, а затем изменить его на rgb. в этом новом векторном пространстве при добавлении двух световых векторов учитываются аддитивные свойства света и наше восприятие цвета для получения аддитивного цвета.</p><p>оказывается, векторное пространство cie xyz хорошо работает для этой цели.</p><p>векторы xyz аддитивны в этом пространстве и смешиваются, как и источники света.</p><p>смотрите <a href="http://www.cree.com/~/media/files/cree/led-components-and-modules/xlamp/xlamp-application-notes/led\_color\_mixing.pdf">этот документ о смешивании цветов</a> от cree:</p><pre><code>x\_mix = x1 + x2 + ... y\_mix = y1 + y2 + ... z\_mix = z1 + z2 + ... </code></pre><p>затем вы можете изменить базу обратно на rgb. для изменения цвета между векторными пространствами доступно много библиотек, и ciexyz стандартизирован и широко поддерживается.</p><p>этот метод дает реалистичные результаты, которые подходят для большинства моих целей.</p><p>больше информации о <a href="https://en.wikipedia.org/wiki/cie\_1931\_color\_space">цветовое пространство cie 1931</a> .</p>

<p>глядя на ответ коди грей, я думаю, что могу предложить, как сочетать цвета. преобразование цветового круга в rgb:</p><pre><code> cyan(0, 255, 255) blue(0, 0, 255) green(0, 255, 0) magenta(255, 0, 255) red(255, 0, 0) yellow(255, 255, 0) </code></pre><p>без дополнительных сложностей цвета можно комбинировать следующим образом: инвертировать оба цвета, сложить их вместе и инвертировать результат (actionscript):</p><pre><code>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; } </code></pre><p>результат:</p><pre><code>cyan + magenta = 0 0 255 red + green = 0 0 0 black + black = 0 0 0 black + white = 0 0 0 </code></pre><p>посмотри, подходит ли это тебе.</p><p>правка: я не притворяюсь, что это физически правильно, это просто попытка приблизиться. идея таблицы поиска звучит для меня безумно по двум причинам: она зависит от двух аргументов, поэтому ее размер будет очень большим; и законы природы обычно непрерывны без каких-либо или редких угловых случаев. если вы можете заполнить справочную таблицу, вы должны знать алгоритм - так что просто напишите для нее функцию.</p>

<p>я просто хотел указать, почему вы становитесь серыми, когда добавляете<strong> синий </strong>. это потому, что вы добавляете<strong> синий </strong>, а не<strong> голубой </strong>:</p><p><img src="https://i.stack.imgur.com/gk7sb.png" alt="enter image description here"></p><ul> <li>если вы добавите<strong> cyan </strong>в желтый, вы получите<strong> зеленый </strong></li> <li>если вы добавите<strong> синий </strong>(т.е. голубой + magents) к желтому, вы получите серый.</li> </ul><p>или, более математически:</p><pre><code>yellow + (cyan ) = green yellow + (cyan + magenta) = gray yellow + (blue) = gray </code></pre><p>вы добавляете<strong> blue </strong>, когда вы хотели добавить<strong> cyan </strong>.</p><pre><code>0.5*yellow(255,255,0) + 0.5*cyan(0,255,255) = verylightlimegreen(128,255,128) </code></pre>

<p>вот java-реализация теории отражения кубелки-мунка для смешивания цветов rgb. в этой реализации используется упрощенная версия модели кубелка-мунка, которая предполагает, что все цвета имеют одинаковую концентрацию при смешивании, и что все цвета непрозрачны.</p><p> <a href="https://github.com/benjholla/colormixer">https://github.com/benjholla/colormixer</a> </p>

<p>я не думаю, что ответы выше дают адекватные результаты микширования.</p><p>я работал над этой проблемой как с rgb, так и с ryb (после конвертации из rgb). преобразование для rgb в ryb здесь хорошо: <a href="http://www.insanit.net/tag/rgb-to-ryb/">http://www.insanit.net/tag/rgb-to-ryb/</a> (я поделюсь своим кодом по запросу).</p><p>если смешивать как свет, это не так уж плохо (см. ниже). если вы хотите смешивать физические материалы, такие как paint, то это <em>немного</em> хитрее - я работаю над приложением, чтобы изучить его. </p><p>вернемся к первоначальному вопросу - вот мой код для микширования rgb. rgbcolor - это пользовательский класс, но я думаю, что это имеет смысл само по себе:</p><pre><code>-(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; } </code></pre>

<p>имея ту же проблему со смешением цветов в темной или светлой теме в моем приложении, я искал быстрое и простое решение.</p><p>в темной теме я просто использовал цвета rgb, и результат был довольно хорошим, однако в светлой теме это привело к тому, что очень светлые цвета стали невидимыми.</p><p>я просто пробовал и красил, и это работало довольно хорошо. синий + желтый дал мне зеленый, пурпурный + голубой дал мне по крайней мере синий.</p><p>итак, в темной теме (задний фон) я делаю:</p><pre><code>mixed\_color = color1 | color2; // dark theme, like rgb mixing </code></pre><p>в светлую тему:</p><pre><code>mixed\_color = color1 & color2; // light theme, like cmy mixing </code></pre><p>маловероятно, что в миксе есть какой-либо реализм, но для моей потребности (вдали от программного обеспечения для фотографии) это было вполне удовлетворительно.</p>

<p>«желтый» в модели rgb - это не то же самое, что желтый в модели ryb, который при смешивании с синим должен давать зеленый.</p><p>в качестве примера: (255, 255, 0) (приблизительно) вдвое "интенсивнее", чем (0, 0, 255) в модели rgb, в то время как в модели ryb предполагается, что равные количества желтого и синего дают зеленый. аналогично, красный и синий в двух моделях различны. </p><p>думайте о них как о векторных пространствах rgb и r'y'b '.</p><p>если какое-то отношение вроде:</p><pre><code>r = i1*r' + j1*y' + k1*b'; g = i2*r' + j2*y' + k2*b'; b = i3*r' + j3*y' + k3*b'; </code></pre><p>держите, вы можете сделать свою алгебру, сначала преобразовав отдельные цвета (операнды) из rgb в пространство r'y'b '.</p><p>есть 9 неизвестных (переменные i, j, k), поэтому вам нужно 9 уравнений (3 цветовых равенства в этих двух пространствах).</p><p>к сожалению,<em> я думаю </em>/ что модели не масштабируются линейно, и, следовательно, для точности вам, возможно, придется использовать справочные таблицы.</p><p>другой хорошей идеей может быть преобразование в пространство hsv или ycbcr, поскольку информация о цвете более четко абстрагируется в этом пространстве. (если преобразование rgb в ryb существует, маршрут rgb-> ycbcr-> ryb может быть легче найти).</p>

<p>смешивание желтого (= красный + зеленый) и синего <em>действительно</em> дает белый цвет в соответствии с физикой, см. <a href="http://en.wikipedia.org/wiki/additive\_color">http://en.wikipedia.org/wiki/additive\_color</a> .</p>

<p>многое уже было сказано по этому вопросу, но я просто хотел поделиться способом смешивания цветов (учитывая работу со светом: схема добавления).</p><p>я попробовал пример кода от дэмиена дель руссо, который мне показался хорошим подходом, использующим среднее значение белого для вычисления rgb-микса. я хотел сравнить результаты с моим собственным (базовым и линейным) кодом.</p><p>к сожалению, бывший код может возвращать значения, которые в некоторых случаях превышают 255 ... но в этих случаях результат для меня тот же, если применяется соотношение для возврата к диапазону 0-255.</p><p>для других случаев (в основном с белым компонентом) я вижу некоторые различия в результатах. разница скорее в яркости, чем в цветности .... если я пытаюсь уменьшить полученные значения, я очень близок к предыдущим результатам кода ...</p><p>я еще не уверен, какой способ вычисления дает более близкие результаты с точки зрения яркости, но если я получу ответ, я обновлю этот пост, чтобы поделиться результатами.</p><p>зная это, вот мой незавершенный код (на python, так как это мой стенд для тестирования принципов) для смешивания n наборов цветов rgb:</p><pre class="lang-py prettyprint-override"><code>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)) </code></pre><p> <a href="/questions/tagged/mixing">смешивание</a> <a href="/questions/tagged/colors">цвета</a> <a href="/questions/tagged/adding">добавление</a> <a href="/questions/tagged/light">свет</a> <a href="/questions/tagged/rgb">rgb</a> <a href="/questions/tagged/python">python</a> </p>