Files
PaintPlus/backend/scripts/import_eyes.py
T
Claude 3fe70fa663 Add public domain eye catalog system for CNC wood carving
Added complete system for populating eye catalog with classical carved eyes:

Features:
- Eye import script (import_eyes.py) for batch/single eye imports
- Public domain source guide (museums: Met, Smithsonian, Getty, etc.)
- Seed catalog system for pre-populating database
- Organized by emotion (serene, fierce, wise, peaceful, etc.)
- Organized by style (Greek, Roman, Egyptian, Renaissance)
- Organized by side (left, right, both)
- Auto-generates thumbnails and metadata
- CNC-ready tagging system

Workflow:
1. Download classical sculpture photos from public domain museums
2. Crop eyes in any image editor
3. Run import script with metadata
4. Eyes saved to catalog with proper tags
5. Apply to colored photos (pure image compositing, no AI regeneration)
6. Convert result to grayscale for CNC carving

Documentation:
- PUBLIC_DOMAIN_EYE_SOURCES.md: Where to find carved eyes
- scripts/README.md: How to import eyes
- Includes recommended starting collection (10 essential eyes)

Benefits for wood carving:
- Build library from master sculptors (2000+ years of proven designs)
- Reusable across all projects
- Consistent emotional weight in carvings
- No AI regeneration - just intelligent copy/paste/blend
- Perfect for CNC workflow (colored preview → grayscale → carve)

The patch library system uses PIL/OpenCV for image compositing,
NOT AI regeneration, so it preserves exact carved geometry.
2026-01-25 02:06:40 +00:00

211 lines
5.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Quick eye import script
Usage:
python import_eyes.py greek_serene_left.png --emotion serene --side left --style greek
python import_eyes.py *.png --emotion fierce --style roman
This will add eyes to the patch library with proper metadata.
"""
import sys
import argparse
from pathlib import Path
from PIL import Image
# Add parent directory to path to import app modules
sys.path.insert(0, str(Path(__file__).parent.parent))
from app.database import SessionLocal
from app.models.patch import Patch
from app.services.patch_library import PatchLibraryService
def import_eye(
image_path: Path,
emotion: str,
side: str,
style: str,
description: str = None
):
"""
Import a single eye image into the catalog
Args:
image_path: Path to eye image file
emotion: serene, fierce, wise, peaceful, joyful, sorrowful
side: left, right, both
style: greek, roman, egyptian, renaissance, custom
description: Optional custom description
"""
db = SessionLocal()
patch_service = PatchLibraryService()
# Generate name from filename if not provided
name = image_path.stem.replace('_', ' ').title()
# Auto-generate description if not provided
if not description:
description = f"{style.title()} carved eye, {emotion} expression, {side} side. Suitable for CNC wood carving."
# Generate tags
tags = f"{style}, {emotion}, {side}, carved, cnc-ready, wood-carving"
print(f"\n📸 Importing: {name}")
print(f" File: {image_path.name}")
print(f" Style: {style}")
print(f" Emotion: {emotion}")
print(f" Side: {side}")
try:
# Create patch record
patch = Patch(
name=name,
description=description,
source_type="imported",
category="carved_eye",
tags=tags,
width=0,
height=0,
user_id=None,
file_path=""
)
db.add(patch)
db.commit()
db.refresh(patch)
# Save image file
file_path = patch_service.save_patch_from_file(
patch.id,
str(image_path),
create_thumb=True
)
# Get and update dimensions
width, height = patch_service.get_patch_size(patch.id)
patch.width = width
patch.height = height
patch.file_path = file_path
patch.thumbnail_path = str(patch_service.get_thumbnail_path(patch.id))
db.commit()
print(f"✅ Successfully imported!")
print(f" ID: {patch.id}")
print(f" Size: {width}x{height}px")
return patch.id
except Exception as e:
print(f"❌ Error importing: {e}")
db.rollback()
return None
finally:
db.close()
def main():
parser = argparse.ArgumentParser(
description="Import carved eye images into the patch library",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Import a single eye
python import_eyes.py greek_serene_left.png --emotion serene --side left --style greek
# Import multiple eyes with same metadata
python import_eyes.py roman_*.png --emotion fierce --side both --style roman
# With custom description
python import_eyes.py statue_eye.png --emotion wise --side right --style roman --description "Emperor Augustus portrait eye"
Emotions: serene, fierce, wise, peaceful, joyful, sorrowful, neutral
Sides: left, right, both
Styles: greek, roman, egyptian, renaissance, baroque, modern, custom
"""
)
parser.add_argument(
'images',
nargs='+',
help='Image file(s) to import (supports wildcards)'
)
parser.add_argument(
'--emotion',
required=True,
choices=['serene', 'fierce', 'wise', 'peaceful', 'joyful', 'sorrowful', 'neutral'],
help='Emotional expression of the eye'
)
parser.add_argument(
'--side',
required=True,
choices=['left', 'right', 'both'],
help='Which eye (left or right)'
)
parser.add_argument(
'--style',
required=True,
choices=['greek', 'roman', 'egyptian', 'renaissance', 'baroque', 'modern', 'custom'],
help='Carving style/period'
)
parser.add_argument(
'--description',
help='Custom description (optional)'
)
args = parser.parse_args()
# Resolve wildcards and get all image files
image_files = []
for pattern in args.images:
path = Path(pattern)
if '*' in pattern:
# Wildcard - expand it
parent = path.parent if path.parent.exists() else Path('.')
image_files.extend(parent.glob(path.name))
else:
# Single file
if path.exists():
image_files.append(path)
else:
print(f"⚠️ File not found: {pattern}")
if not image_files:
print("❌ No image files found!")
return
print(f"\n🎨 Importing {len(image_files)} eye image(s) into catalog...")
print(f" Style: {args.style}")
print(f" Emotion: {args.emotion}")
print(f" Side: {args.side}")
print("="*60)
imported_count = 0
for image_path in image_files:
patch_id = import_eye(
image_path,
args.emotion,
args.side,
args.style,
args.description
)
if patch_id:
imported_count += 1
print("="*60)
print(f"\n✅ Import complete! {imported_count}/{len(image_files)} eyes added to catalog")
print(f"\n💡 Access your eye catalog at: http://your-server:3080")
print(f" Or via API: GET /patches/?category=carved_eye")
if __name__ == "__main__":
main()