(来源:kms at www1.appstate.edu)
如果这是无关的,我很抱歉 :-]
如果这是无关的,我很抱歉 :-]
最近我发现我的光谱颜色不正常,因为它们是基于非线性和偏移的数据。所以我进行了一些研究和数据编译,发现大多数光谱图像都是不正确的。此外,颜色范围也不匹配,所以我从这一点开始只使用线性化的真实光谱数据,如此(原链接现已失效):
这是我的纠正输出:
以下是RGB图表:
这是两个图表的合并:
现在是代码:
void spectral_color(double &r,double &g,double &b,double l) // RGB <0,1> <- lambda l <400,700> [nm]
{
double t; r=0.0; g=0.0; b=0.0;
if ((l>=400.0)&&(l<410.0)) { t=(l-400.0)/(410.0-400.0); r= +(0.33*t)-(0.20*t*t); }
else if ((l>=410.0)&&(l<475.0)) { t=(l-410.0)/(475.0-410.0); r=0.14 -(0.13*t*t); }
else if ((l>=545.0)&&(l<595.0)) { t=(l-545.0)/(595.0-545.0); r= +(1.98*t)-( t*t); }
else if ((l>=595.0)&&(l<650.0)) { t=(l-595.0)/(650.0-595.0); r=0.98+(0.06*t)-(0.40*t*t); }
else if ((l>=650.0)&&(l<700.0)) { t=(l-650.0)/(700.0-650.0); r=0.65-(0.84*t)+(0.20*t*t); }
if ((l>=415.0)&&(l<475.0)) { t=(l-415.0)/(475.0-415.0); g= +(0.80*t*t); }
else if ((l>=475.0)&&(l<590.0)) { t=(l-475.0)/(590.0-475.0); g=0.8 +(0.76*t)-(0.80*t*t); }
else if ((l>=585.0)&&(l<639.0)) { t=(l-585.0)/(639.0-585.0); g=0.84-(0.84*t) ; }
if ((l>=400.0)&&(l<475.0)) { t=(l-400.0)/(475.0-400.0); b= +(2.20*t)-(1.50*t*t); }
else if ((l>=475.0)&&(l<560.0)) { t=(l-475.0)/(560.0-475.0); b=0.7 -( t)+(0.30*t*t); }
}
//--------------------------------------------------------------------------
在哪里
l
是波长,单位为[nm],可用值为l = < 400.0 , 700.0 >
r,g,b
是颜色组件,范围为< 0.0 , 1.0 >
查找所需波长的CIE颜色匹配函数数值。
例如,我想获取455纳米光的颜色:
对于我们期望的波长:
╔════════════╦═══════════════════════════════╦═════════════════════════════╗
║ Wavelength ║ CIE color matching functions ║ Chromacity coordinates ║
║ λ nm ║ X │ Y │ Z ║ x │ y │ z ║
╟────────────╫──────────┼──────────┼─────────╫─────────┼─────────┼─────────╢
║ 455 ║ 0.342957 │ 0.106256 │ 1.90070 ║ 0.14594 │ 0.04522 │ 0.80884 ║
╚════════════╩══════════╧══════════╧═════════╩═════════╧═════════╧═════════╝
注意:色度坐标仅是从CIE色匹配函数计算得出的:
x = X / (X+Y+Z)
y = Y / (X+Y+Z)
z = Z / (Z+Y+Z)
X+Y+Z = 0.342257+0.106256+1.90070 = 2.349913
x = 0.342257 / 2.349913 = 0.145945
y = 0.106256 / 2.349913 = 0.045217
z = 1.900700 / 2.349913 = 0.808838
x = x = 0.145945
y = y = 0.045217
Y = y = 0.045217
(255,255,255)
表示"白色"(100, 0, 0)
表示"白色"(100, 0, 309)
表示"白色"(240, 0, 100)
表示"白色"(240, 0, 100)
表示"白色"但是实际上并不存在所谓的白色。你如何定义白色呢?是太阳光的颜色吗?
有些人用他们(非常橙色的)白炽灯泡的白色来表示白色。有些人用荧光灯的颜色。白色没有绝对的物理定义 - 白色存在于我们的大脑中。
Lab
(和Luv
)是相对于某个白点的颜色空间。即使你被迫选择了一个任意的白点,你仍然可以表示出所有可能的颜色。
而RGB不是这样的。对于RGB:
红色
,绿色
,蓝色
这些也是国际委员会在1996年选择的原色。
他们制定了一个标准,要求每个人都使用:
他们将这个标准称为sRGB
。
现在我们已经选择了我们的
我们现在可以将你的XYZ颜色转换为RGB:
不幸的是,这个RGB值存在一些问题:
因此,我们需要四舍五入:
现在我们有了最接近的波长为455纳米的光的sRGB近似值:
#00007f
和#0000ff
,则前一种颜色的亮度不会是后者的一半,而是接近于后者亮度的22%。我也不确定您想要什么样的想法消失。如果您的意思是分段线性和2.4的细节,那么它与2.2的差异与真实世界监视器的伽马曲线的不完美相比相当微不足道。 - Ruslan可见波长的近似RGB值
来源:Dan Bruton - Color Science
原始FORTRAN代码位于(http://www.physics.sfasu.edu/astro/color/spectra.html)
将返回平滑(连续)的光谱,红色成分较重。
w - 波长,R、G和B - 颜色分量
忽略伽马和强度,则简单地表示为:
if w >= 380 and w < 440:
R = -(w - 440.) / (440. - 380.)
G = 0.0
B = 1.0
elif w >= 440 and w < 490:
R = 0.0
G = (w - 440.) / (490. - 440.)
B = 1.0
elif w >= 490 and w < 510:
R = 0.0
G = 1.0
B = -(w - 510.) / (510. - 490.)
elif w >= 510 and w < 580:
R = (w - 510.) / (580. - 510.)
G = 1.0
B = 0.0
elif w >= 580 and w < 645:
R = 1.0
G = -(w - 645.) / (645. - 580.)
B = 0.0
elif w >= 645 and w <= 780:
R = 1.0
G = 0.0
B = 0.0
else:
R = 0.0
G = 0.0
B = 0.0
R=-(w - 440.) / (440. - 350.)
这些不是为中间值吗?这里的 R、G、B 是浮点数,不是整数。 - Rup频率和色调之间存在关系,但由于感知、显示器色域和校准等复杂原因,除了昂贵的实验设备外,你能做到的最好只是粗略近似。
请参见http://en.wikipedia.org/wiki/HSL_and_HSV获取数学知识,并注意你需要自己推测色调与频率的映射关系。我认为这种经验性的映射关系不可能是线性的。
我认为答案未能解决实际问题。
RGB值通常来源于XYZ色彩空间,该空间是标准人类观察者函数、照明和每个波长范围内样本的相对功率的组合,范围大约为360-830。
我不确定您想要达到什么目的,但可以计算出一个相对“准确”的RGB值,用于样本的每个离散光谱带@ 10nm都是完全饱和的。变换如下:光谱->XYZ->RGB
。请查看Bruce Lindbloom的网站了解数学知识。从XYZ中,您还可以轻松计算色调
、饱和度
或色度测量
值,例如L*a*b*
。
我发现Spektre的答案很有用,因为许多人可能无法应用其他答案中严格的CIE基于方法,但仍希望有一个基于物理实际的即插即用解决方案。
为此,我通过使用波长作为参数,将Spektre的数据与二次B样条拟合而成了修订后的算法。这样做的优点是RGB颜色随波长平滑变化(具有连续的一阶导数),并且稍微简单一些,因为大部分计算已经提前完成。这种形式也适用于矢量(SIMD)处理,如果相关的话。
在Javascript中:
function wavelengthToRGB (λ) {
const C=[
350,
3.08919e-5,-2.16243e-2, 3.78425e+0,
0.00000e+0, 0.00000e+0, 0.00000e+0,
4.33926e-5,-3.03748e-2, 5.31559e+0,
397,
-5.53952e-5, 4.68877e-2,-9.81537e+0,
6.13203e-5,-4.86883e-2, 9.66463e+0,
4.41410e-4,-3.46401e-1, 6.80468e+1,
423,
-3.09111e-5, 2.61741e-2,-5.43445e+0,
1.85633e-4,-1.53857e-1, 3.19077e+1,
-4.58520e-4, 4.14940e-1,-9.29768e+1,
464,
2.86786e-5,-2.91252e-2, 7.39499e+0,
-1.66581e-4, 1.72997e-1,-4.39224e+1,
4.37994e-7,-1.09728e-2, 5.83495e+0,
514,
2.06226e-4,-2.11644e-1, 5.43024e+1,
-6.65652e-5, 7.01815e-2,-1.74987e+1,
9.41471e-5,-1.07306e-1, 3.05925e+1,
565,
-2.78514e-4, 3.36113e-1,-1.00439e+2,
-1.79851e-4, 1.98194e-1,-5.36623e+1,
1.12142e-5,-1.35916e-2, 4.11826e+0,
606,
-1.44403e-4, 1.73570e-1,-5.11884e+1,
2.47312e-4,-3.19527e-1, 1.03207e+2,
0.00000e+0, 0.00000e+0, 0.00000e+0,
646,
6.24947e-5,-9.37420e-2, 3.51532e+1,
0.00000e+0, 0.00000e+0, 0.00000e+0,
0.00000e+0, 0.00000e+0, 0.00000e+0,
750
];
let [r,g,b] = [0,0,0];
if (λ >= C[0] && λ < C[C.length-1]) {
for (let i=0; i<C.length; i+=10) {
if (λ < C[i+10]) {
const λ2 = λ*λ;
r = C[i+1]*λ2 + C[i+2]*λ + C[i+3];
g = C[i+4]*λ2 + C[i+5]*λ + C[i+6];
b = C[i+7]*λ2 + C[i+8]*λ + C[i+9];
break;
}
}
}
return [r,g,b];
}
该函数中的数组包含每个区间(以nm为单位)的边界波长,每个边界之间有三组λ²、λ¹和λ⁰系数 - 分别对应红色、绿色和蓝色。
如果您想使用不同的单位,可以相应地转换边界值(但如果使用倒数单位,例如THz、eV或cm-1,则需要反转搜索顺序)。
如果要直接生成8位颜色分量,还可以将所有系数预乘以255(并强制转换为int类型)。