✅ Complete Faza 1&2 Status + Batch Visual Cleanup
- Created comprehensive FAZA1_GENERATION_STATUS.md with 10 categories tracking 176 tasks
- Auto-sync system for real-time progress updates
- Batch cleanup: 1411 images scanned across references/, assets/, style_test_samples/
- 33 backgrounds removed total (24 previous + 9 new)
- Updated ROADMAP.md: Visual Cleanup ✅ Complete
- Script: batch_cleanup_all_assets.py for automated processing
- Critical path identified: 17 tasks (60-80h) to Kickstarter Demo ready
This commit is contained in:
182
scripts/batch_cleanup_all_assets.py
Normal file
182
scripts/batch_cleanup_all_assets.py
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
BATCH VISUAL ASSET CLEANUP
|
||||
Removes backgrounds from ALL image assets in the project.
|
||||
Processes: /references/, /assets/, /style_test_samples/
|
||||
|
||||
Features:
|
||||
- Multi-folder scanning
|
||||
- Chroma keying (green #00FF00 removal)
|
||||
- Smart detection of already transparent images
|
||||
- Progress tracking
|
||||
- Automatic _nobg.png generation
|
||||
"""
|
||||
|
||||
import os
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
|
||||
# Configuration
|
||||
SEARCH_FOLDERS = [
|
||||
'references',
|
||||
'assets/images',
|
||||
'assets/bugs',
|
||||
'assets/tools',
|
||||
'assets/crops',
|
||||
'assets/buildings',
|
||||
'assets/characters',
|
||||
'assets/enemies',
|
||||
'assets/npcs',
|
||||
'style_test_samples'
|
||||
]
|
||||
|
||||
GREEN_KEY = (0, 255, 0) # #00FF00
|
||||
TOLERANCE = 30 # Color variance tolerance
|
||||
|
||||
def has_transparency(image):
|
||||
"""Check if image already has transparent pixels"""
|
||||
if image.mode != 'RGBA':
|
||||
return False
|
||||
|
||||
alpha = np.array(image)[:, :, 3]
|
||||
return np.any(alpha < 255)
|
||||
|
||||
def remove_green_background(image_path, output_path):
|
||||
"""Remove green chroma key background and save as transparent PNG"""
|
||||
try:
|
||||
img = Image.open(image_path).convert('RGBA')
|
||||
data = np.array(img)
|
||||
|
||||
# Check if already transparent
|
||||
if has_transparency(img):
|
||||
print(f" ⏭️ Already transparent: {os.path.basename(image_path)}")
|
||||
return False
|
||||
|
||||
# Extract RGB channels
|
||||
red, green, blue, alpha = data[:, :, 0], data[:, :, 1], data[:, :, 2], data[:, :, 3]
|
||||
|
||||
# Create mask for green pixels (with tolerance)
|
||||
mask = (
|
||||
(np.abs(red.astype(int) - GREEN_KEY[0]) <= TOLERANCE) &
|
||||
(np.abs(green.astype(int) - GREEN_KEY[1]) <= TOLERANCE) &
|
||||
(np.abs(blue.astype(int) - GREEN_KEY[2]) <= TOLERANCE)
|
||||
)
|
||||
|
||||
# Check if green background exists
|
||||
green_pixel_count = np.sum(mask)
|
||||
if green_pixel_count == 0:
|
||||
print(f" ℹ️ No green background: {os.path.basename(image_path)}")
|
||||
return False
|
||||
|
||||
# Set alpha to 0 for green pixels
|
||||
data[:, :, 3] = np.where(mask, 0, 255)
|
||||
|
||||
# Save as transparent PNG
|
||||
result = Image.fromarray(data, 'RGBA')
|
||||
result.save(output_path, 'PNG')
|
||||
|
||||
percentage = (green_pixel_count / (data.shape[0] * data.shape[1])) * 100
|
||||
print(f" ✅ Processed: {os.path.basename(image_path)} ({percentage:.1f}% background removed)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ ERROR: {os.path.basename(image_path)} - {e}")
|
||||
return False
|
||||
|
||||
def scan_and_process(base_dir):
|
||||
"""Scan all configured folders and process images"""
|
||||
stats = {
|
||||
'total_found': 0,
|
||||
'processed': 0,
|
||||
'skipped_transparent': 0,
|
||||
'skipped_no_green': 0,
|
||||
'errors': 0
|
||||
}
|
||||
|
||||
print("🔍 SCANNING FOR IMAGES...\n")
|
||||
|
||||
for folder in SEARCH_FOLDERS:
|
||||
folder_path = os.path.join(base_dir, folder)
|
||||
|
||||
if not os.path.exists(folder_path):
|
||||
print(f"⏭️ Skipping (not found): {folder}")
|
||||
continue
|
||||
|
||||
print(f"\n📁 Processing: {folder}/")
|
||||
print("=" * 60)
|
||||
|
||||
# Find all image files
|
||||
image_files = []
|
||||
for ext in ['*.png', '*.jpg', '*.jpeg']:
|
||||
image_files.extend(Path(folder_path).rglob(ext))
|
||||
|
||||
folder_stats = {
|
||||
'found': len(image_files),
|
||||
'processed': 0
|
||||
}
|
||||
|
||||
for img_path in sorted(image_files):
|
||||
# Skip already processed files
|
||||
if '_nobg' in img_path.stem:
|
||||
continue
|
||||
|
||||
stats['total_found'] += 1
|
||||
|
||||
# Generate output filename
|
||||
output_path = img_path.parent / f"{img_path.stem}_nobg.png"
|
||||
|
||||
# Skip if already exists
|
||||
if output_path.exists():
|
||||
print(f" ⏭️ Already exists: {output_path.name}")
|
||||
stats['skipped_transparent'] += 1
|
||||
continue
|
||||
|
||||
# Process the image
|
||||
result = remove_green_background(str(img_path), str(output_path))
|
||||
|
||||
if result:
|
||||
stats['processed'] += 1
|
||||
folder_stats['processed'] += 1
|
||||
elif result is False:
|
||||
# Check reason from function output
|
||||
stats['skipped_no_green'] += 1
|
||||
|
||||
print(f"\n📊 Folder Summary: {folder_stats['processed']}/{folder_stats['found']} processed")
|
||||
|
||||
return stats
|
||||
|
||||
def main():
|
||||
"""Main execution"""
|
||||
print("=" * 60)
|
||||
print("🎨 BATCH VISUAL ASSET CLEANUP")
|
||||
print("=" * 60)
|
||||
print(f"Target folders: {len(SEARCH_FOLDERS)}")
|
||||
print(f"Chroma key: RGB{GREEN_KEY} ±{TOLERANCE}")
|
||||
print("=" * 60)
|
||||
|
||||
# Get project root
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
project_root = os.path.dirname(script_dir)
|
||||
|
||||
# Process all folders
|
||||
stats = scan_and_process(project_root)
|
||||
|
||||
# Final report
|
||||
print("\n" + "=" * 60)
|
||||
print("📊 FINAL REPORT")
|
||||
print("=" * 60)
|
||||
print(f"Total images found: {stats['total_found']}")
|
||||
print(f"✅ Successfully processed: {stats['processed']}")
|
||||
print(f"⏭️ Already transparent: {stats['skipped_transparent']}")
|
||||
print(f"ℹ️ No green background: {stats['skipped_no_green']}")
|
||||
print(f"❌ Errors: {stats['errors']}")
|
||||
print("=" * 60)
|
||||
|
||||
if stats['processed'] > 0:
|
||||
print(f"\n✅ CLEANUP COMPLETE! {stats['processed']} backgrounds removed.")
|
||||
else:
|
||||
print("\n✅ All images already clean!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user