2010-08-04 45 views
32

Necesito un algoritmo o función para mapear cada longitud de onda del rango visible del espectro a sus valores RGB equivalentes. ¿Existe alguna relación estructural entre el sistema RGB y la longitud de onda de una luz? como esta imagen: alt text http://www1.appstate.edu/~kms/classes/psy3203/Color/spectrum5.gif lo siento si esto era irrelevante: -]Valores RGB del espectro visible

+6

esta pregunta, puede dar una idea. http://stackoverflow.com/questions/1472514/convert-light-frequency-to-rgb – GWW

+0

Los colores espectrales y los colores RGB tienen una relación inf-a-1, por lo que no existe una relación única. Un color RGB se asigna a infinitos colores espectrales. –

+0

mira aquí: http://stackoverflow.com/a/22149027/2521214 y sí, esto solo se puede usar para la longitud de onda -> conversión RGB, no al revés ... (la longitud de onda tiene color pero el color no es la longitud de onda ...) – Spektre

Respuesta

7

Existe una relación entre la frecuencia y lo que se conoce como Hue, pero para complicada Por razones de percepción, la gama de monitores y la calibración, lo mejor que puede lograr fuera del costoso equipo de laboratorio es una aproximación aproximada.

Consulte http://en.wikipedia.org/wiki/HSL_and_HSV para las matemáticas, y tenga en cuenta que tendrá que llegar a su mejor estimación para el mapeo de Hue ⇔ Frequency. Espero que este mapeo empírico sea cualquier cosa menos lineal.

+0

toda la matemática para Matiz -> La asignación de RGB es aproximada (lineal). Hue -> freq se puede mapear como mapas de longitud de onda de 390 a 750 nm a hue [0, 1]. freq = c/wavelength – Andrey

+7

Note mi uso de la palabra "empírico" y luego pruébelo usted mismo mientras recuerda que nuestra percepción es tricromática y distintivamente no lineal y que los monitores son un tricromático diferente y también extremadamente no lineales. Existe una industria de calibración completa construida alrededor de estos efectos. – msw

6

"valores RGB aproximados de longitudes de onda visibles" parcial

Crédito: Dan Bruton - tecnología de color

