RGB значения видимого спектра
Мне нужен алгоритм или функция для сопоставления каждой длины волны видимого диапазона спектра с его эквивалентными значениями RGB. Есть ли структурная связь между системой RGB и длиной волны света? как это изображение: http://www1.appstate.edu/~kms/classes/psy3203/Color/spectrum5.gifизвините, если это не имеет значения:-]
12 ответов
Существует взаимосвязь между частотой и так называемым оттенком, но по сложным причинам восприятия, гаммы мониторов и калибровки лучшее, чего вы можете достичь вне дорогого лабораторного оборудования, - это грубое приближение.
См. http://en.wikipedia.org/wiki/HSL_and_HSV по математике и обратите внимание, что вам нужно будет высказать свое наилучшее предположение относительно отображения частоты Hue ⇔. Я ожидаю, что это эмпирическое отображение будет совсем не линейным.
Недавно я обнаружил, что мои спектральные цвета не работают должным образом, потому что они основаны на нелинейных и сдвинутых данных. Поэтому я мало исследовал и собирал данные и обнаружил, что большинство изображений спектра неверны. Кроме того, цветовые диапазоны не совпадают друг с другом, поэтому я использовал с этой точки только линеаризованные данные реальной спектроскопии, подобные этой
Вот мой выпрямленный выход:
- первый спектр - лучший спектр, который я нашел, но он все еще далек от реального
- второй - линеаризованный спектр нашего Солнца, взятый с Земли
- последний мой текущий цветовой вывод
Ниже приведены графики 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
это длина волны в [нм]l = < 400.0 , 700.0 >
r,g,b
возвращают цветовые компоненты в диапазоне< 0.0 , 1.0 >
Чтобы преобразовать длину волны в цвет RGB
Сначала вы обращаетесь к дополнительной стандартной колориметрической карте CIE 1964 ( архив)
и найдите значения функции соответствия цветов CIE для нужной длины волны.
Например, я хочу получить цвет света 455 нм:
Для нашей желаемой длины волны:
| nm | 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
Ваш свет 455 нм указан в двух разных цветовых пространствах:
- XYZ: (0,342957, 0,106256, 1,900700)
- xyz: (0,145945, 0,045217, 0,808838)
Мы также можем добавить третье цветовое пространство: xyY
x = x = 0.145945
y = y = 0.045217
Y = y = 0.045217
Теперь у нас есть свет 455 нм, указанный в 3 разных цветовых пространствах:
- XYZ: (0,342957, 0,106256, 1,900700)
- xyz: (0,145945, 0,045217, 0,808838)
- xyY: (0,145945, 0,045217, 0,045217)
Итак, мы преобразовали длину волны чистого монохроматического излучаемого света в цвет XYZ. Теперь мы хотим преобразовать это в RGB.
Как конвертировать XYZ в RGB?
XYZ, xyz и xyY - это абсолютные цветовые пространства, которые описывают цвета с использованием абсолютной физики.
Между тем, каждое практическое цветовое пространство, которое люди используют:
- лаборатория
- Luv
- HSV
- HSL
- RGB
зависит какая-то белая точка. Затем цвета описываются как относящиеся к этой белой точке.
Например,
- RGB белый (255,255,255) означает "белый"
- Lab white (100, 0, 0) означает "белый"
- LCH белый (100, 0, 309) означает "белый"
- HSL белый (240, 0, 100) означает "белый"
- HSV белый (240, 0, 100) означает "белый"
Но нет такого цвета, как белый. Как вы определяете белый? Цвет солнечного света?
- в какое время суток?
- с какой облачностью?
- на какой широте?
- на земле?
Некоторые люди используют белый цвет своих (ужасно оранжевых) ламп накаливания для обозначения белого. Некоторые люди используют цвет своих флуоресцентных ламп. Не существует абсолютного физического определения белого - белый в нашем мозгу.
Таким образом, мы должны выбрать белый
Мы должны выбрать белый. (На самом деле вы должны выбрать белый.) И есть много белых на выбор:
- Осветитель А: вроде как вольфрамовая лампа
- Иллюминант B & C: попытка подделать солнечный свет в полдень, установив фильтры перед лампой накаливания
- Осветитель D50: естественный дневной свет 5000К
- Осветитель D55: 5500K, естественный дневной свет
- Illuminant D65: 6504K естественный дневной свет
- Осветитель D75: естественный дневной свет 7500K
- Иллюминант E: теоретически всех цветов одинаково присутствует
- Источник света F: флуоресцентные лампы (FL8)
- Осветитель L: светодиодное освещение
Я выберу белый для вас. Тот же самый белый, который использует sRGB:
- D65 - дневное освещение ясного летнего дня в северной европе
D65 (цвет которого близок к 6504K, но не совсем из-за атмосферы Земли) имеет цвет:
- XYZ_D65: (0,95047, 1,00000, 1,08883)
С этим вы можете конвертировать ваши XYZ
в Lab
(или же Luv
) - цветовое пространство, одинаково способное выразить все теоретические цвета. И теперь у нас есть 4-е представление цветового пространства нашего 445 нм монохроматического излучения света:
- XYZ: (0,342957, 0,106256, 1,900700)
- xyz: (0,145945, 0,045217, 0,808838)
- xyY: (0,145945, 0,045217, 0,045217)
- Лаборатория: (38,94259, 119,14058, -146,08508) (при условии d65)
Но вы хотите RGB
Lab
(а также Luv
) - это цветовые пространства, относящиеся к некоторой белой точке. Даже если вы были вынуждены выбрать произвольную белую точку, вы все равно можете представлять все возможные цвета.
RGB не такой. С RGB:
- не только цвет относительно некоторой белой точки
- но это также относительно трех основных цветов: красный, зеленый, синий
Если вы указываете цвет RGB (255, 0, 0), вы говорите, что хотите "просто красный". Но нет определения красного. Нет такой вещи как "красный", "зеленый" или "синий". Радуга непрерывна и не идет со стрелой, говорящей:
Это красный
И снова это означает, что мы должны выбрать три выбрать три основных цвета. Вы должны выбрать три основных цвета, чтобы сказать, что такое "красный", "зеленый" и "синий". И снова у вас есть много разных определений красного, зеленого, синего на выбор:
- CIE 1931
- ROMM RGB
- Adobe Wide Gamut RGB
- DCI-Р3
- NTSC (1953)
- Apple RGB
- SRGB
- Японский NTSC
- PAL / SECAM
- Adobe RGB 98
- scRGB
Я выберу для вас. Я выберу эти три цвета:
- Красный: xyY = (0,6400, 0,3300, 0,2126)
- Зеленый: xyY = (0,3000, 0,6000, 0,7152)
- Синий: xyY = (0,1500, 0,0600, 0,0722)
Это были также праймериз, выбранные международным комитетом в 1996 году.
Они создали стандарт, который сказал, что каждый должен использовать:
- Whitepoint: дневной свет D65
- Красный: (0,6400, 0,3300, 0,2126)
- Зеленый: (0.3000, 0.6000, 0.7152)
- Синий: (0,1500, 0,0600, 0,0722)
И они назвали этот стандарт sRGB
,
Финальный толчок
Теперь, когда мы выбрали наш
- бело-точка
- три праймериз
Теперь мы можем преобразовать ваш цвет XYZ в RGB:
- RGB = (1,44750, -178,21694, 345,59392)
К сожалению, есть некоторые проблемы с этим значением RGB:
- ваш монитор не может отображать отрицательный зеленый (-178.21694); это означает, что это цвет вне того, что может отображать ваш монитор.
- ваш монитор не может отображать больше синего, чем 255 (345,59392); только монитор будет таким же синим, как и синий - он не может быть синее. Это означает, что это цвет вне того, что может отображать ваш монитор.
Итак, мы должны округлить:
- XYZ: (0,342957, 0,106256, 1,900700)
- xyz: (0,145945, 0,045217, 0,808838)
- xyY: (0,145945, 0,045217, 0,045217)
- Lab: (38,94259, 119,14058, -146,08508) (д65)
- RGB: (1, 0, 255) (sRGB)
И теперь мы имеем ближайшее приближение sRGB длины волны 455 нм света:
Частичное "Приблизительные значения RGB для видимых длин волн"
Предоставлено: Дэн Брутон - 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
Если вы хотите точное совпадение, то единственное решение состоит в том, чтобы выполнить свертку функций сопоставления цветов x,y,z с вашими спектральными значениями, чтобы вы наконец получили (независимое от устройства) представление цвета XYZ, которое вы позже сможете преобразовать в (устройство -зависимый) RGB.
Это описано здесь: http://www.cs.rit.edu/~ncs/color/t_spectr.html
Вы можете найти функцию сопоставления цветов x,y,z для свертки здесь: http://cvrl.ioo.ucl.ac.uk/cmfs.htm
Я думаю, что ответы не решают проблему с реальным вопросом.
Значения RGB обычно выводятся из цветового пространства XYZ, которое является комбинацией стандартной функции наблюдателя, освещенности и относительной мощности образца на каждой длине волны в диапазоне ~360-830.
Я не уверен в том, чего вы пытаетесь достичь здесь, но было бы возможно рассчитать относительно "точное" значение RGB для выборки, где каждая дискретная полоса спектра при, скажем, 10 нм была полностью насыщена. Трансформация выглядит как этот спектрум ->XYZ->RGB
, Проверьте сайт Брюса Линдблума по математике. Из XYZ вы также можете легко рассчитать hue
, chroma
или же colorimetric
такие значения, как L*a*b*
,
Это большая часть цветовых профилей. В основном, для данного устройства (сканер, камера, монитор, принтер и т. Д.) Цветовой профиль сообщает, какие фактические цвета света будут генерироваться определенным набором входов.
Также обратите внимание, что для большинства реальных устройств вы имеете дело только с несколькими дискретными длинами волн света, и промежуточные цвета создаются не путем непосредственного получения этой длины волны, а путем смешивания различного количества двух соседних доступных длин волн. Учитывая, что мы воспринимаем цвет одинаково, это на самом деле не проблема, но в зависимости от того, почему вы заботитесь, в любом случае это стоит знать.
Без цветового профиля (или эквивалентной информации) вам не хватает информации, необходимой для сопоставления значения RGB с цветами. Значение RGB чистого красного цвета обычно отображается на самый красный цвет, который устройство способно воспроизводить / воспринимать (и аналогично, чистый синий на самый синий цвет), но этот "самый красный" или "самый синий" может и будет изменяться (широко) на основе устройства.
У Patapom это почти правильно: для каждой длины волны вы вычисляете значения CIE XYZ, а затем конвертируете их в (скажем) sRGB, используя стандартные формулы (если вам повезет, вы найдете код, который вы можете просто использовать для этого преобразования). Таким образом, ключевым шагом является получение значений XYZ. К счастью, для одноволнового света это легко: функции подбора цвета XYZ - это просто таблицы, в которых перечислены значения XYZ для данной длины волны. Так что просто посмотрите. Если бы у вас был свет с более сложным спектром, может быть, с черным телом, вам пришлось бы усреднять XYZ-ответы, умноженные на количество каждой длины волны в свете.
Я не программист. Я не врач. Я просто музыкант с двумя глазами (как и у любого человека).
Итак... Я знаю, что электромагнитные волны имеют логарифмический масштаб в диапазоне радио и телевидения. Почему он должен отличаться в диапазоне видимого света?
В мире радио и телевидения мы используем простое уравнение: мы делим заданный диапазон между двумя частотами на заданное количество частей в соответствии с соотношением между крайними частотами.
Скажем: если наш диапазон начинается с 100 МГц и заканчивается на 200 МГц, у нас есть отношение 2 (200 равно 100, умноженному на 2).
Итак, если нам нужно разделить этот диапазон на 10 равных частей, мы должны использовать это уравнение:
Первая частота (100 МГц), умноженная на корень 10-й степени из 2.
Это новое значение умножается на корень 10-й степени из 2.
И так далее.
Почему мы используем корень 10-й степени из 2? Просто: помните, что это не линейная шкала, это шкала логарифма (точно такая же, как у музыкальных нот).
Итак, основываясь на этом уравнении, поскольку мы знаем, что спектр видимого света составляет от 780 до 380 нанометров (приблизительно от 384,02 ТГц до 789,26 ТГц; оба значения очень приблизительны, потому что это переменное значение в соответствии с индивидуальными оптическими возможностями), мы просто должны знать соотношение между этими частотами:
789,26/384,02=2055
Кроме того, мы знаем, что RGB примерно эквивалентны этим экстремальным частотам:
384,02 ТГц = 95,0,0 (hx=5F0000)
788,92 ТГц = 97,0,97 (hx=610061)
Кроме того, мы знаем, что все возможные комбинации RGB между этими точками равны = 1595
Итак, со всеми этими значениями у нас есть простое уравнение:
RGB = 95, 0, 0 = 384,02 ТГц
RGB = 96, 0, 0 = 384,02 ТГц, умноженное на (1595-й корень из 2055) = 384,19 ТГц
RGB = 97, 0, 0 = 384,19 ТГц, умноженное на (корень 1595-й степени из 2055) = 384,37 ТГц
И так и далее
Простая шкала.
Просто мое скромное мнение.
Я нашел ответ Спектра полезным, поскольку многие люди не смогут применять строгую методологию, основанную на CIE, из других ответов, но все равно хотели бы иметь готовое к использованию решение, имеющее некоторую основу в физической реальности.
С этой целью я сделал пересмотренный алгоритм, подобрав данные Спектра B-сплайном степени 2, используя длину волны в качестве параметра. Преимущество этого подхода состоит в том, что цвет 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];
}
Массив в этой функции содержит ограничивающие длины волн для каждого диапазона (в нм), а между каждой границей есть три набора коэффициентов λ², λ¹ и λ⁰ — по одному для красного, зеленого и синего.
Если вы хотите использовать другие единицы измерения, вы можете соответствующим образом преобразовать граничные значения (но измените порядок поиска, если вы используете обратные единицы измерения, например, ТГц, эВ или см-1 ) .
Вы также можете предварительно умножить все коэффициенты на 255 (и привести к int), если хотите напрямую генерировать 8-битные компоненты цвета.
Код VBA получен из Приблизительных "значений RGB для видимых длин волн" Дэна Брутона (astro@tamu.edu). Ссылка на его оригинальный код на Фортране: 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
Работоспособный пример, основанный на популярном ответе:
function spectrogram() {
var svgns = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgns, 'svg');
var defs = document.createElementNS(svgns, 'defs');
var gradient = document.createElementNS(svgns, 'linearGradient');
var rect = document.createElementNS(svgns, 'rect');
var stops = spectral_gradient( 400, 700, 3 );
for( var i = 0, length = stops.length; i < length; i++ ) {
var stop = document.createElementNS(svgns, 'stop');
stop.setAttribute('offset', stops[i].offset);
stop.setAttribute('stop-color', stops[i].color);
gradient.appendChild(stop);
}
// Apply the <lineargradient> to <defs>
gradient.id = 'Gradient';
gradient.setAttribute('x1', '0');
gradient.setAttribute('x2', '1');
gradient.setAttribute('y1', '0');
gradient.setAttribute('y2', '0');
defs.appendChild(gradient);
// Setup the <rect> element.
rect.setAttribute('fill', 'url(#Gradient)');
rect.setAttribute('width', '100%');
rect.setAttribute('height', '100%');
// Assign an id, classname, width and height
svg.setAttribute('width', '100%');
svg.setAttribute('height', '100%')
svg.setAttribute('version', '1.1');
svg.setAttribute('xmlns', svgns);
// Add the <defs> and <rect> elements to <svg>
svg.appendChild(defs);
svg.appendChild(rect);
// Add the <svg> element to <body>
document.body.appendChild(svg);
}
function spectral_gradient( wl1, wl2, steps ) {
var stops = [];
var delta = Math.abs( wl2 - wl1 );
for( var wl = wl1; wl <= wl2; wl += steps ) {
var offset = Math.round( (1 - Math.abs( wl2 - wl ) / delta) * 100 );
stops.push({
"color": wavelength2hex( wl ),
"offset": offset + "%"
});
}
return stops;
}
function wavelength2hex( l ) {
var wl = wavelength2rgb( l );
var rgb = {
"r": Math.round( wl.r * 255 ),
"g": Math.round( wl.g * 255 ),
"b": Math.round( wl.b * 255 )
};
return rgb2hex( rgb.r, rgb.g, rgb.b );
}
function wavelength2rgb( l ) {
var t;
var r = 0.0;
var g = 0.0;
var 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);
}
return {"r": r, "g": g, "b": b};
}
function rgb2hex( r, g, b ) {
return "#" + hex( r ) + hex( g ) + hex( b );
}
function hex( v ) {
return v.toString( 16 ).padStart( 2, "0" );
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="js/spectrum.js"></script>
</head>
<body onload="spectrogram();">
</body>
</html>