Thumbnail.

Animal Patterns v1

Description

I asked Chatgpt to create mathematical approximations of 42 notable animal patterns, and put them in 24-bit rgb. (This is another thing I’ve wanted to do for a long time, but never got around to.)

The Python code you can run for yourself:

import numpy as np
from PIL import Image, ImageDraw, ImageFont
import colorsys
import os

# --- CONFIG ---
IMAGE_SIZE = 4096
BLOCK_SIZE = 1024
NUM_COLORS = 256**3
BLOCKS_PER_SIDE = 4
FONT_SIZE = 48
LINE_SPACING = 8
LABEL_MARGIN = 16

# --- Load bold and italic fonts ---
def load_fonts():
    bold_candidates = [
        "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
        "/System/Library/Fonts/Supplemental/Arial Bold.ttf",
        "C:/Windows/Fonts/arialbd.ttf",
        "./DejaVuSans-Bold.ttf",
    ]
    italic_candidates = [
        "/usr/share/fonts/truetype/dejavu/DejaVuSans-Oblique.ttf",
        "/System/Library/Fonts/Supplemental/Arial Italic.ttf",
        "C:/Windows/Fonts/ariali.ttf",
        "./DejaVuSans-Oblique.ttf",
    ]
    def try_paths(paths):
        for path in paths:
            if os.path.exists(path):
                return ImageFont.truetype(path, FONT_SIZE)
        return ImageFont.load_default()
    return try_paths(bold_candidates), try_paths(italic_candidates)

# --- Labels ---
animal_labels = [
    ("Tiger", "Panthera tigris"),
    ("Zebra", "Equus quagga"),
    ("Giraffe", "Giraffa camelopardalis"),
    ("Leopard", "Panthera pardus"),
    ("Cheetah", "Acinonyx jubatus"),
    ("Jaguar", "Panthera onca"),
    ("Okapi", "Okapia johnstoni"),
    ("Lemur", "Lemur catta"),
    ("Boa", "Boa constrictor"),
    ("Python", "Python regius"),
    ("Monitor", "Varanus niloticus"),
    ("Flounder", "Bothus lunatus"),
    ("Clownfish", "Amphiprion ocellaris"),
    ("Mandarinfish", "Synchiropus splendidus"),
    ("Dart Frog", "Dendrobates tinctorius"),
    ("Boxfish", "Ostracion cubicus"),
]

# --- Color generation ---
def generate_rgb_colors():
    r = np.arange(256, dtype=np.uint8)
    g = np.arange(256, dtype=np.uint8)
    b = np.arange(256, dtype=np.uint8)
    return np.array(np.meshgrid(r, g, b)).T.reshape(-1, 3)

def sort_by_brightness(colors):
    brightness = np.dot(colors, [0.2126, 0.7152, 0.0722])
    return colors[np.argsort(brightness)]

def block_coords(index):
    row = index // BLOCKS_PER_SIDE
    col = index % BLOCKS_PER_SIDE
    return row * BLOCK_SIZE, col * BLOCK_SIZE

def safe_tile(base, tile_size, h, w):
    tiled = np.kron(base, np.ones((tile_size, tile_size)))
    return tiled[:h, :w]

