HSL a valores RGB


17

El objetivo principal del modelo de color RGB (Rojo Verde Azul) es la detección, representación y visualización de imágenes en sistemas electrónicos, como televisores y computadoras.

HSL (Hue Saturation Lightness) es un modelo de color alternativo, diseñado en la década de 1970 por investigadores de gráficos por computadora para alinearse más estrechamente con la forma en que la visión humana percibe los atributos de creación de color

Aquí están los artículos wiki para RGB y HSL . Es común que los programas gráficos realicen los cálculos en HSL y luego los conviertan al formato preferido para la mayoría de las pantallas: RGB.

La tarea es escribir una función / programa que tome HSL como entrada y produzca RGB.

Puede elegir su representación preferida para E / S, siempre que sea coherente entre ellas.

Por ejemplo, pueden ser una matriz / tupla con 3 elementos o un objeto con 3 propiedades con nombre h, sy l, pero voy a aceptar otras variaciones inteligentes, como la recepción de la hsl como un entero (precisión perder) y dar salida a un número entero rgb.

Se puede suponer que la entrada es segura en rango y formato, los cuales puede decidir. Sugiero encarecidamente los rangos 0-1 0-1 0-1o 0-360 0-100 0-100para hsl y / 0-1 0-1 0-1o 0-255 0-255 0-255para rgb.

Se requiere que cada respuesta especifique las dos anteriores y ponga varias variaciones en sus respuestas si está particularmente orgulloso de ellas, incluso si no tienen menos caracteres que sus otras variaciones. Pon el más pequeño encima.

Pseudo casos de prueba para 0-360 0-100 0-1000-255 0-255 0-255

h   s   l   → r   g   b

0   0   0   → 0   0   0
90  56  17  → 43  68  19
202 19  39  → 81  104 118
72  55  26  → 88  103 30

Las fórmulas para la conversión se pueden encontrar aquí :

Esta es una buena manera de visualizar la conversión:


Su rango sugerido Hde 0-360es [0,360), ¿estaría mejor escrito como 0-359?
Jonathan Allan

3
@JonathanAllan Creo que podría parecer un poco más confuso, en mi opinión, eso sugiere que 395.1 no es una entrada posible. En todo caso, usar la a-bnotación es incorrecto en sí mismo cuando se trata de valores no enteros, pero diría que está bien mantener la pregunta más legible. Si alguien más se queja, lo repensaré, así que gracias por señalarlo
Towc

Sí, de acuerdo con el punto 359.1, tal vez solo use la notación estándar de [0,360)entonces :)
Jonathan Allan

sorprendido de no ver respuestas de glsl;)
towc

Respuestas:


8

JavaScript (ES6), 98 95 94 bytes

Toma H en [0,360) y S / L en [0,1) . Salidas R , G y B como un conjunto de 3 flotadores en [0,1) .

(H,S,L)=>[5,3,1].map(i=>A(L*2)*S*([1,Y,0,0,Y,1][(i-~H)%6]-.5)+L,Y=(A=n=>n>1?2-n:n)((H/=60)%2))

Casos de prueba

Este fragmento convierte los resultados nuevamente en [0,255] .

¿Cómo?

Código de inicialización

Y = (                  // we compute Y = 1 - |(H/60) mod 2 - 1| = X / C
  A = n =>             // A = function that returns 1 - |n - 1|
    n > 1 ?            //   first compare n with 1
      2 - n            //     which allows to simplify the formula to either 2 - n
    :                  //   or
      n                //     just n
)((H /= 60) % 2)       // divide H by 60 and compute Y = A(H % 2)

Código principal

[5, 3, 1].map(i =>     // for each i in (5, 3, 1):
  A(L * 2) * S * (     //   compute (1 - |2L - 1|) * S (this is C), and multiply it by:
    [1, Y, 0, 0, Y, 1] //     either 0, 1 or Y (let's call this factor K), picked from
    [(i - ~H) % 6]     //     a cyclic sequence of period 6, using i and ~H (-6 ≤ ~H ≤ -1)
    - .5               //     minus 1/2
  )                    //   this gives: C(K - 1/2) = CK - C/2, where CK = 0, C or X
  + L                  //   we add L, leading to CK - C/2 + L = CK + m
)                      // end of map() --> returns [R, G, B]

