colorsys en Python: RGB, HSV y HLS

Publicado el: 09/08/2026
Tempo de leitura: 5 minutos
Círculo cromático que representa conversiones RGB, HSV y HLS con colorsys en Python

Las interfaces, gráficos, herramientas de imagen y sistemas de diseño necesitan transformar colores entre representaciones diferentes. colorsys en Python ofrece conversiones bidireccionales entre RGB y los modelos HSV, HLS y YIQ usando únicamente la biblioteca estándar.

El módulo es pequeño, pero exige atención a la escala: casi todos los componentes son floats entre cero y uno. Tampoco administra perfiles ICC, gamma, espacios Lab, canales alpha ni diferencias perceptuales. Esta guía explica normalización, paletas, rotación de matiz, cambios de saturación y brillo, validación, pruebas y límites de gestión profesional del color.

El contenido complementa nuestras guías sobre Decimal, fractions, statistics, filecmp y mimetypes.

Modelos disponibles

El módulo convierte RGB a tres sistemas:

  • HSV: hue, saturation y value;
  • HLS: hue, lightness y saturation;
  • YIQ: luminancia y dos componentes de crominancia.

Las funciones inversas convierten cada modelo nuevamente a RGB.

Escala normalizada

Los componentes RGB, HSV y HLS normalmente van de cero a uno. Esto es diferente del RGB habitual de 8 bits, que usa 0 a 255.

def rgb_255_a_unitario(r, g, b):
    return r / 255, g / 255, b / 255


def rgb_unitario_a_255(r, g, b):
    return tuple(round(c * 255) for c in (r, g, b))

Normaliza en la entrada y vuelve a enteros solamente al producir la salida.

RGB a HSV

import colorsys

rgb = rgb_255_a_unitario(51, 102, 102)
h, s, v = colorsys.rgb_to_hsv(*rgb)
print(h, s, v)

Hue representa una posición en el círculo cromático, saturation la intensidad y value se basa en el componente RGB mayor.

HSV a RGB

r, g, b = colorsys.hsv_to_rgb(h, s, v)
print(rgb_unitario_a_255(r, g, b))

Una ida y vuelta puede producir pequeñas diferencias por punto flotante y redondeo a 8 bits.

Hue es circular

Cero y uno representan la misma dirección. Usa módulo al rotar.

nuevo_h = (h + 30 / 360) % 1.0

Sumar 30 grados equivale a añadir 30/360 en la escala normalizada.

Crear una paleta

def paleta(h_inicial, cantidad):
    colores = []
    for indice in range(cantidad):
        h = (h_inicial + indice / cantidad) % 1.0
        colores.append(colorsys.hsv_to_rgb(h, 0.7, 0.9))
    return colores

Distribuir matices por igual no garantiza diferencia perceptual, contraste ni accesibilidad.

Cambiar saturación

def cambiar_saturacion(rgb, factor):
    h, s, v = colorsys.rgb_to_hsv(*rgb)
    s = min(1.0, max(0.0, s * factor))
    return colorsys.hsv_to_rgb(h, s, v)

Factor cero produce gris. Los valores mayores intensifican hasta el límite. Decide si el clipping es aceptable.

Cambiar value

def cambiar_valor(rgb, delta):
    h, s, v = colorsys.rgb_to_hsv(*rgb)
    v = min(1.0, max(0.0, v + delta))
    return colorsys.hsv_to_rgb(h, s, v)

Value no es luminancia perceptual. Incrementarlo no genera la misma sensación de brillo en todos los colores.

RGB a HLS

h, l, s = colorsys.rgb_to_hls(*rgb)

La función devuelve H, L, S. Muchas herramientas web usan la sigla HSL y muestran hue, saturation, lightness. Confundir el orden produce colores incorrectos.

Cambiar lightness

def aclarar_hls(rgb, cantidad):
    h, l, s = colorsys.rgb_to_hls(*rgb)
    l = min(1.0, l + cantidad)
    return colorsys.hls_to_rgb(h, l, s)

HLS es práctico para variantes claras y oscuras, pero tampoco es perceptualmente uniforme.

HSV frente a HLS

HSV usa value y HLS usa lightness. Los modelos reorganizan RGB de manera diferente. Saturación del 100% no tiene exactamente el mismo significado visual.

HSV es común en selectores e intensidad; HLS puede resultar intuitivo para variantes claras y oscuras.

Modelo YIQ

YIQ fue utilizado por la televisión NTSC. Y representa luminancia aproximada, mientras I y Q transportan crominancia.

y, i, q = colorsys.rgb_to_yiq(*rgb)
r, g, b = colorsys.yiq_to_rgb(y, i, q)

Y permanece entre cero y uno, pero I y Q pueden ser negativos. No apliques clamp de cero a uno a esos componentes.

Colores hexadecimales

def hex_a_rgb(color):
    valor = color.lstrip("#")
    if len(valor) != 6:
        raise ValueError("usa #RRGGBB")
    return tuple(int(valor[i:i+2], 16) / 255 for i in (0, 2, 4))


def rgb_a_hex(rgb):
    r, g, b = rgb_unitario_a_255(*rgb)
    return f"#{r:02X}{g:02X}{b:02X}"

Valida el formato y define si se permiten versiones abreviadas o alpha.

Clamping seguro

def clamp(valor, minimo=0.0, maximo=1.0):
    return min(maximo, max(minimo, valor))

El clamp es útil después de cálculos controlados, no para ocultar una entrada API inválida que debería generar excepción.

Precisión flotante

Valores como 0.30000000000000004 son normales. Compara con tolerancia.

import math

assert math.isclose(restaurado, original, abs_tol=1e-9)

