{ "cells": [ { "cell_type": "markdown", "source": [ "# Select Klein processed file to use next" ], "metadata": { "id": "s7R3l3-pY5W7" } }, { "cell_type": "code", "source": [ "from google.colab import drive\n", "drive.mount('/content/drive')" ], "metadata": { "id": "ijzwEoboHVPR" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "OdcEXFs4oBt_", "cellView": "form" }, "outputs": [], "source": [ "import os\n", "\n", "klein_edited_zip_path = '/content/drive/MyDrive/klein_processed.zip' #@param {type:'string'}\n", "zip_path = klein_edited_zip_path\n", "\n", "if not os.path.exists(zip_path):\n", " raise FileNotFoundError(f\"โŒ Klein edited zip file not found:\\n{zip_path}\\n\\nPlease ensure the path is correct and the file exists in your Drive.\")" ] }, { "cell_type": "markdown", "source": [ "# โš™๏ธ Create 1024x1024 frames from selected klein edited set" ], "metadata": { "id": "4PjK9a8Sni3A" } }, { "cell_type": "code", "source": [ "#@title ๐Ÿ–ผ๏ธ **Image Background Processor (v1)**\n", "#@markdown ---\n", "#@markdown ## Enable Processor V1\n", "enable_processor_v1 = False #@param {type:\"boolean\"}\n", "\n", "#@title ๐Ÿ–ผ๏ธ **Image Background Processor**\n", "#(v2 - Solid #181818 Flood-Fill + Auto-Clear)\n", "#**Crop left/right empty space + Convert *any* gray background to exact #181818**\n", "#@markdown ---\n", "#**New**: Automatically clears all previous processed images on re-run\n", "#(no more mixing old files when you run again)\n", "\n", "#Run this cell (Shift + Enter)\n", "#Fill the form below\n", "#Click **Run**\n", "\n", "# ==================== FORM PARAMETERS ====================\n", "\n", "#input_zip_path = \"/content/drive/MyDrive/klein_processed.zip\" #@param {type:\"string\", placeholder:\"Paste full path to your ZIP file here\"}\n", "input_zip_path = zip_path\n", "\n", "tolerance_crop = 50 #@param {type:\"slider\", min:0, max:100, step:1, title:\"๐ŸŸฆ Crop Tolerance (higher = more aggressive cropping)\"}\n", "\n", "bg_replace_threshold = 20 #@param {type:\"slider\", min:10, max:100, step:1}\n", "\n", "force_remount = False #@param {type:\"boolean\", title:\"๐Ÿ”„ Force remount Drive (recommended)\"}\n", "\n", "#@markdown ---\n", "\n", "\n", "if enable_processor_v1:\n", " from google.colab import drive\n", " import zipfile\n", " import os\n", " import shutil # โ† NEW for clearing folders\n", " from PIL import Image\n", " from collections import deque\n", "\n", " # ========================= CONFIG =========================\n", " TARGET_GRAY = (24, 24, 24) # Exact #181818 - do not change\n", " # =======================================================\n", "\n", " print(\"๐Ÿš€ Starting image processor (Solid Background v2 + Auto-Clear)...\")\n", "\n", " # 1. Mount Google Drive\n", " drive.mount('/content/drive', force_remount=force_remount)\n", "\n", " # 2. Validate ZIP path\n", " if not input_zip_path or not os.path.exists(input_zip_path):\n", " raise FileNotFoundError(f\"โŒ ZIP file not found:\\n{input_zip_path}\\n\\nPlease paste the correct full path (e.g. /content/drive/MyDrive/my_photos.zip)\")\n", "\n", " print(f\"โœ… ZIP found: {input_zip_path}\")\n", "\n", " # 3. Define working folders\n", " extract_dir = '/content/extracted_images'\n", " processed_dir = '/content/processed_images'\n", "\n", " # === NEW: Clear previous processed & extracted images on every run ===\n", " for directory in [extract_dir, processed_dir]:\n", " if os.path.exists(directory):\n", " shutil.rmtree(directory)\n", " print(f\"๐Ÿงน Cleared old folder: {directory}\")\n", " os.makedirs(extract_dir, exist_ok=True)\n", " os.makedirs(processed_dir, exist_ok=True)\n", " print(\"โœ… Fresh folders ready\")\n", "\n", " # 4. Unzip\n", " print(\"๐Ÿ“ฆ Unzipping...\")\n", " with zipfile.ZipFile(input_zip_path, 'r') as zip_ref:\n", " zip_ref.extractall(extract_dir)\n", " print(f\"โœ… Unzipped to {extract_dir}\")\n", "\n", " # ==================== HELPER 1: Crop only left & right ====================\n", " def crop_left_right(img):\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", "\n", " width, height = img.size\n", " bg_color = img.getpixel((0, 0))\n", "\n", " left = width\n", " right = 0\n", "\n", " for x in range(width):\n", " column_is_empty = True\n", " for y in range(height):\n", " px = img.getpixel((x, y))\n", " if any(abs(a - b) > tolerance_crop for a, b in zip(px, bg_color)):\n", " column_is_empty = False\n", " break\n", " if not column_is_empty:\n", " left = min(left, x)\n", " right = max(right, x)\n", "\n", " if left >= right:\n", " return img\n", "\n", " return img.crop((left, 0, right + 1, height))\n", "\n", " # ==================== HELPER 2: FLOOD-FILL BACKGROUND FROM EDGES ====================\n", " def adjust_background(img, original_bg_color):\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", "\n", " width, height = img.size\n", " pixels = img.load()\n", " threshold = bg_replace_threshold\n", "\n", " visited = set()\n", " queue = deque()\n", " directions = [(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1] if not (dx == 0 and dy == 0)]\n", "\n", " # Seed from borders\n", " for x in range(width):\n", " for y in (0, height - 1):\n", " if (x, y) not in visited:\n", " px = pixels[x, y]\n", " dist = ((px[0] - original_bg_color[0])**2 + (px[1] - original_bg_color[1])**2 + (px[2] - original_bg_color[2])**2) ** 0.5\n", " if dist <= threshold:\n", " queue.append((x, y))\n", " visited.add((x, y))\n", " pixels[x, y] = TARGET_GRAY\n", "\n", " for y in range(height):\n", " for x in (0, width - 1):\n", " if (x, y) not in visited:\n", " px = pixels[x, y]\n", " dist = ((px[0] - original_bg_color[0])**2 + (px[1] - original_bg_color[1])**2 + (px[2] - original_bg_color[2])**2) ** 0.5\n", " if dist <= threshold:\n", " queue.append((x, y))\n", " visited.add((x, y))\n", " pixels[x, y] = TARGET_GRAY\n", "\n", " # Flood fill\n", " while queue:\n", " x, y = queue.popleft()\n", " for dx, dy in directions:\n", " nx, ny = x + dx, y + dy\n", " if 0 <= nx < width and 0 <= ny < height and (nx, ny) not in visited:\n", " px = pixels[nx, ny]\n", " dist = ((px[0] - original_bg_color[0])**2 + (px[1] - original_bg_color[1])**2 + (px[2] - original_bg_color[2])**2) ** 0.5\n", " if dist <= threshold:\n", " visited.add((nx, ny))\n", " pixels[nx, ny] = TARGET_GRAY\n", " queue.append((nx, ny))\n", "\n", " return img\n", "\n", " # 5. Process every image\n", " print(\"๐Ÿ–ผ๏ธ Processing images...\")\n", " image_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.webp')\n", "\n", " processed_count = 0\n", " for filename in os.listdir(extract_dir):\n", " if filename.lower().endswith(image_extensions):\n", " img_path = os.path.join(extract_dir, filename)\n", " try:\n", " with Image.open(img_path) as original_img:\n", " cropped = crop_left_right(original_img)\n", " orig_bg = original_img.getpixel((0, 0))\n", " processed = adjust_background(cropped, orig_bg)\n", "\n", " out_path = os.path.join(processed_dir, filename)\n", " processed.save(out_path, quality=95 if filename.lower().endswith(('.jpg', '.jpeg')) else None)\n", "\n", " processed_count += 1\n", " print(f\" โœ… {filename}\")\n", " except Exception as e:\n", " print(f\" โŒ Skipped {filename}: {e}\")\n", "\n", " print(f\"\\n๐ŸŽ‰ Processed {processed_count} images!\")\n", "\n", " # 6. Create final ZIP in Drive\n", " output_zip_name = \"PROCESSED_\" + os.path.basename(zip_path)\n", " output_zip_path = os.path.join(os.path.dirname(zip_path), output_zip_name)\n", " zip_path = output_zip_path\n", "\n", " print(f\"๐Ÿ“ฆ Creating final ZIP: {output_zip_name}\")\n", " with zipfile.ZipFile(output_zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_out:\n", " for root, _, files in os.walk(processed_dir):\n", " for file in files:\n", " file_path = os.path.join(root, file)\n", " arcname = os.path.relpath(file_path, processed_dir)\n", " zip_out.write(file_path, arcname)\n", "\n", " print(\"\\nโœ… ALL DONE! Solid #181818 background achieved.\")\n", " print(f\"๐Ÿ“ Saved to your Drive at:\\n {output_zip_path}\")\n" ], "metadata": { "id": "HN4kta-OpZ4W", "cellView": "form" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "#@title **๐Ÿ–ผ๏ธ Image Background Processor V2 (WIP)**\n", "#@markdown ---\n", "#@markdown ## Enable Processor V2\n", "enable_processor_v2 = True #@param {type:\"boolean\"}\n", "\n", "#@title **๐Ÿ–ผ๏ธ Image Background Processor V2 (WIP)**\n", "#(v2.7 - **Inverse speck removal** + Border-protected forward speck + % Margin + Solid #181818)\n", "\n", "#**Crop left/right empty space + Convert *any* gray background to exact #181818**\n", "#**New in v2.7**:\n", "# โ€ข **Inverse speck removal**: finds tiny foreground (subject-colored) specks/islands inside the background and replaces them with solid #181818\n", "# โ€ข Forward speck removal (previous) still protects any #181818 connected to the outer image edge\n", "# โ€ข Anti-aliasing is guaranteed to be the **very last step** (after both forward + inverse speck removal)\n", "# โ€ข All previous features (4-corner BG, % margin, checkboxes, distance-based enclosed speck removal) unchanged\n", "\n", "# ==================== FORM PARAMETERS ====================\n", "\n", "input_zip_path = zip_path\n", "\n", "tolerance_crop = 60 #@param {type:\"slider\", min:0, max:100, step:1, title:\"๐Ÿ”ต Crop Tolerance (higher = more aggressive cropping)\"}\n", "\n", "bg_replace_threshold = 10 #@param {type:\"slider\", min:10, max:100, step:1, title:\"๐ŸŽจ Legacy absolute threshold (kept for compatibility)\"}\n", "\n", "# โ”€โ”€ % Margin for BG color estimation โ”€โ”€\n", "bg_margin_percent = 6 #@param {type:\"slider\", min:0, max:50, step:1, title:\"% Margin for BG color estimation (wider = more tolerant to inner-loop gray variations)\"}\n", "\n", "# โ”€โ”€ Feature Checkboxes โ”€โ”€\n", "enable_robust_bg_detection = True #@param {type:\"boolean\", title:\"โœ… Use 4-corner robust BG color (best for inner loops)\"}\n", "enable_floodfill_background_adjustment = True #@param {type:\"boolean\", title:\"โœ… Enable solid #181818 background replacement\"}\n", "enable_small_speck_removal = True #@param {type:\"boolean\"}\n", "#title:\"โœ… Forward speck removal: remove tiny #181818 specks on subject\"}\n", "enable_inverse_speck_removal = True #@param {type:\"boolean\"}\n", "#title:\"โœ… Inverse speck removal: fill tiny subject specks inside background with #181818\"}\n", "enable_anti_aliasing = True #@param {type:\"boolean\", title:\"โœ… Smooth edges (Gaussian anti-aliasing)\"}\n", "\n", "anti_aliasing_strength = 6 #@param {type:\"slider\", min:1, max:40, step:1, title:\" โ†ณ Anti-aliasing Strength (pixels to blend)\"}\n", "\n", "# โ”€โ”€ Forward speck removal (enclosed only) โ”€โ”€\n", "min_floodfill_steps = 8 #@param {type:\"slider\", min:1, max:20, step:1, title:\" โ†ณ Min floodfill steps to foreground (N) for ENCLOSED BG only (outer-edge-connected BG always protected)\"}\n", "\n", "# โ”€โ”€ Inverse speck removal โ”€โ”€\n", "max_inverse_speck_size = 10 #@param {type:\"slider\", min:1, max:100, step:1, title:\" โ†ณ Max size of foreground specks to fill with #181818\"}\n", "\n", "force_remount = False #@param {type:\"boolean\", title:\"๐Ÿ”„ Force remount Drive\"}\n", "\n", "#@markdown ---\n", "\n", "\n", "if enable_processor_v2:\n", " from google.colab import drive\n", " import zipfile\n", " import os\n", " import shutil\n", " from PIL import Image, ImageFilter\n", " from collections import deque\n", "\n", " # ========================= CONFIG =========================\n", " TARGET_GRAY = (24, 24, 24) # Exact #181818\n", " # =======================================================\n", "\n", " print(\"๐Ÿš€ Starting Image Background Processor v2.7 (Forward + Inverse speck removal)...\")\n", "\n", " # 1. Mount Google Drive\n", " drive.mount('/content/drive', force_remount=force_remount)\n", "\n", " # 2. Validate ZIP path\n", " if not input_zip_path or not os.path.exists(input_zip_path):\n", " raise FileNotFoundError(f\"โŒ ZIP file not found:\\n{input_zip_path}\\n\\nPlease paste the correct full path\")\n", "\n", " print(f\"โœ… ZIP found: {input_zip_path}\")\n", "\n", " # 3. Define working folders\n", " extract_dir = '/content/extracted_images'\n", " processed_dir = '/content/processed_images'\n", "\n", " # Clear previous runs\n", " for directory in [extract_dir, processed_dir]:\n", " if os.path.exists(directory):\n", " shutil.rmtree(directory)\n", " print(f\"๏น… Cleared old folder: {directory}\")\n", " os.makedirs(extract_dir, exist_ok=True)\n", " os.makedirs(processed_dir, exist_ok=True)\n", " print(\"โœ… Fresh folders ready\")\n", "\n", " # 4. Unzip\n", " print(\"๐Ÿš€ Unzipping...\")\n", " with zipfile.ZipFile(input_zip_path, 'r') as zip_ref:\n", " zip_ref.extractall(extract_dir)\n", " print(f\"โœ… Unzipped to {extract_dir}\")\n", "\n", " # ==================== HELPER 1: Crop only left & right ====================\n", " def crop_left_right(img):\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", " width, height = img.size\n", " bg_color = img.getpixel((0, 0))\n", " left = width\n", " right = 0\n", " for x in range(width):\n", " column_is_empty = True\n", " for y in range(height):\n", " px = img.getpixel((x, y))\n", " if any(abs(a - b) > tolerance_crop for a, b in zip(px, bg_color)):\n", " column_is_empty = False\n", " break\n", " if not column_is_empty:\n", " left = min(left, x)\n", " right = max(right, x)\n", " if left >= right:\n", " return img\n", " return img.crop((left, 0, right + 1, height))\n", "\n", " # ==================== HELPER 2: FULL BACKGROUND PROCESSOR (v2.7) ====================\n", " def adjust_background(img, original_bg_color,\n", " enable_floodfill_background_adjustment,\n", " enable_small_speck_removal,\n", " enable_inverse_speck_removal,\n", " enable_anti_aliasing,\n", " anti_aliasing_strength,\n", " min_floodfill_steps,\n", " max_inverse_speck_size,\n", " bg_margin_percent):\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", "\n", " width, height = img.size\n", " pixels_access = img.load()\n", " target_gray = TARGET_GRAY\n", " directions = [(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1] if not (dx == 0 and dy == 0)]\n", "\n", " # 1. Identify foreground using % margin\n", " per_channel_margin = int(255 * (bg_margin_percent / 100.0))\n", " is_foreground = [[False for _ in range(height)] for _ in range(width)]\n", " for y in range(height):\n", " for x in range(width):\n", " px = pixels_access[(x, y)]\n", " is_bg = all(abs(px[i] - original_bg_color[i]) <= per_channel_margin for i in range(3))\n", " if not is_bg:\n", " is_foreground[x][y] = True\n", "\n", " # 2. Base image: solid #181818 + foreground\n", " base_processed_img = Image.new(\"RGB\", (width, height), target_gray)\n", " base_processed_pixels = base_processed_img.load()\n", " for y in range(height):\n", " for x in range(width):\n", " if is_foreground[x][y]:\n", " base_processed_pixels[(x, y)] = pixels_access[(x, y)]\n", "\n", " # 3. Forward speck removal (border-protected, enclosed only)\n", " if enable_floodfill_background_adjustment and enable_small_speck_removal:\n", " print(\" ๐Ÿ” Running forward speck removal (border-protected)...\")\n", " refined_img = base_processed_img.copy()\n", " refined_pixels = refined_img.load()\n", "\n", " # Mark border-connected #181818\n", " connected_to_border = [[False] * height for _ in range(width)]\n", " queue = deque()\n", " for x in range(width):\n", " for y_border in [0, height-1]:\n", " if refined_pixels[(x, y_border)] == target_gray and not connected_to_border[x][y_border]:\n", " connected_to_border[x][y_border] = True\n", " queue.append((x, y_border))\n", " for y in range(height):\n", " for x_border in [0, width-1]:\n", " if refined_pixels[(x_border, y)] == target_gray and not connected_to_border[x_border][y]:\n", " connected_to_border[x_border][y] = True\n", " queue.append((x_border, y))\n", " while queue:\n", " cx, cy = queue.popleft()\n", " for dx, dy in directions:\n", " nx, ny = cx + dx, cy + dy\n", " if 0 <= nx < width and 0 <= ny < height and not connected_to_border[nx][ny] and refined_pixels[(nx, ny)] == target_gray:\n", " connected_to_border[nx][ny] = True\n", " queue.append((nx, ny))\n", "\n", " # Distance to foreground (for enclosed BG only)\n", " distance = [[-1] * height for _ in range(width)]\n", " queue = deque()\n", " for y in range(height):\n", " for x in range(width):\n", " if is_foreground[x][y]:\n", " for dx, dy in directions:\n", " nx, ny = x + dx, y + dy\n", " if 0 <= nx < width and 0 <= ny < height and not is_foreground[nx][ny] and distance[nx][ny] == -1:\n", " distance[nx][ny] = 1\n", " queue.append((nx, ny))\n", " break\n", " while queue:\n", " cx, cy = queue.popleft()\n", " for dx, dy in directions:\n", " nx, ny = cx + dx, cy + dy\n", " if 0 <= nx < width and 0 <= ny < height and not is_foreground[nx][ny] and distance[nx][ny] == -1:\n", " distance[nx][ny] = distance[cx][cy] + 1\n", " queue.append((nx, ny))\n", "\n", " # Revert only enclosed + too-close BG pixels\n", " for y in range(height):\n", " for x in range(width):\n", " if refined_pixels[(x, y)] == target_gray:\n", " if not connected_to_border[x][y] and (distance[x][y] == -1 or distance[x][y] < min_floodfill_steps):\n", " refined_pixels[(x, y)] = pixels_access[(x, y)]\n", "\n", " base_processed_img = refined_img\n", " base_processed_pixels = base_processed_img.load()\n", "\n", " # 4. INVERSE speck removal (tiny foreground specks inside background โ†’ #181818)\n", " if enable_floodfill_background_adjustment and enable_inverse_speck_removal:\n", " print(\" ๐Ÿ” Running inverse speck removal (small FG specks โ†’ #181818)...\")\n", " refined_img = base_processed_img.copy()\n", " refined_pixels = refined_img.load()\n", " visited = [[False] * height for _ in range(width)]\n", "\n", " for y in range(height):\n", " for x in range(width):\n", " if refined_pixels[(x, y)] != target_gray and not visited[x][y]:\n", " component = []\n", " queue = deque([(x, y)])\n", " visited[x][y] = True\n", " while queue:\n", " cx, cy = queue.popleft()\n", " component.append((cx, cy))\n", " for dx, dy in directions:\n", " nx, ny = cx + dx, cy + dy\n", " if 0 <= nx < width and 0 <= ny < height and not visited[nx][ny] and refined_pixels[(nx, ny)] != target_gray:\n", " visited[nx][ny] = True\n", " queue.append((nx, ny))\n", " # Fill small foreground specks with solid #181818\n", " if len(component) < max_inverse_speck_size:\n", " for px, py in component:\n", " refined_pixels[(px, py)] = target_gray\n", "\n", " base_processed_img = refined_img\n", " base_processed_pixels = base_processed_img.load()\n", "\n", " # 5. Anti-aliasing โ€“ ALWAYS LAST (as requested)\n", " if not enable_anti_aliasing:\n", " return base_processed_img\n", "\n", " mask = Image.new(\"L\", (width, height), 0)\n", " mask_pixels = mask.load()\n", " for y in range(height):\n", " for x in range(width):\n", " if base_processed_pixels[(x, y)] != target_gray:\n", " mask_pixels[(x, y)] = 255\n", "\n", " blur_radius = anti_aliasing_strength / 2.0\n", " blurred_mask = mask.filter(ImageFilter.GaussianBlur(radius=blur_radius))\n", "\n", " solid_bg = Image.new(\"RGB\", (width, height), target_gray)\n", " final_img_with_aa = Image.composite(base_processed_img, solid_bg, blurred_mask)\n", "\n", " return final_img_with_aa\n", "\n", " # ==================== MAIN PROCESSING LOOP ====================\n", " print(\"๐Ÿš€ Processing images...\")\n", " image_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.webp')\n", "\n", " processed_count = 0\n", " for filename in os.listdir(extract_dir):\n", " if filename.lower().endswith(image_extensions):\n", " img_path = os.path.join(extract_dir, filename)\n", " try:\n", " with Image.open(img_path) as original_img:\n", " # === ROBUST BACKGROUND COLOR DETECTION ===\n", " cropped = crop_left_right(original_img)\n", " if cropped.mode != 'RGB':\n", " cropped = cropped.convert('RGB')\n", "\n", " if enable_robust_bg_detection:\n", " w, h = cropped.size\n", " samples = [\n", " cropped.getpixel((0, 0)),\n", " cropped.getpixel((w-1, 0)),\n", " cropped.getpixel((0, h-1)),\n", " cropped.getpixel((w-1, h-1))\n", " ]\n", " orig_bg = tuple(sum(c) // len(samples) for c in zip(*samples))\n", " print(f\" ๐Ÿ“ Using robust 4-corner BG color for {filename}\")\n", " else:\n", " orig_bg = cropped.getpixel((0, 0))\n", "\n", " # === PROCESS IMAGE ===\n", " if enable_floodfill_background_adjustment:\n", " processed = adjust_background(\n", " cropped,\n", " orig_bg,\n", " enable_floodfill_background_adjustment,\n", " enable_small_speck_removal,\n", " enable_inverse_speck_removal,\n", " enable_anti_aliasing,\n", " anti_aliasing_strength,\n", " min_floodfill_steps,\n", " max_inverse_speck_size,\n", " bg_margin_percent\n", " )\n", " else:\n", " processed = cropped\n", "\n", " out_path = os.path.join(processed_dir, filename)\n", " processed.save(out_path, quality=95 if filename.lower().endswith(('.jpg', '.jpeg')) else None)\n", "\n", " processed_count += 1\n", " print(f\" โœ… {filename}\")\n", "\n", " except Exception as e:\n", " print(f\" โŒ Skipped {filename}: {e}\")\n", "\n", " print(f\"\\n๐ŸŽ‰ Processed {processed_count} images!\")\n", "\n", " # 6. Create final ZIP\n", " output_zip_name = \"PROCESSED_\" + os.path.basename(input_zip_path)\n", " output_zip_path = os.path.join(os.path.dirname(input_zip_path), output_zip_name)\n", "\n", " print(f\"๐Ÿš€ Creating final ZIP: {output_zip_name}\")\n", " with zipfile.ZipFile(output_zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_out:\n", " for root, _, files in os.walk(processed_dir):\n", " for file in files:\n", " file_path = os.path.join(root, file)\n", " arcname = os.path.relpath(file_path, processed_dir)\n", " zip_out.write(file_path, arcname)\n", "\n", " print(\"\\nโœ… ALL DONE! Solid #181818 everywhere (forward + inverse specks cleaned) + smooth AA last\")\n", " print(f\"๐Ÿ“ Saved to your Drive at:\\n {output_zip_path}\")\n" ], "metadata": { "cellView": "form", "id": "tFGWg7jNv4mo" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "# โš™๏ธ Create composites" ], "metadata": { "id": "kVAe29swHo4I" } }, { "cell_type": "code", "source": [ "#@markdown Set zip file input path for making composites\n", "input_zip_path = \"/content/drive/MyDrive/PROCESSED_klein_processed.zip\" #@param {type:'string'}\n", "zip_file_path = input_zip_path" ], "metadata": { "id": "IXQKiBVrNPcE" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "93JpoQJ77NGu", "cellView": "form" }, "outputs": [], "source": [ "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# ๐ŸŽจ CLEAN ROW โ†’ PURE 1024x1024 FRAMES (NO DISTORTION)\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "#@markdown ## โš™๏ธ Main Settings\n", "num_frames = 100 #@param {type:\"slider\", min:10, max:2000, step:10}\n", "overlap_percent = 0 #@param {type:\"slider\", min:0, max:50, step:1}\n", "min_step_ratio = 0.8 #@param {type:\"slider\", min:0.5, max:1.0, step:0.05}\n", "max_step_ratio = 1.0 #@param {type:\"slider\", min:0.8, max:1.5, step:0.05}\n", "\n", "#@markdown ## ๐Ÿงฑ Border\n", "border_width = 8 #@param {type:\"slider\", min:0, max:100}\n", "\n", "#@markdown ## ๐Ÿ’พ Input / Output\n", "save_to_google_drive = True #@param {type:\"boolean\"}\n", "drive_folder_name = \"vertical_slices_output\" #@param {type:\"string\"}\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "FRAME_SIZE = 1024\n", "INNER_SIZE = FRAME_SIZE - 2 * border_width\n", "BORDER_COLOR = (24, 24, 24)\n", "\n", "import os, random, zipfile\n", "import numpy as np\n", "from PIL import Image\n", "from google.colab import drive\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Mount Drive\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "drive_mounted = False\n", "if save_to_google_drive:\n", " try:\n", " drive.mount('/content/drive', force_remount=False)\n", " drive_mounted = True\n", " drive_output_dir = os.path.join(\"/content/drive/MyDrive\", drive_folder_name)\n", " os.makedirs(drive_output_dir, exist_ok=True)\n", " print(\"Drive mounted\")\n", " except:\n", " save_to_google_drive = False\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Extract ZIP\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "extract_root = \"/content/extracted_images\"\n", "output_dir = \"/content/frames\"\n", "\n", "os.makedirs(extract_root, exist_ok=True)\n", "os.makedirs(output_dir, exist_ok=True)\n", "\n", "with zipfile.ZipFile(zip_file_path, 'r') as zf:\n", " zf.extractall(extract_root)\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Load images\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "valid_exts = ('.jpg','.jpeg','.png','.webp')\n", "all_sources = []\n", "\n", "for root, _, files in os.walk(extract_root):\n", " for f in files:\n", " if f.lower().endswith(valid_exts):\n", " all_sources.append(os.path.join(root, f))\n", "\n", "print(\"Images found:\", len(all_sources))\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Build row UNTIL enough width\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "def build_row_until_width(all_sources, target_h, overlap_ratio, required_width):\n", " canvas = Image.new(\"RGB\", (required_width, target_h))\n", " x = 0\n", "\n", " while x < required_width:\n", " src = random.choice(all_sources)\n", "\n", " try:\n", " im = Image.open(src).convert(\"RGB\")\n", " w, h = im.size\n", "\n", " scale = target_h / h\n", " new_w = int(w * scale)\n", "\n", " im = im.resize((new_w, target_h), Image.LANCZOS)\n", "\n", " # overlap\n", " if x > 0:\n", " x -= int(new_w * overlap_ratio)\n", "\n", " canvas.paste(im, (x, 0))\n", " x += new_w\n", "\n", " except:\n", " continue\n", "\n", " return canvas\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Calculate required width\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "overlap_ratio = overlap_percent / 100.0\n", "\n", "avg_step = (min_step_ratio + max_step_ratio) / 2\n", "estimated_width = int(num_frames * INNER_SIZE * avg_step * 1.2)\n", "\n", "print(\"Building row width:\", estimated_width)\n", "\n", "row_img = build_row_until_width(\n", " all_sources,\n", " INNER_SIZE,\n", " overlap_ratio,\n", " estimated_width\n", ")\n", "\n", "row_np = np.array(row_img)\n", "row_h, row_w = row_np.shape[:2]\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Generate frames (NO distortion)\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "frame_idx = 0\n", "x_cursor = 0\n", "\n", "while x_cursor + INNER_SIZE <= row_w and frame_idx < num_frames:\n", "\n", " step = random.randint(\n", " int(INNER_SIZE * min_step_ratio),\n", " int(INNER_SIZE * max_step_ratio)\n", " )\n", "\n", " crop = row_np[:, x_cursor:x_cursor + INNER_SIZE]\n", "\n", " final = Image.new(\"RGB\", (FRAME_SIZE, FRAME_SIZE), BORDER_COLOR)\n", " final.paste(Image.fromarray(crop), (border_width, border_width))\n", "\n", " fname = f\"frame_{frame_idx:04d}.jpg\"\n", " final.save(os.path.join(output_dir, fname), \"JPEG\", quality=90)\n", "\n", " frame_idx += 1\n", " x_cursor += step\n", "\n", " if frame_idx % 50 == 0:\n", " print(frame_idx, \"frames done\")\n", "\n", "print(\"Finished:\", frame_idx)\n", "\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Save ZIP\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "if save_to_google_drive and drive_mounted:\n", "\n", " zip_path = \"/content/output.zip\"\n", " drive_path = os.path.join(drive_output_dir, \"vertical_slices.zip\")\n", "\n", " with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:\n", " for f in os.listdir(output_dir):\n", " if f.endswith(\".jpg\"):\n", " zf.write(os.path.join(output_dir, f), arcname=f)\n", "\n", " !cp -f \"{zip_path}\" \"{drive_path}\"\n", "\n", " print(\"Saved to Drive:\", drive_path)" ] }, { "cell_type": "markdown", "source": [ "# Done!\n", "\n", "In the zip file /content/drive/MyDrive/vertical_slices_output/vertical_slices.zip , there you will find 100 image composites to choose for lora training\n", "\n", "//-----//" ], "metadata": { "id": "tJlvhf9xDmA7" } } ], "metadata": { "colab": { "provenance": [], "collapsed_sections": [ "6UhKYCWzPyrm", "TEupY-WNeMHu", "7eeX3_qpYpwl", "s7R3l3-pY5W7", "4PjK9a8Sni3A", "kVAe29swHo4I" ], "gpuType": "T4" }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "name": "python" }, "accelerator": "GPU" }, "nbformat": 4, "nbformat_minor": 0 }