Permutaciones de (0, C, X)

La parte ligeramente complicada es generar la permutación correcta de (0, C, X) de acuerdo con el ángulo del componente de tono. Como se muestra en la siguiente figura, cada valor de columna se selecciona de la misma secuencia de ciclo del período 6 , comenzando en diferentes compensaciones. En el código anterior, estamos usando - ~ H en lugar de solo + H porque necesitamos forzar H a un número entero. De ahí las compensaciones (5,3,1) en lugar de (0,4,2) .

                       C,X,0,0,X,C,C,X,0,0,X,C, ...
 +------> C,X,0,0,X,C  <--------->                  offset = 0, (0 - 1) mod 6 = 5
 | +----> X,C,C,X,0,0          <--------->          offset = 4, (4 - 1) mod 6 = 3
 | | +--> 0,0,X,C,C,X      <--------->              offset = 2, (2 - 1) mod 6 = 1
 | | |
(C,X,0) for   0 ≤ H <  60
(X,C,0) for  60 ≤ H < 120
(0,C,X) for 120 ≤ H < 180
(0,X,C) for 180 ≤ H < 240
(X,0,C) for 240 ≤ H < 300
(C,0,X) for 300 ≤ H < 360

¿Podría tomar Hen [0,6)y la salida de [0,1]ahorrar algo de bytes?
Jonathan Allan

@ JonathanAllan Ah, no me di cuenta de que el formato de E / S estaba suelto. ¡Gracias!
Arnauld

4

Mathematica, 155 bytes

