import numpy as np import cv2 from typing import Tuple, List # Image and Grid constants IMG_SIZE = 128 GRID_SIZE = 16 SPOT_RADIUS = 6 # Approximate radius in pixels # Colors (BGR) FACE_COLOR = (180, 220, 240) # Pale cream/tan SPOT_COLOR = (50, 50, 200) # Reddish-orange EYE_COLOR = (0, 0, 0) def extract_coords(pid: int, mode: str = "standard") -> List[Tuple[int, int]]: """Extracts four (x, y) coordinates from a 32-bit PID/EC. Standard (Little-Endian): Byte 0 (LL), 1 (LR), 2 (UL), 3 (UR) BDSP (Big-Endian): Byte 3 (LL), 2 (LR), 1 (UL), 0 (UR) """ bytes_list = [ (pid >> 0) & 0xFF, # Byte 0 (pid >> 8) & 0xFF, # Byte 1 (pid >> 16) & 0xFF, # Byte 2 (pid >> 24) & 0xFF, # Byte 3 ] if mode == "bdsp": # BDSP reads the bytes in reverse order ordered_bytes = [bytes_list[3], bytes_list[2], bytes_list[1], bytes_list[0]] else: ordered_bytes = bytes_list coords = [] for byte in ordered_bytes: x = byte & 0x0F y = (byte >> 4) & 0x0F coords.append((x, y)) return coords def generate_spinda_face(pid: int, mode: str = "standard") -> np.ndarray: """Generates a procedural Spinda face with spots based on the PID.""" # Create blank canvas (white) img = np.ones((IMG_SIZE, IMG_SIZE, 3), dtype=np.uint8) * 255 # Draw Ears cv2.circle(img, (IMG_SIZE // 2 - 40, IMG_SIZE // 2 - 50), 20, FACE_COLOR, -1) cv2.circle(img, (IMG_SIZE // 2 - 40, IMG_SIZE // 2 - 50), 20, (0, 0, 0), 2) cv2.circle(img, (IMG_SIZE // 2 + 40, IMG_SIZE // 2 - 50), 20, FACE_COLOR, -1) cv2.circle(img, (IMG_SIZE // 2 + 40, IMG_SIZE // 2 - 50), 20, (0, 0, 0), 2) # Draw main face (oval) center = (IMG_SIZE // 2, IMG_SIZE // 2) axes = (50, 60) cv2.ellipse(img, center, axes, 0, 0, 360, FACE_COLOR, -1) cv2.ellipse(img, center, axes, 0, 0, 360, (0, 0, 0), 2) # Outline # Fixed Eyes cv2.circle(img, (center[0] - 15, center[1] - 10), 4, EYE_COLOR, -1) cv2.circle(img, (center[0] + 15, center[1] - 10), 4, EYE_COLOR, -1) # Define Spot Zones (Relative to the 16x16 grid) # Heuristic mapping for a more "Pokemon-like" layout # Spot 1 (LL), Spot 2 (LR), Spot 3 (UL), Spot 4 (UR) # These offsets are designed to place spots in their respective quadrants quadrant_offsets = [ (center[0] - 45, center[1] + 5), # LL (Face) (center[0] + 5, center[1] + 5), # LR (Face) (center[0] - 45, center[1] - 55), # UL (Ear/Upper Face) (center[0] + 5, center[1] - 55), # UR (Ear/Upper Face) ] coords = extract_coords(pid, mode=mode) for i, (x, y) in enumerate(coords): offset_x, offset_y = quadrant_offsets[i] px = int(offset_x + x * 2.5) # Scale grid to quadrant py = int(offset_y + y * 2.5) cv2.circle(img, (px, py), SPOT_RADIUS, SPOT_COLOR, -1) return img