Spaces:
Runtime error
Runtime error
File size: 4,655 Bytes
54a7220 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
"""
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())
|