python python-imaging-library color-space spectrum hsv

python - Ordenar una lista de tripletes RGB en un espectro



python-imaging-library color-space (5)

¿Presumiblemente estás clasificando por matiz (es decir, H )? Eso dará un buen resultado si S y L (o V ) son constantes, pero si varían de forma independiente, ¡obtendrá un poco de lío!

Tengo una lista de trillizos RGB, y me gustaría trazarlos de tal manera que formen algo como un espectro.

Los he convertido a HSV, que la gente parece recomendar.

from PIL import Image, ImageDraw import colorsys def make_rainbow_rgb(colors, width, height): """colors is an array of RGB tuples, with values between 0 and 255""" img = Image.new("RGBA", (width, height)) canvas = ImageDraw.Draw(img) def hsl(x): to_float = lambda x : x / 255.0 (r, g, b) = map(to_float, x) h, s, l = colorsys.rgb_to_hsv(r,g,b) h = h if 0 < h else 1 # 0 -> 1 return h, s, l rainbow = sorted(colors, key=hsl) dx = width / float(len(colors)) x = 0 y = height / 2.0 for rgb in rainbow: canvas.line((x, y, x + dx, y), width=height, fill=rgb) x += dx img.show()

Sin embargo, el resultado no se parece mucho a un buen espectro de arco iris. Sospecho que necesito convertir a un espacio de color diferente o manejar el triplete HSL de manera diferente.

¿Alguien sabe qué debo hacer para que estos datos se vean como un arco iris?

Actualizar:

Estaba jugando con las curvas de Hilbert y revisé este problema. La clasificación de los valores RGB (los mismos colores en ambas imágenes) por su posición a lo largo de una curva de Hilbert produce un resultado interesante (si aún no es del todo satisfactorio):


Aquí hay algunos arco iris que hice recientemente, puede modificar la idea para hacer lo que quiera

from PIL import Image, ImageDraw # pip install pillow import numpy as np from matplotlib import pyplot as plt strip_h, strip_w = 100, 720 strip = 255*np.ones((strip_h,strip_w,3), dtype=''uint8'') image_val = Image.fromarray(strip) image_sat = Image.fromarray(strip) draw0 = ImageDraw.Draw(image_val) draw1 = ImageDraw.Draw(image_sat) for y in range(strip_h): for x in range(strip_w): draw0.point([x, y], fill=''hsl(%d,%d%%,%d%%)''%(x%360,y,50)) draw1.point([x, y], fill=''hsl(%d,%d%%,%d%%)''%(x%360,100,y)) plt.subplot(2,1,1) plt.imshow(image_val) plt.subplot(2,1,2) plt.imshow(image_sat) plt.show()


Estás intentando convertir un espacio tridimensional en un espacio unidimensional. No hay garantía de que puedas hacer un arcoíris agradable, como dice Oli.

Lo que puede hacer es agrupar los colores en unas pocas categorías diferentes en función de la saturación y el valor / luminosidad, y luego ordenar dentro de las categorías, para obtener varios gradientes independientes. Por ejemplo, los colores de alta saturación primero para el arco iris clásico, luego los colores de alto valor de saturación media (pasteles), y luego la saturación baja (grises).

Alternativamente, si todo lo que te importa es el arco iris, conviértelo a hsl, luego slam saturation a 1.0 y value a 0.5, conviértelo de nuevo a rgb y procesa eso en lugar del color original.


Esto parece incorrecto.

canvas.line((x, y, x + dx, y), width=height, fill=rgb)

Prueba esto.

canvas.rectangle([(x, y), (x+dx, y+height)], fill=rgb)


Un método interesante para reducir la dimensionalidad de los espacios de color utiliza la curva de Hilbert que llena el espacio . Dos artículos relevantes son:

  • Reducción de la dimensión del espacio de color: descripción general de varios métodos para reducir la dimensionalidad de los datos de color
  • Retrato de la curva de Hilbert : artículo detallado sobre las curvas de Hilbert y su aplicación a la reducción de la dimensionalidad del espacio de color.

Ambos consideran la reducción 3d -> 2d, pero el paso intermedio de la asignación a la curva 1d podría ser una solución a su problema.