Michael Pilosov, PhD
9 months ago
3 changed files with 191 additions and 10 deletions
@ -0,0 +1,170 @@ |
|||
import argparse |
|||
from pathlib import Path |
|||
|
|||
import matplotlib.colors as mcolors |
|||
import matplotlib.patches as patches |
|||
import matplotlib.pyplot as plt |
|||
import numpy as np |
|||
from hilbertcurve.hilbertcurve import HilbertCurve |
|||
|
|||
from check import plot_preds |
|||
|
|||
# Extract XKCD colors |
|||
colors = list(mcolors.XKCD_COLORS.keys()) |
|||
rgb_values = [mcolors.to_rgb(mcolors.XKCD_COLORS[color]) for color in colors] |
|||
|
|||
# Parse command-line arguments |
|||
parser = argparse.ArgumentParser() |
|||
parser.add_argument("-s", "--sort-by", type=str, default="hsv", help="kind of sorting") |
|||
parser.add_argument("--seed", type=int, default=21, help="seed for UMAP") |
|||
parser.add_argument("--dpi", type=int, default=300, help="dpi for saving") |
|||
parser.add_argument("--size", type=float, default=6.0, help="size of figure") |
|||
parser.add_argument( |
|||
"--fontsize", |
|||
type=float, |
|||
default=0, |
|||
help="fontsize of annotation (default: 0 = None)", |
|||
) |
|||
parser.add_argument( |
|||
"--radius", type=float, default=1 / 2, help="inner radius of circle" |
|||
) |
|||
args = parser.parse_args() |
|||
KIND = args.sort_by |
|||
SEED = args.seed |
|||
DPI = args.dpi |
|||
SIZE = args.size |
|||
FONTSIZE = args.fontsize |
|||
INNER_RADIUS = args.radius |
|||
DIR = "/teamspace/studios/colors/umap" |
|||
|
|||
|
|||
prefix = "" |
|||
if KIND == "umap": |
|||
prefix = f"{SEED:04d}_" |
|||
FDIR = f"{DIR}/{KIND}" |
|||
Path(FDIR).mkdir(exist_ok=True, parents=True) |
|||
fname = f"{FDIR}/{prefix}sorted_colors_circle.png" |
|||
|
|||
|
|||
|
|||
if KIND in ("lex", "alpha", "abc"): |
|||
preds = np.array(colors) |
|||
|
|||
elif KIND == "umap": |
|||
# from umap import UMAP |
|||
from cuml import UMAP |
|||
|
|||
# Use UMAP to create a 1D representation |
|||
reducer = UMAP( |
|||
n_components=1, |
|||
n_neighbors=250, |
|||
min_dist=1e-2, |
|||
metric="euclidean", |
|||
random_state=SEED, |
|||
negative_sample_rate=2, |
|||
) |
|||
embedding = reducer.fit_transform(np.array(rgb_values)) |
|||
|
|||
# Sort colors by the 1D representation |
|||
preds = embedding[:, 0] |
|||
del reducer, embedding |
|||
|
|||
elif KIND in ("cielab", "lab", "ciede2000"): |
|||
from skimage.color import deltaE_ciede2000, rgb2lab |
|||
|
|||
# CIELAB |
|||
# Convert RGB values to CIELAB |
|||
lab_values = rgb2lab([rgb_values]) |
|||
|
|||
# Reference color for sorting (can be the first color or any other reference point) |
|||
reference_color = lab_values[0] |
|||
|
|||
# Compute CIEDE2000 distances of all colors to the reference color |
|||
distances = [deltaE_ciede2000(reference_color, color) for color in lab_values] |
|||
|
|||
# Sort colors by their CIEDE2000 distance to the reference color |
|||
# preds = distances).flatten() # awful |
|||
lab_values_flat = lab_values.reshape(-1, 3) |
|||
# Sort colors based on the L* value in the CIELAB space |
|||
# 0 corresponds to the L* channel |
|||
preds = lab_values_flat[:, 0] |
|||
|
|||
elif KIND == "hsv": |
|||
from matplotlib.colors import rgb_to_hsv |
|||
|
|||
# Convert RGB values to HSV |
|||
hsv_values = np.array([rgb_to_hsv(np.array(rgb)) for rgb in rgb_values]) |
|||
|
|||
# Sort colors based on the hue value |
|||
# 0 corresponds to the hue component |
|||
preds = hsv_values[:, 0] |
|||
else: |
|||
raise ValueError(f"Unknown kind: {KIND}") |
|||
|
|||
sorted_indices = np.argsort(preds) |
|||
|
|||
# Save the sorted indices to disk |
|||
# if (KIND == "umap") or (KIND != "umap"): |
|||
PDIR = f"scripts/{KIND}" |
|||
Path(PDIR).mkdir(parents=True, exist_ok=True) |
|||
file_path = f"{PDIR}/{SEED:06d}.npy" |
|||
np.save(file_path, preds.ravel()) |
|||
print(f"Predictions saved to {file_path}") |
|||
|
|||
# Sort colors by the 1D representation |
|||
sorted_colors = [colors[i] for i in sorted_indices] |
|||
|
|||
plot_preds( |
|||
preds, |
|||
np.array(rgb_values), |
|||
fname, |
|||
roll=False, |
|||
dpi=DPI, |
|||
inner_radius=INNER_RADIUS, |
|||
figsize=(SIZE, SIZE), |
|||
fsize=FONTSIZE, |
|||
label=f"{KIND.upper()}", |
|||
) |
|||
print(f"saved {fname}") |
|||
|
|||
HILBERT = False |
|||
|
|||
if HILBERT: |
|||
# Create Hilbert curve |
|||
# We'll set the order such that the number of positions is greater than or equal to the number of colors |
|||
hilbert_order = int(np.ceil(0.5 * np.log2(len(sorted_colors)))) |
|||
hilbert_curve = HilbertCurve(hilbert_order, 2) |
|||
|
|||
# Create an image for visualization |
|||
image_size = 2**hilbert_order |
|||
image = np.ones((image_size, image_size, 3)) |
|||
|
|||
for i, color in enumerate(sorted_colors): |
|||
# Convert linear index to Hilbert coordinates |
|||
coords = hilbert_curve.point_from_distance(i) |
|||
image[coords[1], coords[0]] = mcolors.to_rgb(color) |
|||
|
|||
# annotation in upper right |
|||
# Display the image |
|||
fig, ax = plt.subplots(1, 1, figsize=(SIZE, SIZE)) |
|||
ax.imshow(image) |
|||
ax.annotate( |
|||
f"{KIND.upper()}", |
|||
(1.0, 1.0), |
|||
ha="right", |
|||
va="top", |
|||
size=FONTSIZE, |
|||
xycoords="axes fraction", |
|||
) |
|||
ax.axis("off") |
|||
ax.set_aspect("equal") |
|||
fig.tight_layout() |
|||
fname = f"{DIR}/{prefix}{KIND}_sorted_colors_hilbert.png" |
|||
fig.savefig( |
|||
fname, |
|||
dpi=DPI, |
|||
transparent=True, |
|||
# bbox_inches="tight", |
|||
# pad_inches=0 |
|||
) |
|||
print(f"Saved {fname}") |
Loading…
Reference in new issue