Значения 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 - это абсолютные цветовые пространства, которые описывают цвета с использованием абсолютной физики.

Между тем, каждое практическое цветовое пространство, которое используют люди:

  • 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) означает "белый"

Но нет такого цвета, как белый. Как вы определяете белый? Цвет солнечного света?

  • в какое время суток?
  • сколько облачного покрова?
  • на какой широте?
  • на Земле?

Некоторые люди используют белый цвет своих (ужасно оранжевых) ламп накаливания для обозначения белого. Некоторые люди используют цвет своих флуоресцентных ламп. Не существует абсолютного физического определения белого - белое в наших мозгах.

Таким образом, мы должны выбрать белый

Мы должны выбрать белый. (На самом деле вы должны выбрать белый.) И есть из чего выбрать:

Я выберу белый для вас. Тот же самый белый, который использует 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

LabLuv) - это цветовые пространства, относящиеся к некоторой белой точке. Даже если вы были вынуждены выбрать произвольную белую точку, вы все равно можете представить все возможные цвета.

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>