在javascript中"自然地"混合两种颜色

Tam*_*Pap 30 javascript math color-scheme colors

问题:我想在javascript中混合两种颜色,并获得结果颜色.在SO上有很多类似的问题,但我没有发现任何实际上正常工作的问题.我知道混合两种不同颜色的颜料(颜料)和灯会产生非常不同的结果(http://en.wikipedia.org/wiki/Color_mixing).

以下是我已经看到的问题和建议的解决方案,并尝试实施:

1: 混合两个RGB颜色矢量以得到结果
因此,混合RGB中的颜色.我实现了它,在某些情况下它可以在某些情况下使用它没有.

工作示例:redyellow- > 混合orange.大!
http://jsbin.com/afomim/1/edit

不工作的例子:blueyellow- > 混合gray.不太好!:) http://jsbin.com/afomim/5/edit
我知道,在RGB混合blue使用yellow不会让green的,我明白为什么.

我们不会在这里找到答案,让我们继续前进.

2: 像油漆一样添加颜色(颜色)(蓝色+黄色=绿色等)

让我们尝试使用本讨论中建议的CMYK值.混合cyanyellow给出green:
http://jsbin.com/igaveg/1/edit
但混合blue使用yellow的结果black.
http://jsbin.com/igaveg/2/edit - >不工作!

3: 如何将"自然"与C#混合使用?
一个非常相似的问题.最受欢迎的答案建议将颜色转换为LAB,这个解决方案似乎很有希望.
所以我将我的颜色转换为LAB.转换算法是正确的,我测试了它!

http://jsbin.com/oxefox/1/edit

现在我在LAB中有两种颜色,但是如何混合呢?

注:我知道,可能我会找不到一个混合算法中blue使用yellow,并给完美的green,但我希望我能够生成类似于绿色的东西:)

Tam*_*Pap 33

我这个问题专门用了3-4天.这是一个非常复杂的问题.

如果你想"自然地"混合两种颜色,你可以做以下几点:

  1. CMYK混音:它不是一个完美的解决方案,但如果您现在需要一个解决方案,并且您不想花费数月时间学习该主题,试验和编码,您可以查看:https://github.com/ AndreasSoiron/Color_mixer

  2. 实施Kubelka-Munk理论.我花了很多时间阅读它,并试图理解它.如果你想要一个专业的解决方案,这应该是要走的路,但它需要6个参数(如反射,吸收等),你想要混合的每种颜色.有R,G,B是不够的.实现理论并不难,但是获取每种颜色所需的参数似乎是缺失的部分.如果你弄明白该怎么做,请告诉我:)

  3. 实验:你可以做一些ipad应用程序的开发人员:Paper已经完成了.他们手动选择了100对流行的颜色和眼球测试它们应该如何混合.在此了解更多信息.

我个人将暂时实施CMYK混音,也许稍后,如果我有时间,我会尝试制作像Fiftythree这样的人.等着瞧 :)


Mar*_*n R 12

RYB颜色模型可能是混色计算一个合适的选择.据维基百科称,它主要用于艺术和设计教育,尤其是绘画.

要混合使用2种颜色,可以将RGB中的颜色转换为RYB,通过添加每种颜色成分来混合颜色,并将生成的颜色从RYB转换回RGB.

我使用在线颜色混合工具尝试了这个,结果是

  • 混合#FFFF00(黄色)的0000FF(蓝色)给出#008000(深绿色),

  • 与#FFFF00(黄色)混合的FF0000(红色)给出#FFA000(橙色).

因此,此方法可以准确地生成您期望的结果.

不幸的是,我无法找到带有"即用型"公式的参考,无法将RGB转换为RYB并返回RGB.

Paper Paint Inspired Color Mixing and Compositing for Visualization - Gossett和Chen 在"2实现直观颜色混合"一节中描述了RYB颜色模型的一般概念.

根据该论文,从RYB到RGB的转换是通过三线性插值完成的 .

困难的部分是从RGB到RYB的转换,因为它需要三线性插值的反演.有关 更多信息,请参阅RGB和RYB颜色空间之间的转换.

即使这个答案没有提供完整的计算公式,我希望它提供了一些如何继续的想法.


小智 6

