可见光谱的RGB值
我需要一个algorithm或函数来将可见光谱范围的每个波长映射到相应的RGB值。 RGB系统和光的波长之间是否有结构关系? 喜欢这个图像: 替代文本http://www1.appstate.edu/~kms/classes/psy3203/Color/spectrum5.gif 对不起,如果这是无关的: – ]
频率和所谓的色调之间有一个关系,但是由于复杂的感知原因,监视色域和校准,在昂贵的实验室设备之外所能达到的最好结果是粗略的近似值。
请参阅http://en.wikipedia.org/wiki/HSL_and_HSV获得math计算结果,并注意您需要对色调⇔频率映射进行最佳猜测。; 我期望这个经验映射不是线性的。
我最近发现,我的光谱颜色不能正常工作,因为它们是基于非线性和移位的数据。 所以我做了很less的研究和数据编辑,发现大多数光谱图像都是不正确的。 此外,颜色范围不匹配,所以我从这一点上只使用线性化的实际光谱数据
这里是我的整改输出:
- 第一个光谱是我发现的最好的再现光谱,但仍然离开真实的东西
- 第二个是从地球上取得的太阳线性化谱
- 最后一个是我目前的颜色输出
下面是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 >
400.0,700.0l = < 400.0 , 700.0 >
-
r,g,b
是返回范围< 0.0 , 1.0 >
颜色分量
部分“可见波长的近似RGB值”
信用:丹布鲁顿 – 色彩科学
原始的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
我认为答案不能解决实际问题。
RGB值通常是从XYZ色彩空间导出的,XYZ色彩空间是标准的人类观察者function,照明和在〜360-830范围内的每个波长的样品的相对功率的组合。
我不确定你要在这里实现什么,但是可以计算一个相对“准确的”RGB值,其中每个离散频谱(例如10nm)完全饱和。 变换看起来像这个光谱->XYZ->RGB
。 查看Bruce Lindbloom的math网站。 从XYZ你也可以很容易地计算hue
, chroma
或colorimetric
值,如L*a*b*
。
如果你想要一个精确的匹配,那么唯一的解决办法是执行x,y,z颜色匹配函数与你的光谱值的卷积,这样你最终得到一个(设备无关的)XYZ颜色表示,你以后可以转换成独立)RGB。
这在这里描述: http : //www.cs.rit.edu/~ncs/color/t_spectr.html
您可以在这里find用于卷积的x,y,z颜色匹配函数: http : //cvrl.ioo.ucl.ac.uk/cmfs.htm
这是颜色configuration文件处理的大部分内容。 基本上,对于给定的设备(扫描仪,照相机,监视器,打印机等),颜色configuration文件指示将由特定的一组input产生的光的实际颜色。
还要注意,对于大多数真实的设备,只处理几个不连续的光波长,而不是通过直接产生该波长来产生中间色,而是通过混合不同数量的可用的两个相邻波长。 鉴于我们以同样的方式感知颜色,这不是一个真正的问题,但取决于你为什么关心,无论如何它可能是值得了解的。
如果没有颜色configuration文件(或等效信息),则缺less将RGB值映射到颜色所需的信息。 纯红色的RGB值通常映射到设备能够产生/感应的最红的颜色(同样,纯蓝色到最蓝的颜色) – 但是“最红”或“最蓝”可以且将会变化(广泛地)基于设备。
Patapom几乎是正确的:为每个波长计算CIE XYZ值,然后使用标准公式将这些值转换(比如说)sRGB(如果幸运的话,您会发现可以用来执行此转换的代码)。 所以关键的一步是获取XYZ值。 幸运的是,对于单波长灯光来说这很简单:XYZ色彩匹配function只是列出给定波长的XYZ值的表格。 所以只要看看。 如果你有更复杂的光谱,也许是一个黑色的身体,那么你必须平均XYZ的反应乘以每个波长的光量。
VBA代码由Dan Bruton(astro@tamu.edu)的近似“可见波长的RGB值”派生而来。 链接到他原来的Fortran代码: http : //www.physics.sfasu.edu/astro/color/spectra.html Spectra程序: http : //www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm
Sub Wavelength_To_RGB() 'Purpose: Loop thru the wavelengths in the visible spectrum of light ' and output the RGB values and colors to a worksheet. ' Wavelength range: 380nm and 780nm Dim j As Long, CellRow As Long Dim R As Double, G As Double, B As Double Dim iR As Integer, iG As Integer, iB As Integer Dim WL As Double Dim Gamma As Double Dim SSS As Double Gamma = 0.8 CellRow = 1 For j = 380 To 780 WL = j Select Case WL Case 380 To 440 R = -(WL - 440#) / (440# - 380#) G = 0# B = 1# Case 440 To 490 R = 0# G = ((WL - 440#) / (490# - 440#)) B = 1# Case 490 To 510 R = 0# G = 1# B = (-(WL - 510#) / (510# - 490#)) Case 510 To 580 R = ((WL - 510#) / (580# - 510#)) G = 1# B = 0# Case 580 To 645 R = 1# G = (-(WL - 645#) / (645# - 580#)) B = 0# Case 645 To 780 R = 1# G = 0# B = 0# Case Else R = 0# G = 0# B = 0# End Select 'LET THE INTENSITY SSS FALL OFF NEAR THE VISION LIMITS If WL > 700 Then SSS = 0.3 + 0.7 * (780# - WL) / (780# - 700#) ElseIf WL < 420 Then SSS = 0.3 + 0.7 * (WL - 380#) / (420# - 380#) Else SSS = 1# End If 'GAMMA ADJUST R = (SSS * R) ^ Gamma G = (SSS * G) ^ Gamma B = (SSS * B) ^ Gamma 'Multiply by 255 R = R * 255 G = G * 255 B = B * 255 'Change RGB data type from Double to Integer. iR = CInt(R) iG = CInt(G) iB = CInt(B) 'Output to worksheet Cells(CellRow, 1).Interior.Color = RGB(iR, iG, iB) Cells(CellRow, 2) = WL Cells(CellRow, 3) = "(" & iR & "," & iG & "," & iB & ")" CellRow = CellRow + 1 Next j End Sub