Вопрос:
Мне нужен алгоритм или функция для сопоставления каждой длины волны видимого диапазона спектра с его эквивалентными значениями RGB.
Есть ли структурная связь между системой RGB и длиной волны света?
как это изображение:
(источник: км на www1.appstate.edu)
извините, если это не имеет значения: -]
Лучший ответ:
Существует взаимосвязь между частотой и тем, что известно как Hue, но по сложным причинам восприятия, гаммы монитора и калибровки лучшее, что вы можете достичь за пределами дорогого лабораторного оборудования, является грубым приближением.
См. http://en.wikipedia.org/wiki/HSL_and_HSV для математики, и обратите внимание, что вам придётся придумать ваше лучшее предположение для Hue ⇔ Отображение частоты, Я ожидаю, что это эмпирическое отображение будет чем угодно, но линейным.
Ответ №1Недавно я узнал, что мои спектральные цвета не работают должным образом, потому что они основаны на нелинейных и сдвинутых данных. Поэтому я сделал небольшое исследование и сбор данных и выяснил, что большинство изображений спектра там неверны. Кроме того, диапазоны цветов не совпадают друг с другом, поэтому я использовал с этой точки только данные линеаризованной реальной спектроскопии как это
Вот выпрямленный вывод моей:
- первый спектр – лучший отображаемый спектр, который я нашел, но все еще в стороне от реальной вещи.
- второй линеаризован Спектр нашего Солнца, взятый с Земли
- последний мой текущий цветной вывод
Ниже приведены графики 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] полезной величине a l = < 400.0 , 700.0 >
- r,g,b возвращают цветовые компоненты в диапазоне < 0.0 , 1.0 >
Ответ №2
Частичное “Приблизительные значения 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 Ответ №3
Я думаю, что ответы не могут решить проблему с фактическим вопросом.
Значения RGB обычно выводятся из цветового пространства XYZ, которое представляет собой комбинацию стандартной функции человеческого наблюдателя, освещенности и относительной мощности образца на каждой длине волны в диапазоне ~ 360-830.
Я не уверен, чего вы пытаетесь достичь здесь, но можно было бы вычислить относительно “точное” значение RGB для образца, где каждая дискретная полоса спектра @говорит, что 10 нм полностью насыщена. Преобразование выглядит как этот Spectrum ->XYZ->RGB. Посмотрите на сайт Брюса Линдблома для математики. Из XYZ вы также можете легко вычислить значения hue, chroma или colorimetric, такие как L*a*b*.
Ответ №4
Если вы хотите точное совпадение, единственным решением является выполнение свертки функций согласования цвета 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
Ответ №5
Это больше всего связано с цветными профилями. В основном, для данного устройства (сканера, камеры, монитора, принтера и т.д.) Цветовой профиль сообщает, какие фактические цвета света будут производиться с помощью определенного набора входов.
Также обратите внимание, что для большинства реальных устройств вы имеете дело только с несколькими дискретными длинами волн света, а промежуточные цвета производятся не путем создания этой длины волны напрямую, а путем смешивания различных количеств двух соседних длин волн, которые доступны. Учитывая, что мы воспринимаем цвет таким же образом, это не проблема, но в зависимости от того, почему вы заботитесь, в любом случае, возможно, стоит знать.
Без цветового профиля (или эквивалентной информации) вам не хватает информации, необходимой для сопоставления значения RGB с цветами. Значение RGB чистого красного цвета обычно будет отображаться на самый красный цвет, который устройство может производить/воспринимать (а также чисто синим до самого синего цвета), но что “красноватый” или “голубой” может и будет меняться (широко) на основе устройства.
Ответ №6Содержание
- Чтобы преобразовать длину волны в цвет RGB
- Как конвертировать XYZ в RGB?
- Таким образом, мы должны выбрать белый
- Но вы хотите RGB
- Финальный толчок
Чтобы преобразовать длину волны в цвет 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 – это абсолютные цветовые пространства, которые описывают цвета с использованием абсолютной физики.
Между тем, каждое практическое цветовое пространство, которое используют люди:
- Lab
- 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) означает “белый”
Но нет такого цвета, как белый. Как вы определяете белый? Цвет солнечного света?
- в какое время суток?
- сколько облачного покрова?
- на какой широте?
- на Земле?
Некоторые люди используют белый цвет своих (ужасно оранжевых) ламп накаливания для обозначения белого. Некоторые люди используют цвет своих флуоресцентных ламп. Не существует абсолютного физического определения белого – белое в наших мозгах.
Таким образом, мы должны выбрать белый
Мы должны выбрать белый. (На самом деле вы должны выбрать белый.) И есть из чего выбрать:
- Осветительный прибор A: что-то вроде вольфрамовой лампы
- Источник света B & C: попытка подделать солнечный свет в полдень, установив фильтры перед лампой накаливания
- Источник света D50: естественный дневной свет 5000К
- Источник света D55: естественный дневной свет 5500K
- Источник света 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.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 нм света:
Ответ №7
Patapom имеет почти право: для каждой длины волны вы вычисляете значения CIE XYZ, а затем конвертируете их в (скажем) sRGB с использованием стандартных формул (если вам повезет, вы найдете код, который вы можете использовать для этого преобразования), Таким образом, ключевым шагом является получение значений XYZ. К счастью, для одноволнового света это легко: функции согласования цвета XYZ – это просто таблицы, в которых перечислены значения XYZ для заданной длины волны. Так что просто посмотри. Если бы у вас был свет с более сложным спектром, может быть, с черным телом, тогда вам пришлось бы усреднять время ответа XYZ на количество каждой длины волны в свете.
Ответ №8
Код VBA получен из приблизительных “значений RGB для видимых длин волн” Дэн Брутон (astro@tamu.edu).
Ссылка на его исходный код Fortran:
Программа 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 Ответ №9
Работоспособный пример, основанный на популярном ответе:
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>