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

    Documento y bandeja de entrada que representan buzones de correo con mailbox en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    mailbox en Python: buzones de correo

    Aprende mailbox en Python para leer, crear y migrar Maildir, mbox y MH con locking, flags, mensajes y manejo seguro

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Editor de texto que representa formato con textwrap en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    textwrap en Python: formatea textos

    Aprende textwrap en Python para dividir, rellenar, acortar, indentar y quitar sangrías con control de ancho, espacios y palabras largas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Carpeta y lupa que representan filtros de nombres con fnmatch en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    fnmatch en Python: filtra nombres de archivos

    Aprende fnmatch en Python para filtrar nombres de archivos con comodines, controlar mayúsculas, excluir patrones y distinguir glob de regex.

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Monitor con datos binarios que representa arrays numéricos compactos en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    array en Python: números compactos

    Aprende array en Python para almacenar números compactos, usar archivos binarios, byte order, memoryview y buffers seguros.

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    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: lee y escribe 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