Spaces:
Runtime error
Runtime error
""" | |
Encapsulate the list of hex colors and array of Lab values representations | |
of a palette (codebook) of colors. | |
Provide methods to work with color conversion and the Palette class. | |
Provide a parametrized method to generate a palette that covers the range | |
of colors. | |
""" | |
import os | |
import numpy as np | |
from skimage.color import hsv2rgb, rgb2lab | |
from skimage.io import imsave | |
from sklearn.metrics import euclidean_distances | |
from .util import rgb2hex | |
class Palette(object): | |
""" | |
Create a color palette (codebook) in the form of a 2D grid of colors, | |
as described in the parameters list below. | |
Further, the rightmost column has num_hues gradations from black to white. | |
Parameters | |
---------- | |
num_hues : int | |
number of colors with full lightness and saturation, in the middle | |
sat_range : int | |
number of rows above middle row that show | |
the same hues with decreasing saturation. | |
light_range : int | |
number of rows below middle row that show | |
the same hues with decreasing lightness. | |
Returns | |
------- | |
palette: rayleigh.Palette | |
""" | |
def __init__(self, num_hues=8, sat_range=2, light_range=2): | |
height = 1 + sat_range + (2 * light_range - 1) | |
# generate num_hues+1 hues, but don't take the last one: | |
# hues are on a circle, and we would be oversampling the origin | |
hues = np.tile(np.linspace(0, 1, num_hues + 1)[:-1], (height, 1)) | |
if num_hues == 8: | |
hues = np.tile(np.array( | |
[0., 0.10, 0.15, 0.28, 0.51, 0.58, 0.77, 0.85]), (height, 1)) | |
if num_hues == 9: | |
hues = np.tile(np.array( | |
[0., 0.10, 0.15, 0.28, 0.49, 0.54, 0.60, 0.7, 0.87]), (height, 1)) | |
if num_hues == 10: | |
hues = np.tile(np.array( | |
[0., 0.10, 0.15, 0.28, 0.49, 0.54, 0.60, 0.66, 0.76, 0.87]), (height, 1)) | |
elif num_hues == 11: | |
hues = np.tile(np.array( | |
[0.0, 0.0833, 0.166, 0.25, | |
0.333, 0.5, 0.56333, | |
0.666, 0.73, 0.803, | |
0.916]), (height, 1)) | |
sats = np.hstack(( | |
np.linspace(0, 1, sat_range + 2)[1:-1], | |
1, | |
[1] * (light_range), | |
[.4] * (light_range - 1), | |
)) | |
lights = np.hstack(( | |
[1] * sat_range, | |
1, | |
np.linspace(1, 0.2, light_range + 2)[1:-1], | |
np.linspace(1, 0.2, light_range + 2)[1:-2], | |
)) | |
sats = np.tile(np.atleast_2d(sats).T, (1, num_hues)) | |
lights = np.tile(np.atleast_2d(lights).T, (1, num_hues)) | |
colors = hsv2rgb(np.dstack((hues, sats, lights))) | |
grays = np.tile( | |
np.linspace(1, 0, height)[:, np.newaxis, np.newaxis], (1, 1, 3)) | |
self.rgb_image = np.hstack((colors, grays)) | |
# Make a nice histogram ordering of the hues and grays | |
h, w, d = colors.shape | |
color_array = colors.T.reshape((d, w * h)).T | |
h, w, d = grays.shape | |
gray_array = grays.T.reshape((d, w * h)).T | |
self.rgb_array = np.vstack((color_array, gray_array)) | |
self.lab_array = rgb2lab(self.rgb_array[None, :, :]).squeeze() | |
self.hex_list = [rgb2hex(row) for row in self.rgb_array] | |
#assert(np.all(self.rgb_array == self.rgb_array[None, :, :].squeeze())) | |
self.distances = euclidean_distances(self.lab_array, squared=True) | |
def output(self, dirname, html=False): | |
""" | |
Output an image of the palette, josn list of the hex | |
colors, and an HTML color picker for it. | |
Parameters | |
---------- | |
dirname : string | |
directory for the files to be output | |
""" | |
def get_palette_html(): | |
""" | |
Return HTML for a color picker using the given palette. | |
""" | |
html = """ | |
<style> | |
span { | |
width: 20px; | |
height: 20px; | |
margin: 2px; | |
padding: 0px; | |
display: inline-block; | |
} | |
</style> | |
""" | |
for row in self.rgb_image: | |
for rgb_color in row: | |
s = '<a id="{0}"><span style="background-color: {0}" /></a>\n' | |
html += s.format(rgb2hex(rgb_color)) | |
html += "<br />\n" | |
return html | |
imsave(os.path.join(dirname, 'palette.png'), (self.rgb_image*255).astype(np.uint8)) | |
if html: | |
with open(os.path.join(dirname, 'palette.html'), 'w') as f: | |
f.write(get_palette_html()) | |