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.
This commit is contained in:
@@ -0,0 +1,225 @@
|
|||||||
|
# Eye Catalog Import Scripts
|
||||||
|
|
||||||
|
Tools for populating your carved eye catalog with public domain examples.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Download Classical Eyes
|
||||||
|
|
||||||
|
Follow the guide: `/docs/PUBLIC_DOMAIN_EYE_SOURCES.md`
|
||||||
|
|
||||||
|
**Best sources:**
|
||||||
|
- Metropolitan Museum (CC0)
|
||||||
|
- Smithsonian Open Access
|
||||||
|
- Getty Museum Open Content
|
||||||
|
|
||||||
|
**Download 10-20 high-res images** of carved eyes from classical sculptures.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Crop the Eyes
|
||||||
|
|
||||||
|
Use any image editor (Photoshop, GIMP, Preview, etc.):
|
||||||
|
|
||||||
|
1. Open statue photo
|
||||||
|
2. Zoom in on eye
|
||||||
|
3. Crop just the eye (include eyelids, socket, tear duct)
|
||||||
|
4. Save as PNG with descriptive name:
|
||||||
|
- `greek_serene_left.png`
|
||||||
|
- `roman_fierce_right.png`
|
||||||
|
- `egyptian_wise_left.png`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Import to Catalog
|
||||||
|
|
||||||
|
**Easy way (one at a time):**
|
||||||
|
```bash
|
||||||
|
cd backend/scripts
|
||||||
|
|
||||||
|
# Import a Greek serene eye
|
||||||
|
python import_eyes.py greek_serene_left.png \
|
||||||
|
--emotion serene \
|
||||||
|
--side left \
|
||||||
|
--style greek
|
||||||
|
|
||||||
|
# Import a Roman fierce eye
|
||||||
|
python import_eyes.py roman_fierce_right.png \
|
||||||
|
--emotion fierce \
|
||||||
|
--side right \
|
||||||
|
--style roman
|
||||||
|
```
|
||||||
|
|
||||||
|
**Batch import:**
|
||||||
|
```bash
|
||||||
|
# Import all Greek eyes at once
|
||||||
|
python import_eyes.py greek_*.png \
|
||||||
|
--emotion serene \
|
||||||
|
--side both \
|
||||||
|
--style greek
|
||||||
|
|
||||||
|
# Import all Roman eyes
|
||||||
|
python import_eyes.py roman_*.png \
|
||||||
|
--emotion fierce \
|
||||||
|
--side both \
|
||||||
|
--style roman
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Available Options
|
||||||
|
|
||||||
|
### Emotions
|
||||||
|
- `serene` - Peaceful, calm (most classical Greek)
|
||||||
|
- `fierce` - Intense, powerful (Hellenistic, Alexander)
|
||||||
|
- `wise` - Aged, experienced (Roman senators)
|
||||||
|
- `peaceful` - Gentle, kind (Archaic Greek)
|
||||||
|
- `joyful` - Happy, smiling (rare in classical)
|
||||||
|
- `sorrowful` - Sad, mourning (some Hellenistic)
|
||||||
|
- `neutral` - Default, no strong emotion
|
||||||
|
|
||||||
|
### Styles
|
||||||
|
- `greek` - Classical Greek (450-400 BCE)
|
||||||
|
- `roman` - Roman Republican/Imperial
|
||||||
|
- `egyptian` - Ancient Egyptian carved eyes
|
||||||
|
- `renaissance` - Renaissance sculpture
|
||||||
|
- `baroque` - Baroque period
|
||||||
|
- `modern` - Contemporary carving
|
||||||
|
- `custom` - Your own style
|
||||||
|
|
||||||
|
### Sides
|
||||||
|
- `left` - Left eye
|
||||||
|
- `right` - Right eye
|
||||||
|
- `both` - Can be used for either (symmetric)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Workflow
|
||||||
|
|
||||||
|
### Build a Complete Catalog
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Download eyes from Met Museum
|
||||||
|
# (See PUBLIC_DOMAIN_EYE_SOURCES.md)
|
||||||
|
|
||||||
|
# 2. Crop and save them:
|
||||||
|
# greek_serene_left.png
|
||||||
|
# greek_serene_right.png
|
||||||
|
# roman_fierce_left.png
|
||||||
|
# roman_fierce_right.png
|
||||||
|
# etc.
|
||||||
|
|
||||||
|
# 3. Import them all:
|
||||||
|
|
||||||
|
python import_eyes.py greek_serene_left.png --emotion serene --side left --style greek
|
||||||
|
python import_eyes.py greek_serene_right.png --emotion serene --side right --style greek
|
||||||
|
python import_eyes.py roman_fierce_left.png --emotion fierce --side left --style roman
|
||||||
|
python import_eyes.py roman_fierce_right.png --emotion fierce --side right --style roman
|
||||||
|
|
||||||
|
# Or batch:
|
||||||
|
python import_eyes.py greek_*.png --emotion serene --side both --style greek
|
||||||
|
python import_eyes.py roman_*.png --emotion fierce --side both --style roman
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Starting Collection
|
||||||
|
|
||||||
|
### 10 Essential Eyes
|
||||||
|
|
||||||
|
1. **Greek Serene Left** (peaceful carvings)
|
||||||
|
2. **Greek Serene Right**
|
||||||
|
3. **Greek Archaic Left** (stylized, simple)
|
||||||
|
4. **Greek Archaic Right**
|
||||||
|
5. **Roman Fierce Left** (powerful portraits)
|
||||||
|
6. **Roman Fierce Right**
|
||||||
|
7. **Roman Wise Left** (aged, realistic)
|
||||||
|
8. **Roman Wise Right**
|
||||||
|
9. **Egyptian Stylized Left** (distinctive style)
|
||||||
|
10. **Egyptian Stylized Right**
|
||||||
|
|
||||||
|
This gives you 5 styles/emotions to start!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Check Your Catalog
|
||||||
|
|
||||||
|
### Via API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all eyes in catalog
|
||||||
|
curl http://localhost:8101/patches/?category=carved_eye
|
||||||
|
|
||||||
|
# Filter by emotion
|
||||||
|
curl http://localhost:8101/patches/?category=carved_eye&tags=serene
|
||||||
|
|
||||||
|
# Filter by style
|
||||||
|
curl http://localhost:8101/patches/?tags=greek
|
||||||
|
```
|
||||||
|
|
||||||
|
### Via Web Interface
|
||||||
|
|
||||||
|
Go to: `http://your-server:3080`
|
||||||
|
|
||||||
|
Navigate to patch library to browse your eyes visually.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Advanced: Seed Script
|
||||||
|
|
||||||
|
For batch importing from the `seed_data/eyes/` directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Place all cropped eyes in:
|
||||||
|
mkdir -p seed_data/eyes/
|
||||||
|
# Copy your eye images there
|
||||||
|
|
||||||
|
# 2. Edit seed_eye_catalog.py to add metadata
|
||||||
|
|
||||||
|
# 3. Run:
|
||||||
|
python seed_eye_catalog.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This auto-imports all eyes in `seed_data/eyes/` with pre-configured metadata.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
1. **High resolution:** Use images 1000px+ for best results
|
||||||
|
2. **Clean crops:** Include some surrounding area, not just the eyeball
|
||||||
|
3. **Consistent naming:** Use descriptive filenames
|
||||||
|
4. **Test first:** Import 2-3 eyes to test the workflow
|
||||||
|
5. **Build gradually:** Start with 10 eyes, expand as needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**"File not found":**
|
||||||
|
- Make sure you're in `backend/scripts/` directory
|
||||||
|
- Use full path or relative path to image
|
||||||
|
|
||||||
|
**"Database connection error":**
|
||||||
|
- Make sure backend is running: `docker compose up backend`
|
||||||
|
- Check database exists: `ls -la ../../data/`
|
||||||
|
|
||||||
|
**"Import failed":**
|
||||||
|
- Check image format (PNG, JPG supported)
|
||||||
|
- Verify file isn't corrupted
|
||||||
|
- Check file permissions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
After importing eyes:
|
||||||
|
|
||||||
|
1. **Test them:** Apply to a colored photo via API
|
||||||
|
2. **Refine:** Add more variations as needed
|
||||||
|
3. **Build library:** Aim for 20-30 eyes covering all emotions
|
||||||
|
4. **Share:** Your best eyes can be exported and shared
|
||||||
|
|
||||||
|
**Your catalog of master sculptor's eyes is ready to use!**
|
||||||
Executable
+210
@@ -0,0 +1,210 @@
|
|||||||
|
#!/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()
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
"""
|
||||||
|
Seed the patch library with classical carved eyes from public domain sources
|
||||||
|
|
||||||
|
This script helps pre-populate the eye catalog with examples from:
|
||||||
|
- Greek statues (Metropolitan Museum, Louvre)
|
||||||
|
- Roman sculptures (Smithsonian, British Museum)
|
||||||
|
- Renaissance carvings
|
||||||
|
- Ancient Egyptian carved eyes
|
||||||
|
|
||||||
|
All images should be public domain (CC0, Public Domain Mark)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import httpx
|
||||||
|
from pathlib import Path
|
||||||
|
from PIL import Image
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
# Public domain eye examples to seed the catalog
|
||||||
|
# These are examples - you would add actual URLs from museum APIs
|
||||||
|
CLASSICAL_EYES = [
|
||||||
|
{
|
||||||
|
"name": "Greek Statue - Serene Left Eye",
|
||||||
|
"description": "Classical Greek marble carving, convex eyeball, defined upper lid, deep socket. Perfect for serene expressions.",
|
||||||
|
"category": "carved_eye",
|
||||||
|
"tags": "greek, serene, left, marble, classical, convex, deep-socket",
|
||||||
|
"style": "greek_classical",
|
||||||
|
"emotion": "serene",
|
||||||
|
"side": "left",
|
||||||
|
"source_url": "https://images.metmuseum.org/...", # Example
|
||||||
|
"source": "Metropolitan Museum of Art - Public Domain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Sculpture - Fierce Right Eye",
|
||||||
|
"description": "Roman marble, prominent brow ridge, intense gaze, sharp eyelid definition.",
|
||||||
|
"category": "carved_eye",
|
||||||
|
"tags": "roman, fierce, right, marble, intense, sharp-detail",
|
||||||
|
"style": "roman_classical",
|
||||||
|
"emotion": "fierce",
|
||||||
|
"side": "right",
|
||||||
|
"source_url": "https://...",
|
||||||
|
"source": "Smithsonian - CC0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Greek Kouros - Peaceful Left Eye",
|
||||||
|
"description": "Archaic Greek style, almond-shaped, subtle carving, peaceful expression.",
|
||||||
|
"category": "carved_eye",
|
||||||
|
"tags": "greek, peaceful, left, archaic, almond-shaped, subtle",
|
||||||
|
"style": "greek_archaic",
|
||||||
|
"emotion": "peaceful",
|
||||||
|
"side": "left",
|
||||||
|
"source_url": "https://...",
|
||||||
|
"source": "Getty Museum - Public Domain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Portrait - Wise Right Eye",
|
||||||
|
"description": "Late Roman period, detailed eyelids, slight downward gaze, wisdom and age.",
|
||||||
|
"category": "carved_eye",
|
||||||
|
"tags": "roman, wise, right, portrait, detailed, aged",
|
||||||
|
"style": "roman_portrait",
|
||||||
|
"emotion": "wise",
|
||||||
|
"side": "right",
|
||||||
|
"source_url": "https://...",
|
||||||
|
"source": "British Museum - CC0"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
async def download_image(url: str) -> bytes:
|
||||||
|
"""Download image from URL"""
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
response = await client.get(url)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.content
|
||||||
|
|
||||||
|
async def crop_eye_from_statue(image_bytes: bytes, crop_box: tuple) -> bytes:
|
||||||
|
"""
|
||||||
|
Crop just the eye from a full statue photo
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_bytes: Full statue image
|
||||||
|
crop_box: (left, top, right, bottom) coordinates
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Cropped eye image bytes
|
||||||
|
"""
|
||||||
|
img = Image.open(BytesIO(image_bytes))
|
||||||
|
eye = img.crop(crop_box)
|
||||||
|
|
||||||
|
# Save as PNG
|
||||||
|
buffer = BytesIO()
|
||||||
|
eye.save(buffer, format='PNG')
|
||||||
|
return buffer.getvalue()
|
||||||
|
|
||||||
|
async def seed_eye_catalog():
|
||||||
|
"""
|
||||||
|
Seed the patch library with classical carved eyes
|
||||||
|
|
||||||
|
NOTE: This is a template. You need to:
|
||||||
|
1. Get actual public domain image URLs
|
||||||
|
2. Manually crop the eyes (or provide crop coordinates)
|
||||||
|
3. Run this to populate the catalog
|
||||||
|
"""
|
||||||
|
|
||||||
|
from app.database import SessionLocal
|
||||||
|
from app.models.patch import Patch
|
||||||
|
from app.services.patch_library import PatchLibraryService
|
||||||
|
|
||||||
|
db = SessionLocal()
|
||||||
|
patch_service = PatchLibraryService()
|
||||||
|
|
||||||
|
print("Seeding eye catalog with classical carved eyes...")
|
||||||
|
|
||||||
|
for eye_data in CLASSICAL_EYES:
|
||||||
|
print(f"\nAdding: {eye_data['name']}")
|
||||||
|
|
||||||
|
# Create patch record
|
||||||
|
patch = Patch(
|
||||||
|
name=eye_data['name'],
|
||||||
|
description=eye_data['description'],
|
||||||
|
source_type="imported",
|
||||||
|
category=eye_data['category'],
|
||||||
|
tags=eye_data['tags'],
|
||||||
|
width=0, # Will be set after image save
|
||||||
|
height=0,
|
||||||
|
user_id=None,
|
||||||
|
file_path=""
|
||||||
|
)
|
||||||
|
|
||||||
|
db.add(patch)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(patch)
|
||||||
|
|
||||||
|
# Download and save image
|
||||||
|
# NOTE: You need to manually download/crop these first
|
||||||
|
# This is just the structure
|
||||||
|
|
||||||
|
try:
|
||||||
|
# image_bytes = await download_image(eye_data['source_url'])
|
||||||
|
# cropped_eye = await crop_eye_from_statue(image_bytes, crop_box)
|
||||||
|
|
||||||
|
# For now, you would manually place images in:
|
||||||
|
# ./seed_data/eyes/greek_serene_left.png
|
||||||
|
# ./seed_data/eyes/roman_fierce_right.png
|
||||||
|
# etc.
|
||||||
|
|
||||||
|
seed_image_path = Path(__file__).parent / "seed_data" / "eyes" / f"{eye_data['style']}_{eye_data['emotion']}_{eye_data['side']}.png"
|
||||||
|
|
||||||
|
if seed_image_path.exists():
|
||||||
|
file_path = patch_service.save_patch_from_file(
|
||||||
|
patch.id,
|
||||||
|
str(seed_image_path),
|
||||||
|
create_thumb=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get 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"✅ Added {eye_data['name']}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ Image not found: {seed_image_path}")
|
||||||
|
print(f" Please download and crop eye from: {eye_data['source']}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error adding {eye_data['name']}: {e}")
|
||||||
|
db.rollback()
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
print("\n✅ Eye catalog seeding complete!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(seed_eye_catalog())
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
# Public Domain Carved Eye Sources
|
||||||
|
|
||||||
|
Where to find high-quality images of carved eyes from classical sculptures (all public domain).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Museums with Public Domain Images
|
||||||
|
|
||||||
|
### 1. Metropolitan Museum of Art (CC0 Public Domain)
|
||||||
|
|
||||||
|
**Website:** https://www.metmuseum.org/art/collection
|
||||||
|
|
||||||
|
**Search tips:**
|
||||||
|
- Search: "greek statue marble head"
|
||||||
|
- Search: "roman portrait bust"
|
||||||
|
- Filter: "Public Domain" only
|
||||||
|
- Download: Click "Download" for high-resolution
|
||||||
|
|
||||||
|
**Great examples:**
|
||||||
|
- Greek Kouros heads (Archaic period)
|
||||||
|
- Roman portrait busts
|
||||||
|
- Hellenistic marble sculptures
|
||||||
|
|
||||||
|
**Direct collections:**
|
||||||
|
- Greek & Roman Art: https://www.metmuseum.org/art/collection/search#!?department=13
|
||||||
|
- Filter by "Images" → "Public Domain"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Smithsonian Open Access (CC0)
|
||||||
|
|
||||||
|
**Website:** https://www.si.edu/openaccess
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- 3 million+ images
|
||||||
|
- All CC0 (no copyright restrictions)
|
||||||
|
- High-resolution downloads
|
||||||
|
|
||||||
|
**Search:**
|
||||||
|
- "roman marble head"
|
||||||
|
- "greek sculpture eyes"
|
||||||
|
- "classical portrait bust"
|
||||||
|
|
||||||
|
**API available:** https://api.si.edu/openaccess/api/v1.0/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Getty Museum (Open Content)
|
||||||
|
|
||||||
|
**Website:** https://www.getty.edu/art/collection/
|
||||||
|
|
||||||
|
**Search tips:**
|
||||||
|
- Filter: "Open Content Program"
|
||||||
|
- Greek and Roman antiquities
|
||||||
|
- High-resolution IIIF images
|
||||||
|
|
||||||
|
**Great for:**
|
||||||
|
- Archaic Greek sculptures
|
||||||
|
- Classical period heads
|
||||||
|
- Detailed close-ups
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Rijksmuseum (Public Domain)
|
||||||
|
|
||||||
|
**Website:** https://www.rijksmuseum.nl/en/rijksstudio
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Rijksstudio (free download tool)
|
||||||
|
- High-resolution images
|
||||||
|
- Classical sculpture collection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. British Museum (CC BY-NC-SA 4.0)
|
||||||
|
|
||||||
|
**Website:** https://www.britishmuseum.org/collection
|
||||||
|
|
||||||
|
**Note:** Some restrictions, but many images free for non-commercial use
|
||||||
|
|
||||||
|
**Great for:**
|
||||||
|
- Egyptian carved eyes
|
||||||
|
- Greek marble heads
|
||||||
|
- Roman portraits
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. Louvre Collections
|
||||||
|
|
||||||
|
**Website:** https://collections.louvre.fr/en/
|
||||||
|
|
||||||
|
**Search:** "sculpture greek head" or "sculpture roman portrait"
|
||||||
|
|
||||||
|
**Note:** Check individual image licenses
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Find the Perfect Eyes
|
||||||
|
|
||||||
|
### Search Strategy
|
||||||
|
|
||||||
|
1. **Search for heads/busts, not full statues:**
|
||||||
|
- "greek marble head"
|
||||||
|
- "roman portrait bust"
|
||||||
|
- "classical sculpture face"
|
||||||
|
|
||||||
|
2. **Specific periods:**
|
||||||
|
- "archaic greek kouros" (serene, stylized)
|
||||||
|
- "classical greek sculpture" (idealized, peaceful)
|
||||||
|
- "hellenistic sculpture" (emotional, dramatic)
|
||||||
|
- "roman portrait" (realistic, wise)
|
||||||
|
|
||||||
|
3. **Look for close-ups:**
|
||||||
|
- Museums often provide detail shots
|
||||||
|
- Check "zoom" or "IIIF viewer" options
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Starting Collection
|
||||||
|
|
||||||
|
### Serene/Peaceful Eyes
|
||||||
|
|
||||||
|
**Greek Classical Period (450-400 BCE):**
|
||||||
|
- Doryphoros (Spear Bearer) type
|
||||||
|
- Athena heads
|
||||||
|
- Apollo statues
|
||||||
|
- Smooth, idealized features
|
||||||
|
- Almond-shaped eyes
|
||||||
|
- Minimal lid detail
|
||||||
|
|
||||||
|
**Best sources:** Met Museum, Getty
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Fierce/Intense Eyes
|
||||||
|
|
||||||
|
**Hellenistic Period (323-31 BCE):**
|
||||||
|
- Alexander the Great portraits
|
||||||
|
- Dying Gaul
|
||||||
|
- Laocoon group
|
||||||
|
- Dramatic expressions
|
||||||
|
- Deep-set eyes
|
||||||
|
- Strong brow ridges
|
||||||
|
|
||||||
|
**Best sources:** Smithsonian, British Museum
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Wise/Aged Eyes
|
||||||
|
|
||||||
|
**Roman Republican Period:**
|
||||||
|
- Senator portraits
|
||||||
|
- Veristic portraits
|
||||||
|
- Realistic aging details
|
||||||
|
- Detailed wrinkles
|
||||||
|
- Saggy eyelids
|
||||||
|
- Life-like features
|
||||||
|
|
||||||
|
**Best sources:** Met Museum, Getty
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Stylized/Archaic Eyes
|
||||||
|
|
||||||
|
**Greek Archaic Period (700-480 BCE):**
|
||||||
|
- Kouros statues
|
||||||
|
- Kore statues
|
||||||
|
- Almond-shaped
|
||||||
|
- Simplified forms
|
||||||
|
- "Archaic smile"
|
||||||
|
- Clean, simple carving
|
||||||
|
|
||||||
|
**Best sources:** Getty, Met Museum
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Download and Crop
|
||||||
|
|
||||||
|
### Step 1: Find the Statue
|
||||||
|
|
||||||
|
Example: Met Museum
|
||||||
|
1. Go to https://www.metmuseum.org/art/collection
|
||||||
|
2. Search: "roman portrait marble"
|
||||||
|
3. Filter: Public Domain only
|
||||||
|
4. Click on a good example
|
||||||
|
|
||||||
|
### Step 2: Download High-Res
|
||||||
|
|
||||||
|
1. Click "Download" button
|
||||||
|
2. Choose largest size (usually 4000px+)
|
||||||
|
3. Save to your computer
|
||||||
|
|
||||||
|
### Step 3: Crop the Eyes
|
||||||
|
|
||||||
|
Use any image editor (Photoshop, GIMP, etc.):
|
||||||
|
|
||||||
|
1. Open the full statue image
|
||||||
|
2. Zoom in on one eye
|
||||||
|
3. Crop just the eye area:
|
||||||
|
- Include: eyeball, eyelids, tear duct, socket
|
||||||
|
- Leave some surrounding area for context
|
||||||
|
- Square or slightly rectangular crop
|
||||||
|
|
||||||
|
4. Save as PNG:
|
||||||
|
- `greek_serene_left.png`
|
||||||
|
- `roman_fierce_right.png`
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
5. Repeat for other eye (if different)
|
||||||
|
|
||||||
|
### Step 4: Organize
|
||||||
|
|
||||||
|
Place cropped eyes in:
|
||||||
|
```
|
||||||
|
./backend/scripts/seed_data/eyes/
|
||||||
|
├── greek_serene_left.png
|
||||||
|
├── greek_serene_right.png
|
||||||
|
├── roman_fierce_left.png
|
||||||
|
├── roman_fierce_right.png
|
||||||
|
├── greek_peaceful_left.png
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Run Seed Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python scripts/seed_eye_catalog.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Starting Collection (10 Eyes)
|
||||||
|
|
||||||
|
To start, get these 10 eyes:
|
||||||
|
|
||||||
|
### Greek Classical (Serene)
|
||||||
|
1. Left eye - Greek marble head
|
||||||
|
2. Right eye - Greek marble head
|
||||||
|
|
||||||
|
### Greek Archaic (Stylized/Peaceful)
|
||||||
|
3. Left eye - Kouros statue
|
||||||
|
4. Right eye - Kouros statue
|
||||||
|
|
||||||
|
### Hellenistic (Fierce/Dramatic)
|
||||||
|
5. Left eye - Alexander portrait
|
||||||
|
6. Right eye - Alexander portrait
|
||||||
|
|
||||||
|
### Roman Republican (Wise/Aged)
|
||||||
|
7. Left eye - Roman senator bust
|
||||||
|
8. Right eye - Roman senator bust
|
||||||
|
|
||||||
|
### Roman Imperial (Powerful)
|
||||||
|
9. Left eye - Emperor portrait
|
||||||
|
10. Right eye - Emperor portrait
|
||||||
|
|
||||||
|
This gives you 5 emotional ranges × 2 eyes = 10 eyes to start!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
- **Met Museum Collection:** https://www.metmuseum.org/art/collection/search#!?department=13&showOnly=openAccess
|
||||||
|
- **Smithsonian Open Access:** https://www.si.edu/openaccess
|
||||||
|
- **Getty Open Content:** https://www.getty.edu/about/whatwedo/opencontent.html
|
||||||
|
- **Rijksmuseum API:** https://data.rijksmuseum.nl/object-metadata/api/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Legal Notes
|
||||||
|
|
||||||
|
- **CC0/Public Domain:** Use freely for any purpose
|
||||||
|
- **CC BY:** Must credit the source
|
||||||
|
- **CC BY-NC:** Non-commercial use only
|
||||||
|
- **Always check** individual image licenses
|
||||||
|
|
||||||
|
For commercial carving business, stick to **CC0** or **Public Domain** images.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tips for Best Results
|
||||||
|
|
||||||
|
1. **High resolution:** Download largest size available (2000px+ minimum)
|
||||||
|
2. **Good lighting:** Look for evenly lit photographs
|
||||||
|
3. **Straight-on angle:** Avoid extreme angles
|
||||||
|
4. **Clear detail:** Can you see the eyelid lines clearly?
|
||||||
|
5. **Minimal damage:** Choose well-preserved sculptures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Browse the museums above
|
||||||
|
2. Download 10-20 good eye examples
|
||||||
|
3. Crop them in an image editor
|
||||||
|
4. Place in `backend/scripts/seed_data/eyes/`
|
||||||
|
5. Run the seed script
|
||||||
|
6. Your catalog is ready!
|
||||||
|
|
||||||
|
**You'll have a library of proven carved eyes from master sculptors spanning 2000+ years!**
|
||||||
Reference in New Issue
Block a user