original FORTRAN @ (http://www.physics.sfasu.edu/astro/color/spectra.html)

Devolverá el espectro suave (continuo), pesado en el lado rojo.

W - longitud de onda, R, G y B - de color componentes

Haciendo caso omiso de gamma y de intensidad hojas simples:

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 
+0

Esto daría 6 valores RGB discretos. ¿Algo para los colores intermedios? – FrustratedWithFormsDesigner

+0

@FrustratedWithFormsDesigner no, es degradado. w está dentro de las expresiones, entonces son f (w) – Andrey

+0

¿No son los bits 'R = - (w - 440.)/(440. - 350.)' los valores intermedios? R, G, B son puntos flotantes aquí, no enteros. – Rup

4

Esto es más de lo que se relaciona con color profiles. Básicamente, para un dispositivo determinado (escáner, cámara, monitor, impresora, etc.), un perfil de color indica qué colores reales de luz generará un conjunto específico de entradas.

También tenga en cuenta que para la mayoría de los dispositivos reales, que sólo se ocupan de unas pocas longitudes de onda discretas de luz y colores intermedios se producen no mediante la producción de esa longitud de onda directamente, sino mediante la mezcla de cantidades variables de las dos longitudes de onda vecinos que están disponibles . Dado que percibimos el color de la misma manera, eso no es realmente un problema, pero dependiendo de por qué te importa, puede valer la pena saberlo de todos modos.

Sin un perfil de color (o información equivalente), no tiene la información necesaria para asignar el valor RGB a los colores. Un valor RGB de rojo puro normalmente se asignará al color más rojo que el dispositivo sea capaz de producir/detectar (y del mismo modo, azul puro al color azul), pero que "rojo" o "azul" puede variar (ampliamente) basado en el dispositivo.

5

Creo que las respuestas no solucionan un problema con la pregunta real.

Los valores RGB se derivan generalmente del espacio de color XYZ que es la combinación de una función de observador humano estándar, una iluminación y la potencia relativa de la muestra en cada longitud de onda en el rango de ~ 360-830.

No estoy seguro de lo que está tratando de lograr aquí, pero sería posible calcular un valor RGB relativamente "preciso" para una muestra donde cada banda discreta del espectro @ digamos 10nm estaba completamente saturada. La transformación se parece a este Spectrum ->XYZ->RGB. Visite el sitio de Bruce Lindbloom para las matemáticas. Desde el XYZ también puede calcular fácilmente hue, chroma o colorimetric valores como L*a*b*.

5

Si desea una coincidencia exacta, entonces la única solución es realizar una convolución de las funciones de coincidencia de color x, y, z con sus valores espectrales para que finalmente obtenga una representación en color XYZ (independiente del dispositivo) que pueda convertir en RGB (dependiente del dispositivo).

Esto se describe aquí: http://www.cs.rit.edu/~ncs/color/t_spectr.html

Usted puede encontrar la x, y, la función z coincidencia de color de convolución aquí: http://cvrl.ioo.ucl.ac.uk/cmfs.htm

1

Patapom lo tiene casi justo: para cada longitud de onda se calcula el CIE Valores XYZ, luego conviértalos a (digamos) sRGB usando fórmulas estándar (si tienes suerte, encontrarás el código que puedes usar para hacer esta conversión). Entonces, el paso clave es obtener los valores XYZ. Afortunadamente, para la luz de longitud de onda única esto es fácil: las funciones de coincidencia de color XYZ son simplemente tablas que enumeran los valores XYZ para una longitud de onda dada. Así que solo búscalo. Si tuvieras luz con un espectro más complicado, tal vez un cuerpo negro, entonces tendrías que promediar las respuestas XYZ por la cantidad de cada longitud de onda en la luz.

27

Recientemente descubrí que mis colores espectrales no funcionan correctamente porque se basaban en datos no lineales y desplazados. Así que investigué poco y recopilé datos y descubrí que la mayoría de las imágenes de espectro que existen son incorrectas. Además, las gamas de colores no coinciden entre sí, por lo que utilizar desde este punto de datos de espectroscopia real sólo linealizadas like this

Aquí está la salida rectificada mío:

spectral colors

  • la el primer espectro es el mejor espectro procesado que encontré, pero aún está lejos del real
  • el segundo es espectro linealizado de nuestro Sol tomado de la Tierra
  • el último es mi corriente de salida de color

A continuación se presentan los gráficos RGB:

Ésta es la fusión de ambos gráficos:

graph merge

Ahora el código:

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); } 
    } 
//-------------------------------------------------------------------------- 

Dónde

  • l es la longitud de onda en [nm] valueas utilizables son l = < 400.0 , 700.0 >
  • r,g,b están regresando componentes de color en el rango de < 0.0 , 1.0 >
+0

@tivus no, no es un error tipográfico, debería ser 5.82, ya que está en el código. de lo contrario, el extremo verde de la pendiente se desbordará a valores negativos alrededor de 639 nm creando picos de color no válidos. – Spektre

+0

¿No podría simplificarse este código si usa funciones para aproximar las curvas de cada banda de color? Una función que viene a la mente que podría ser buena es 1/sqrt (x^2 + 1), con cada banda obteniendo los cambios apropiados. – Broseph

+0

@Broseph cambiar el polinomio simple de orden bajo con 1/sqrt no suena bien para mí (velocidad, precisión) si quiere velocidad o simplicidad de código, use tabla + interpolación. – Spektre

0

código VBA se deriva de "valores RGB para longitudes de onda visibles" aproximados por Dan Bruton ([email protected]). enlace a su código original de Fortran: http://www.physics.sfasu.edu/astro/color/spectra.html programa 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 
Cuestiones relacionadas