(x~Clear~c;d=Piecewise@Table[{(P=Permutations)[P@{c,x,0}][[42,i]],(i-1)<=#<i*p},{i,6}];c=(1-Abs[2#3-1])#2;x=c(1-Abs[Mod[#/(p=60),2]-1]);m=#3-c/2;(m+d)255)&


Pruébalo en línea!



1
@totallyhuman No creo que sea correcto, ya Hueque HSB (AKA HSV) no HSL (ver las figuras 2a y 2b en la página de Wikipedia vinculada).
Jonathan Allan

1
Jenny: si es correcto, no hay razón para no publicarlo, ya que el byte cuenta con tu no incorporado a continuación.
Jonathan Allan

1
@ JonathanAllan Oh, así es. Es un poco molesto cómo RGBColorexiste pero HSLColorno existe . > _>
totalmente humano

¿Hay una versión no golfista de esto?
user76284

4

Python 2 , 32 bytes

from colorsys import*;hls_to_rgb

Pruébalo en línea!

Esta funcionalidad está realmente integrada en Python a través del hls_to_rgbinterior de la colorsysbiblioteca. El formato de las entradas de mina es un rango 0-1 de HLS (en lugar de HSL, ambas son siglas comunes para la misma cosa [aunque, HSL es más común]). Y el mío genera valores RGB en una tupla con un rango de 0 a 1.

Créditos

Gracias a Jonathan Allan por señalar que solo necesito importarlo (y luego ayudarme a reducir el conteo de bytes).


Creo que esto puede ser solo 31 bytes from colorsys import hls_to_rgbya que nos da una función que puede reutilizarse. Editar - haz que 21 como from colorsys import*.
Jonathan Allan

1
@ JonathanAllan Gracias, actualizado.
Neil

En realidad, probablemente solo import colorsyspor 15!
Jonathan Allan

@JonathanAllan Nice, actualizado nuevamente.
Neil

1
por cierto que sea, creo que esto afecta demasiado el espíritu de codegolf: /
towc

4

C ++, 228 221 bytes

-7 bytes gracias a Zacharý

#define S(o,n)r[t[int(h[0])/60*3+o]+o-2]=(n+h[2]-c/2)*255;
void C(float*h,int*r){float g=2*h[2]-1,c=(g<0?1+g:1-g)*h[1],a=int(h[0])%120/60.f-1;int t[]={2,2,2,3,1,2,3,3,0,4,2,0,4,1,1,2,3,1};S(0,c)S(1,c*(a<0?1+a:1-a))S(2,0)}

Los argumentos son ambas matrices que tienen un tamaño mínimo de 3 elementos (es decir, float hsl[3]yint rgb[3]

Bueno. Ahora, ¿cómo funciona eso? ¿Qué es ese largo conjunto?

Bueno, no es una matriz larga, es una intmatriz. Broma a un lado, la matriz indica en cuántas posiciones desplazamos CX y 0 a la derecha cuando queremos seleccionar la permutación correcta, + 2. ¿Recuerdas cómo se seleccionan R ', G' y B '?

Cómo se seleccionan R ', G' y B '

Digamos que tenemos un orden "normal" que es {C, X, 0}

Ahora, cuando se selecciona la primera permutación (es decir, {C, X, 0}), no necesita desplazarse, que es exactamente lo mismo que el desplazamiento a la derecha en 0. Por lo tanto, los primeros 3 elementos de la matriz son 0,0 y 0 0

Para la segunda permutación ({X, C, 0}), necesitamos desplazar a la derecha C en 1 y desplazar a la izquierda X en -1, por lo que el cuarto, quinto y sexto elemento de la matriz son 1, -1 y 0

Y así...

Con el caso de la tercera y cuarta permutación, necesito desplazar a la izquierda el 0 por 2, por lo que el desplazamiento a la derecha por -2. Como hay más de 2 números que son negativos, prefiero agregar 2 a cada elemento en la matriz y restar 2 en el tiempo de ejecución (por razones de golf, para tener solo números enteros en la matriz).



4

Python 2 , 119 112 bytes

def f(h,s,l):c=(1-abs(2*l-1))*s;m=l-c/2;x=c*(1-abs(h%2-1))+m;c+=m;return[c,m,x,c,m,x,m,c,x,m][7-int(h)*5%9:][:3]

Pruébalo en línea!

Toma entrada como H=[0,6[, S=[0,1], L=[0,1]


3

HTML + JavaScript (ES6), 8 + 88 = 96 bytes

f=
(h,s,l)=>(p.style.color=`hsl(${h},${s}%,${l}%)`,getComputedStyle(p).color.match(/\d+/g))
<div oninput=o.textContent=f(h.value,s.value,l.value)>H: <input type=number min=0 max=360 value=0 id=h>°<br>S: <input type=number min=0 max=100 value=0 id=s>%<br>L: <input type=number min=0 max=100 value=0 id=l>%<pre id=o>0,0,0</pre>
<p id=p>

Toma la entrada como un ángulo y dos porcentajes. Estoy puntuando el fragmento de HTML <p id=p>y la función de flecha de JavaScript. No sé qué utilizan los navegadores de redondeo, por lo que mis respuestas pueden diferir ligeramente de las suyas.


2

Swift 4, 218 bytes

Acepta valores HSL en el rango [0,1] como argumentos, y devuelve una matriz que contiene los valores RGB en el mismo rango:

import Cocoa;typealias F=CGFloat;func f(h:F,s:F,l:F)->[F]{var r=F(),g=F(),b=F(),x=s*min(1-l,l),n=2*x/max(l+x,1e-9);NSColor(hue:h,saturation:n,brightness:l+x,alpha:1).getRed(&r,green:&g,blue:&b,alpha:nil);return[r,g,b]}

La idea es convertir primero la entrada de HSL a HSB, luego usar el constructor HSB del objeto de color incorporado en Cocoa para recuperar los valores RGB.

La versión UIKit tiene exactamente la misma longitud, ya que los únicos reemplazos son:

  • CocoaUIKit
  • NSColorUIColor

Sin golf:

#if os(iOS)
    import UIKit
    typealias Color = UIColor
#elseif os(OSX)
    import Cocoa
    typealias Color = NSColor
#endif

typealias F = CGFloat

func f(h: F,s: F,l: F) -> [F] {
    var r = F(), g = F(), b = F()

    let x = s * min(1 - l, l)
    let n = 2 * x / max(l + x, 1e-9)

    let color = Color(hue: h, saturation: n, brightness: l + x, alpha: 1)
    color.getRed(&r, green: &g,blue: &b, alpha: nil)

    return [r, g, b]
}

El siguiente fragmento puede ser utilizado para la prueba, por sólo la sustitución de los valores de h, sy l:

let h: CGFloat = 0
let s: CGFloat = 0
let l: CGFloat = 0

let result = f(h: h/360, s: s/100, l: l/100).map { Int(round($0*255)) }
print(result)

Lamentablemente, no puedo proporcionar un enlace a un entorno limitado en línea, ya que todos se ejecutan en Linux, que no incluye Cocoa.


2

GLSL (GL_ES) 160 144 134 131 bytes

El tono está en el rango 0-6 (ahorra 3 bytes)
Sat, light y rgb son 0-1

vec3 f(vec3 c){return mix(c.bbb,mix(clamp(vec3(-1,2,2)-abs(c.r-vec3(3,2,4))*vec3(-1,1,1),0.,1.),vec3(c.b>.5),abs(.5-c.b)*2.),c.g);}

Pruébalo en el libro de sombreadores

Se utilizó la herramienta de selección de color en una pantalla de impresión para probar la salida correcta,
excepto un pequeño error en 202 19 39 → 81 104 118, que dio 80 104 118


1

R , 88 bytes

function(h,s,l){v=(2*l+s*(1-abs(2*l-1)))/2;col2rgb(hsv(h,ifelse(v==0,v,(2*(v-l))/v),v))}

Pruébalo en línea!

Esta función toma como entrada los valores H, S y L como valores a distancia 0-1 y genera los valores RGB como valores a distancia 0-255. Convierte la representación HSL en una representación HSV, luego usa hsv()para convertir la representación HSV en un color R (es decir, representación hexadecimal - #rrggbb), luego usa col2rgb()para convertir el color R a valores RGB.


1

Jalea ,  39  32 bytes

-1 gracias a caird coinheringaahing ( %2es solo )
-1 y / o inspiración para -4 gracias a caird coinheringaahing también!

Ḥ;Ḃ’ACש"⁵×\;0+³_®H¤⁴Ḟị336Œ?¤¤œ?

Un programa completo que toma tres argumentos de línea de comando:

  • L, H, SEn los intervalos [0,1), [0,6)y [0,1)respectivamente

que imprime una lista que da el formato RGB como

  • [R, G, B] con cada uno de los tres valores en el rango [0,1]

Nota: Htambién puede envolver como lo [0,360)haría.

Pruébalo en línea!

¿Cómo?

Ḥ;Ḃ’ACש"⁵×\;0+³_®H¤⁴Ḟị336Œ?¤¤œ? - Main link: number, L (in [0,1]); number, H (in [0,6))
Ḥ                                - double                 =     2L
  Ḃ                              - modulo by 2            =              H%2
 ;                               - concatenate            = [   2L   ,   H%2]

   ’                             - decrement              = [   2L-1 ,   H%2-1]
    A                            - absolute               = [  |2L-1|,  |H%2-1|]
     C                           - complement             = [1-|2L-1|,1-|H%2-1|]
                                 -                        = [C/S     ,C/X]
         ⁵                       - 3rd program argument   = S  (in [0,1])
        "                        - zip with:
      ×                          -   multiplication       = [C,C/X]
       ©                         -   (copy the result, C, to the register)
           \                     - cumulative reduce with:
          ×                      -   multiplication       = [C, C/X*C] = [C,X]
            ;0                   - concatenate zero       = [C,X,0]
               ³                 - 1st program argument   = L
              +                  - add (vectorises)       = [C+L,X+L,L]
                   ¤             - nilad followed by link(s) as a nilad:
                 ®               -   recall from register = C
                  H              -   halve                = C/2
                _                - subtract               = [C+L-C/2,X+L-C/2,L-C/2]
                             ¤   - nilad followed by link(s) as a nilad:
                    ⁴            -   2nd program argument = H
                     Ḟ           -   floor                = floor(H)
                            ¤    -   nilad followed by link(s) as a nilad:
                       336       -     literal 336
                          Œ?     -     Shortest permutation of natural numbers with a
                                 -     lexicographical index of 336 in all permutations
                                 -     thereof            = [3,5,6,4,2,1]
                      ị          -   index into (1-indexed & modular)
                              œ? - get that permutation of [C+L-C/2,X+L-C/2,L-C/2]
                                 - implicit print

Vaya, por supuesto. ¡Gracias!
Jonathan Allan
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.