Значения RGB видимого спектра
Мне нужен алгоритм или функция для сопоставления каждой длины волны видимого диапазона спектра с его эквивалентными значениями RGB.
Есть ли структурная связь между системой RGB и длиной волны света?
как это изображение:
![alt text]()
(источник: км на www1.appstate.edu)
извините, если это не имеет значения: -]
Ответы
Ответ 1
Существует взаимосвязь между частотой и тем, что известно как Hue, но по сложным причинам восприятия, гаммы монитора и калибровки лучшее, что вы можете достичь за пределами дорогого лабораторного оборудования, является грубым приближением.
См. http://en.wikipedia.org/wiki/HSL_and_HSV для математики, и обратите внимание, что вам придётся придумать ваше лучшее предположение для Hue ⇔ Отображение частоты, Я ожидаю, что это эмпирическое отображение будет чем угодно, но линейным.
Ответ 2
Недавно я узнал, что мои спектральные цвета не работают должным образом, потому что они основаны на нелинейных и сдвинутых данных. Поэтому я сделал небольшое исследование и сбор данных и выяснил, что большинство изображений спектра там неверны. Кроме того, диапазоны цветов не совпадают друг с другом, поэтому я использовал с этой точки только данные линеаризованной реальной спектроскопии как это
Вот выпрямленный вывод моей:
![spectral colors]()
- первый спектр - лучший отображаемый спектр, который я нашел, но все еще в стороне от реальной вещи.
- второй линеаризован Спектр нашего Солнца, взятый с Земли
- последний мой текущий цветной вывод
Ниже приведены графики RGB:
Это слияние обоих графиков:
![graph merge]()
Теперь код:
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] полезной величине a l = < 400.0 , 700.0 >
-
r,g,b
возвращают цветовые компоненты в диапазоне < 0.0 , 1.0 >
Ответ 3
Частичное "Приблизительные значения 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
Ответ 4
Я думаю, что ответы не могут решить проблему с фактическим вопросом.
Значения RGB обычно выводятся из цветового пространства XYZ, которое представляет собой комбинацию стандартной функции человеческого наблюдателя, освещенности и относительной мощности образца на каждой длине волны в диапазоне ~ 360-830.
Я не уверен, чего вы пытаетесь достичь здесь, но можно было бы вычислить относительно "точное" значение RGB для образца, где каждая дискретная полоса спектра @говорит, что 10 нм полностью насыщена. Преобразование выглядит как этот Spectrum ->XYZ->RGB
. Посмотрите на сайт Брюса Линдблома для математики. Из XYZ вы также можете легко вычислить значения hue
, chroma
или colorimetric
, такие как L*a*b*
.
Ответ 5
Если вы хотите точное совпадение, единственным решением является выполнение свертки функций согласования цвета 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
Ответ 6
Это больше всего связано с цветными профилями. В основном, для данного устройства (сканера, камеры, монитора, принтера и т.д.) Цветовой профиль сообщает, какие фактические цвета света будут производиться с помощью определенного набора входов.
Также обратите внимание, что для большинства реальных устройств вы имеете дело только с несколькими дискретными длинами волн света, а промежуточные цвета производятся не путем создания этой длины волны напрямую, а путем смешивания различных количеств двух соседних длин волн, которые доступны. Учитывая, что мы воспринимаем цвет таким же образом, это не проблема, но в зависимости от того, почему вы заботитесь, в любом случае, возможно, стоит знать.
Без цветового профиля (или эквивалентной информации) вам не хватает информации, необходимой для сопоставления значения RGB с цветами. Значение RGB чистого красного цвета обычно будет отображаться на самый красный цвет, который устройство может производить/воспринимать (а также чисто синим до самого синего цвета), но что "красноватый" или "голубой" может и будет меняться (широко) на основе устройства.
Ответ 7
Чтобы преобразовать длину волны в цвет RGB
Сначала вы обратитесь к диаграмме Дополнительного стандартного колориметрического наблюдателя CIE 1964 (архив)
https://imgur.com/a/JDatZNm
и найдите значения функции соответствия цвета CIE для нужной длины волны.
Например, я хочу получить цвет света 455 нм:
![enter image description here]()
Для нашей желаемой длины волны:
| 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 - это абсолютные цветовые пространства, которые описывают цвета с использованием абсолютной физики.
Между тем, каждое практическое цветовое пространство, которое используют люди:
зависит какая-то белая точка. Затем цвета описываются как относящиеся к этой белой точке.
Например,
- RGB белый (255,255,255) означает "белый"
- Lab white (100, 0, 0) означает "белый"
- LCH белый (100, 0, 309) означает "белый"
- HSL белый (240, 0, 100) означает "белый"
- HSV белый (240, 0, 100) означает "белый"
Но нет такого цвета, как белый. Как вы определяете белый? Цвет солнечного света?
- в какое время суток?
- сколько облачного покрова?
- на какой широте?
- на Земле?
Некоторые люди используют белый цвет своих (ужасно оранжевых) ламп накаливания для обозначения белого. Некоторые люди используют цвет своих флуоресцентных ламп. Не существует абсолютного физического определения белого - белое в наших мозгах.
Таким образом, мы должны выбрать белый
Мы должны выбрать белый. (На самом деле вы должны выбрать белый.) И есть из чего выбрать:
Я выберу белый для вас. Тот же самый белый, который использует 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.47450, -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)
- Лаборатория: (38,94259, 119,14058, -146.08508) (d65)
- RGB: (1, 0, 255) (sRGB)
И теперь мы имеем ближайшее приближение sRGB длины волны 455 нм света:
![enter image description here]()
Ответ 8
Patapom имеет почти право: для каждой длины волны вы вычисляете значения CIE XYZ, а затем конвертируете их в (скажем) sRGB с использованием стандартных формул (если вам повезет, вы найдете код, который вы можете использовать для этого преобразования), Таким образом, ключевым шагом является получение значений XYZ. К счастью, для одноволнового света это легко: функции согласования цвета XYZ - это просто таблицы, в которых перечислены значения XYZ для заданной длины волны. Так что просто посмотри. Если бы у вас был свет с более сложным спектром, может быть, с черным телом, тогда вам пришлось бы усреднять время ответа XYZ на количество каждой длины волны в свете.
Ответ 9
Код VBA получен из приблизительных "значений RGB для видимых длин волн" Дэн Брутон ([email protected]).
Ссылка на его исходный код 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
Ответ 10
Работоспособный пример, основанный на популярном ответе:
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>