Mantén floats durante el cálculo y redondea una vez al producir 8 bits.

Colores acromáticos

Cuando la saturación es cero, hue no tiene significado visible. La función devuelve un número, normalmente cero.

Un selector que conserve intención puede guardar el hue anterior por separado.

Alpha no está soportado

colorsys trabaja con tres componentes. Conserva alpha fuera de la conversión.

r, g, b, a = rgba
h, s, v = colorsys.rgb_to_hsv(r, g, b)
# a se mantiene

Gamma y espacio RGB

Los valores de pantalla suelen estar codificados en sRGB. Colorsys aplica fórmulas directamente a los números; no lineariza sRGB ni convierte perfiles ICC.

Para mezcla física, iluminación, impresión o imagen científica utiliza una biblioteca con gestión de color.

Contraste y accesibilidad

Diferentes matices HSV no garantizan contraste suficiente. Calcula contraste con fórmulas de accesibilidad y prueba deficiencias visuales, temas claros y oscuros.

No comuniques estados solo mediante matiz; añade texto, iconos, formas o patrones.

Color complementario

def complementario(rgb):
    h, s, v = colorsys.rgb_to_hsv(*rgb)
    return colorsys.hsv_to_rgb((h + 0.5) % 1.0, s, v)

El opuesto matemático no siempre es la mejor elección de diseño. Úsalo como punto de partida.

Colores análogos

def analogos(rgb, grados=30):
    h, s, v = colorsys.rgb_to_hsv(*rgb)
    desplazamiento = grados / 360
    return [
        colorsys.hsv_to_rgb((h - desplazamiento) % 1, s, v),
        rgb,
        colorsys.hsv_to_rgb((h + desplazamiento) % 1, s, v),
    ]

Procesar muchas cores

El módulo realiza conversiones escalares. Los loops Python pueden ser lentos para millones de píxeles. Usa bibliotecas vectorizadas para imágenes completas.

Para paletas, temas y configuración, la sencillez estándar es excelente.

Pruebas de ida y vuelta

def test_hsv_round_trip():
    original = (0.2, 0.4, 0.7)
    hsv = colorsys.rgb_to_hsv(*original)
    restaurado = colorsys.hsv_to_rgb(*hsv)
    for a, b in zip(original, restaurado):
        assert math.isclose(a, b, abs_tol=1e-9)

Prueba negro, blanco, grises, primarios, límites y valores próximos a cero y uno.

Validar entrada

def validar_rgb(rgb):
    if len(rgb) != 3:
        raise ValueError("RGB necesita tres componentes")
    if not all(0.0 <= c <= 1.0 for c in rgb):
        raise ValueError("componente fuera del rango")

Rechaza NaN e infinito con math.isfinite().

Errores frecuentes

  • Pasar 0 a 255 sin normalizar.
  • Confundir HLS con el orden de una API HSL.
  • Limitar I y Q entre cero y uno.
  • Redondear en cada paso.
  • Perder alpha accidentalmente.
  • Usar HSV como modelo perceptual.
  • Ignorar perfiles y gamma en flujos profesionales.
  • Depender solo del matiz para accesibilidad.

Buenas prácticas

  • Normaliza en los límites de la aplicación.
  • Mantén floats durante los cálculos.
  • Usa módulo para hue.
  • Valida finitud y rango.
  • Conserva alpha por separado.
  • Mide contraste independientemente.
  • Usa bibliotecas vectorizadas para imágenes grandes.
  • Documenta modelo y escala de cada función.

Conclusión

colorsys en Python ofrece conversiones directas entre RGB, HSV, HLS y YIQ. Es ideal para paletas, temas, pequeñas herramientas gráficas y transformaciones de configuración.

Úsalo entendiendo sus límites: valores normalizados, modelos no uniformes perceptualmente y ausencia de gestión de perfiles, gamma o alpha. Consulta la documentación oficial de colorsys y las orientaciones de contraste de W3C.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Icono de configuración que representa archivos plist con plistlib en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    plistlib en Python: archivos plist

    Aprende plistlib en Python para leer y escribir archivos plist XML y binarios, validar datos y manejar fechas, bytes y

    Ler mais

    Tempo de leitura: 6 minutos
    08/08/2026
    Candado digital que representa credenciales por host con netrc en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    netrc en Python: credenciales por host

    Aprende netrc en Python para leer credenciales por host, validar permisos, tratar errores e integrar clientes de red de forma

    Ler mais

    Tempo de leitura: 7 minutos
    08/08/2026
    Mensaje digital que representa codificación quoted-printable con quopri en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    quopri en Python: quoted-printable

    Aprende quopri en Python para codificar y decodificar quoted-printable en correo, archivos e integraciones MIME de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    08/08/2026
    Icono de archivo digital que representa tipos MIME con mimetypes en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    mimetypes en Python: tipos MIME

    Aprende mimetypes en Python para identificar tipos MIME, extensiones y encodings de forma segura en cargas, descargas, correo y APIs

    Ler mais

    Tempo de leitura: 6 minutos
    08/08/2026
    Búsqueda binaria y listas ordenadas con bisect en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    bisect en Python: listas ordenadas

    Aprende bisect en Python para búsqueda binaria, inserción ordenada, duplicados, rangos y diseño seguro de listas.

    Ler mais

    Tempo de leitura: 5 minutos
    08/08/2026
    Código y archivos empaquetados con importlib.resources en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    importlib.resources en Python: guía práctica

    Aprende importlib.resources en Python para acceder a archivos empaquetados con seguridad en wheels y aplicaciones instaladas.

    Ler mais

    Tempo de leitura: 5 minutos
    07/08/2026