# --- Pattern functions ---
def tiger_pattern(h, w): y, x = np.meshgrid(np.linspace(0, 4*np.pi, h), np.linspace(0, 2*np.pi, w), indexing='ij'); return (0.5 * (np.sin(5*x + np.sin(3*y)) + 1)) ** 3
def zebra_pattern(h, w): x = np.linspace(0, 20*np.pi, w); stripes = np.sin(x); return np.tile((stripes + 1) / 2, (h, 1))
def giraffe_pattern(h, w): y, x = np.indices((h, w)); return (((x//80 + y//80) % 2) * 0.5 + 0.25)
def leopard_pattern(h, w): np.random.seed(1); base = np.random.rand(h//40 + 1, w//40 + 1); return safe_tile(base, 40, h, w)
def cheetah_pattern(h, w): np.random.seed(2); base = np.random.rand(h//20 + 1, w//20 + 1); return safe_tile(base, 20, h, w)
def jaguar_pattern(h, w): y, x = np.ogrid[:h, :w]; return ((np.sin(x/40) * np.cos(y/40)) ** 2)
def okapi_pattern(h, w): x = np.linspace(0, 10*np.pi, w); stripes = (np.sin(x)**8); return np.tile(stripes, (h, 1))
def lemur_pattern(h, w): y = np.linspace(0, 6*np.pi, h); rings = (np.sin(y)**6); return np.tile(rings[:, None], (1, w))
def boa_pattern(h, w): y, x = np.ogrid[:h, :w]; return ((np.sin(x/50) + np.cos(y/50))**2) % 1
def python_pattern(h, w): y, x = np.ogrid[:h, :w]; return (((np.sin(x/30) * np.cos(y/30)) + 1) / 2)
def nile_monitor_pattern(h, w): y, x = np.indices((h, w)); return (((x//40 + y//40) % 3) / 2.0)
def flounder_pattern(h, w): y, x = np.indices((h, w)); return ((np.sin(x/60) * np.sin(y/60))**2)
def clownfish_pattern(h, w): y = np.linspace(0, 4*np.pi, h); stripes = ((np.sin(y)**6) * 0.7 + 0.3); return np.tile(stripes[:, None], (1, w))
def mandarinfish_pattern(h, w): y, x = np.ogrid[:h, :w]; return (np.sin(x/20) + np.sin(y/30)) % 1
def dartfrog_pattern(h, w): y, x = np.indices((h, w)); return (np.sin(np.hypot(x - w//2, y - h//2)/20)**2)
def boxfish_pattern(h, w): y, x = np.indices((h, w)); return (((x//30 + y//30) % 2) * 0.5 + 0.25)

pattern_functions = [
    tiger_pattern, zebra_pattern, giraffe_pattern, leopard_pattern,
    cheetah_pattern, jaguar_pattern, okapi_pattern, lemur_pattern,
    boa_pattern, python_pattern, nile_monitor_pattern, flounder_pattern,
    clownfish_pattern, mandarinfish_pattern, dartfrog_pattern, boxfish_pattern
]

# --- Label mask (2 lines per block) ---
def render_labels_and_reserve_coords(font_bold, font_italic):
    img = Image.new("L", (IMAGE_SIZE, IMAGE_SIZE), 0)
    draw = ImageDraw.Draw(img)
    for i, (common, latin) in enumerate(animal_labels):
        row, col = block_coords(i)
        x = col + LABEL_MARGIN
        y = row + LABEL_MARGIN
        draw.text((x, y), common, fill=255, font=font_bold)
        draw.text((x, y + FONT_SIZE + LINE_SPACING), latin, fill=255, font=font_italic)
    return np.array(img) > 0

# --- MAIN ---
def generate_image_with_labels():
    font_bold, font_italic = load_fonts()
    all_colors = generate_rgb_colors()
    sorted_colors = sort_by_brightness(all_colors)

    label_mask = render_labels_and_reserve_coords(font_bold, font_italic)
    label_indices = np.where(label_mask.flatten())[0]
    image_indices = np.where(~label_mask.flatten())[0]

    assert len(label_indices) + len(image_indices) == NUM_COLORS

    canvas = np.zeros((IMAGE_SIZE * IMAGE_SIZE, 3), dtype=np.uint8)
    canvas[image_indices] = sorted_colors[len(label_indices):]
    canvas[label_indices] = sorted_colors[:len(label_indices)]

    for i in range(16):
        print(f"Rendering block {i + 1}/16...")
        row, col = block_coords(i)
        pattern = pattern_functions[i](BLOCK_SIZE, BLOCK_SIZE)
        block_mask = label_mask[row:row + BLOCK_SIZE, col:col + BLOCK_SIZE]
        paintable = ~block_mask.flatten()

        y_indices = np.arange(BLOCK_SIZE)[:, None] + row
        x_indices = np.arange(BLOCK_SIZE)[None, :] + col
        yy, xx = np.meshgrid(y_indices, x_indices, indexing='ij')
        flat_coords = yy.flatten() * IMAGE_SIZE + xx.flatten()

        pattern_vals = pattern.flatten()[paintable]
        color_chunk = canvas[flat_coords[paintable]]
        sorted_idx = np.argsort(pattern_vals)
        canvas[flat_coords[paintable]] = color_chunk[np.argsort(sorted_idx)]

    return canvas.reshape((IMAGE_SIZE, IMAGE_SIZE, 3))

# --- EXECUTE ---
if __name__ == "__main__":
    img = generate_image_with_labels()
    Image.fromarray(img).save("rgb_animal_pattern_grid_with_latin_labels.png")

Author

ACJ
30 entries

Stats

Date
Colors16,777,216
Pixels16,777,216
Dimensions4,096 × 4,096
Bytes48,821,319