Spaces:
Sleeping
Sleeping
File size: 3,754 Bytes
9d41e11 c34bc0e 9d41e11 c34bc0e 9d41e11 c34bc0e 9d41e11 c34bc0e 9d41e11 c34bc0e 9d41e11 c34bc0e ea8d8c2 c34bc0e ea8d8c2 9d41e11 c34bc0e ea8d8c2 9d41e11 c34bc0e 8400955 c34bc0e 9d41e11 c34bc0e ea8d8c2 9d41e11 c34bc0e 1255c3a 9d41e11 ea8d8c2 9d41e11 c34bc0e 8400955 9d41e11 8400955 9d41e11 1255c3a | 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 | import gradio as gr
from PIL import Image, ImageDraw, ImageFont
import numpy as np
# Define color ranges using RGB bounds
COLOR_RANGES = {
"7": {"name": "Red", "min": (150, 0, 0), "max": (255, 100, 100)}, # Red
"B": {"name": "Yellow", "min": (200, 200, 0), "max": (255, 255, 100)}, # Yellow
"H": {"name": "Blue", "min": (0, 0, 150), "max": (100, 100, 255)}, # Blue
"9": {"name": "Orange", "min": (200, 100, 0), "max": (255, 180, 50)}, # Orange
"A": {"name": "Yellow-Orange", "min": (200, 150, 0), "max": (255, 255, 100)}, # Light orange/yellow
"D": {"name": "Green", "min": (0, 150, 0), "max": (100, 255, 100)}, # Green
"F": {"name": "Cyan", "min": (0, 150, 150), "max": (100, 255, 255)}, # Cyan
"I": {"name": "Dark Blue", "min": (0, 0, 100), "max": (50, 50, 255)}, # Dark blue
"M": {"name": "Magenta", "min": (150, 0, 150), "max": (255, 100, 255)}, # Magenta
"L": {"name": "Purple", "min": (100, 0, 150), "max": (180, 50, 255)}, # Purple
"0": {"name": "Black", "min": (0, 0, 0), "max": (50, 50, 50)}, # Black
"W": {"name": "White", "min": (200, 200, 200), "max": (255, 255, 255)}, # White
"6": {"name": "Brown", "min": (100, 50, 0), "max": (180, 100, 50)}, # Brown
}
BLOCK_SIZE = 20
def rgb_in_range(rgb, min_rgb, max_rgb):
"""Check if RGB value is within range (inclusive)."""
r, g, b = rgb
mr, mg, mb = min_rgb
Mr, Mg, Mb = max_rgb
return mr <= r <= Mr and mg <= g <= Mg and mb <= b <= Mb
def find_nearest_color_key(rgb):
"""Find the best matching color key based on ranges."""
for key, data in COLOR_RANGES.items():
if rgb_in_range(rgb, data["min"], data["max"]):
return key
# If no match, use black as fallback
return "0"
def process_image(img):
# Convert to RGB
img = img.convert("RGB")
w, h = img.size
# Resize to max 50x50 for performance
MAX_DIM = 50
if max(w, h) > MAX_DIM:
scale = MAX_DIM / max(w, h)
img = img.resize((int(w * scale), int(h * scale)))
w, h = img.size
# Create output image
output_img = Image.new("RGB", (w * BLOCK_SIZE, h * BLOCK_SIZE), (255, 255, 255))
draw = ImageDraw.Draw(output_img)
font = ImageFont.load_default()
for y in range(h):
for x in range(w):
pixel = img.getpixel((x, y))
key = find_nearest_color_key(pixel)
color_data = COLOR_RANGES[key]
# Use average of min/max as representative color
color = (
(color_data["max"][0] + color_data["min"][0]) // 2,
(color_data["max"][1] + color_data["min"][1]) // 2,
(color_data["max"][2] + color_data["min"][2]) // 2
)
# Draw block
x0 = x * BLOCK_SIZE
y0 = y * BLOCK_SIZE
x1 = x0 + BLOCK_SIZE
y1 = y0 + BLOCK_SIZE
draw.rectangle([x0, y0, x1, y1], fill=color, outline=(0, 0, 0))
# Center text
bbox = draw.textbbox((0, 0), key, font=font)
w_text = bbox[2] - bbox[0]
h_text = bbox[3] - bbox[1]
draw.text(
(x0 + (BLOCK_SIZE - w_text) / 2, y0 + (BLOCK_SIZE - h_text) / 2),
key,
fill=(0, 0, 0),
font=font
)
return output_img
# Interface — NO EXAMPLES, just clean upload
iface = gr.Interface(
fn=process_image,
inputs=gr.Image(type="pil"),
outputs=gr.Image(type="pil"),
title="🎨 Color By Number Pixel Art",
description="Upload any image → Get a printable color-by-number pixel art with symbols. Colors are grouped by range (e.g., all reds → '7')."
)
if __name__ == "__main__":
iface.launch() |