可见光谱的RGB值

71
我需要一个算法或函数来将可见光谱的每个波长映射到对应的RGB值。 RGB系统和光的波长之间是否存在结构关系?像这张图片一样: alt text
(来源:kms at www1.appstate.edu)

如果这是无关的,我很抱歉 :-]


6
这个问题可能会给你一些启示。https://dev59.com/bnM_5IYBdhLWcg3wNwUv - GWW
光谱颜色和RGB颜色具有无限到1的关系,因此没有唯一的关系。一个RGB颜色映射到无限多个光谱颜色。 - Sebastian Mach
请查看此处:https://dev59.com/vH3aa4cB1Zd3GeqPZCXb#22149027,是的,这只能用于波长-> RGB 转换,而不能反过来...(波长有颜色,但颜色不是波长...) - Spektre
基于真实线性光谱数据,我添加了新的波长到RGB转换。 - Spektre
12个回答

1

VBA代码源自Dan Bruton(astro@tamu.edu)的“可见波长的近似RGB值”。 他原始Fortran代码的链接:http://www.physics.sfasu.edu/astro/color/spectra.html 光谱程序: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

1

一个基于流行答案的可运行示例:

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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接