当尝试将2种RGB颜色混合在一起时,我实际上遇到了相同的问题。这两个功能对我有用:

//colorChannelA and colorChannelB are ints ranging from 0 to 255
function colorChannelMixer(colorChannelA, colorChannelB, amountToMix){
    var channelA = colorChannelA*amountToMix;
    var channelB = colorChannelB*(1-amountToMix);
    return parseInt(channelA+channelB);
}
//rgbA and rgbB are arrays, amountToMix ranges from 0.0 to 1.0
//example (red): rgbA = [255,0,0]
function colorMixer(rgbA, rgbB, amountToMix){
    var r = colorChannelMixer(rgbA[0],rgbB[0],amountToMix);
    var g = colorChannelMixer(rgbA[1],rgbB[1],amountToMix);
    var b = colorChannelMixer(rgbA[2],rgbB[2],amountToMix);
    return "rgb("+r+","+g+","+b+")";
}
Run Code Online (Sandbox Code Playgroud)

若要将红色([255,0,0])与蓝色([0,0,255])均匀混合,可以调用

colorMixer([255,0,0], [0,0,255], 0.5);//returns "rgb(127,0,127)" (purple)
Run Code Online (Sandbox Code Playgroud)

这可能会有所帮助,尽管您必须先将每个颜色值转换为数组。如果使用Fabric.js处理画布元素,这将变得非常容易。刚打电话

var rgbA = new fabric.Color(yourColor);
var rgbB = new fabric.Color(yourSecondColor);
Run Code Online (Sandbox Code Playgroud)

然后打电话

colorMixer(rgbA.getSource(),rgbB.getSource(),0.5);
Run Code Online (Sandbox Code Playgroud)

希望这些功能有所帮助。

  • 这真的很有帮助。谢谢! (2认同)

Gir*_*rpa 6

当前接受的答案链接到此存储库,该存储库具有过期的演示页面并使用冗长、过时的代码。

所以我基于相同的代码编写了一个普通的 JavaScript 颜色混合器:

console.log(mix_hexes('#3890b9', '#f6ff00')); // #8cc46f

function hex2dec(hex) {
  return hex.replace('#', '').match(/.{2}/g).map(n => parseInt(n, 16));
}

function rgb2hex(r, g, b) {
  r = Math.round(r);
  g = Math.round(g);
  b = Math.round(b);
  r = Math.min(r, 255);
  g = Math.min(g, 255);
  b = Math.min(b, 255);
  return '#' + [r, g, b].map(c => c.toString(16).padStart(2, '0')).join('');
}

function rgb2cmyk(r, g, b) {
  let c = 1 - (r / 255);
  let m = 1 - (g / 255);
  let y = 1 - (b / 255);
  let k = Math.min(c, m, y);
  c = (c - k) / (1 - k);
  m = (m - k) / (1 - k);
  y = (y - k) / (1 - k);
  return [c, m, y, k];
}

function cmyk2rgb(c, m, y, k) {
  let r = c * (1 - k) + k;
  let g = m * (1 - k) + k;
  let b = y * (1 - k) + k;
  r = (1 - r) * 255 + .5;
  g = (1 - g) * 255 + .5;
  b = (1 - b) * 255 + .5;
  return [r, g, b];
}


function mix_cmyks(...cmyks) {
  let c = cmyks.map(cmyk => cmyk[0]).reduce((a, b) => a + b, 0) / cmyks.length;
  let m = cmyks.map(cmyk => cmyk[1]).reduce((a, b) => a + b, 0) / cmyks.length;
  let y = cmyks.map(cmyk => cmyk[2]).reduce((a, b) => a + b, 0) / cmyks.length;
  let k = cmyks.map(cmyk => cmyk[3]).reduce((a, b) => a + b, 0) / cmyks.length;
  return [c, m, y, k];
}

function mix_hexes(...hexes) {
  let rgbs = hexes.map(hex => hex2dec(hex)); 
  let cmyks = rgbs.map(rgb => rgb2cmyk(...rgb));
  let mixture_cmyk = mix_cmyks(...cmyks);
  let mixture_rgb = cmyk2rgb(...mixture_cmyk);
  let mixture_hex = rgb2hex(...mixture_rgb);
  return mixture_hex;
}
Run Code Online (Sandbox Code Playgroud)