photo3d/
application/
Photos3DSelector.swift
run_photos3d_selector.sh
setup_photos3d.sh
PROJECT.yaml
README.md
[DRAFT — edit this] Find photos from iCloud Photos that are suitable for 3D reconstruction (SfM / photogrammetry) and download them to a local directory for processing with the [video2mesh pipeline](../../../apps/ai-applevoicerecorder/video2mesh/). Inferred stage: development. Define the specific deliverable, success state, and timeline.
Success criteria:| Code | /Users/friedrichstr/ai-mac-studio/privat/photo3d |
| Check | Path | Status | Detail |
|---|---|---|---|
| code | /Users/friedrichstr/ai-mac-studio/privat/photo3d | ✓ ok | 3 items, last_modified=2026-08-24 |
Find photos from iCloud Photos that are suitable for 3D reconstruction (SfM / photogrammetry) and download them to a local directory for processing with the video2mesh pipeline.
privat/photo3d/
├── application/
│ ├── Photos3DSelector.swift # Swift tool: query + analyze + download
│ ├── run_photos3d_selector.sh # Wrapper script
│ └── Photos3DSelector.app/ # Compiled app bundle (for TCC permissions)
├── photos_for_3d/ # Downloaded photos (output, created on first run)
└── README.md # This file
This Mac mini has iCloud signed in (gerd.grasshoff@gmail.com) with the iCloud Photos service active,
but no local Photos Library exists (~/Pictures/ is empty).
To set up the Photos Library:
~/Pictures/Photos Library.photoslibrary (default location)On first run, the system will show a permission dialog asking for Photos access. Click "Allow" to grant the Photos3DSelector access to your photo library.
If the permission is denied, you can reset it:
tccutil reset Photos
Then re-run the selector.
Always go through run_photos3d_selector.sh. It compiles the selector into the
Photos3DSelector.app bundle and runs that binary. Running the source directly
with swift Photos3DSelector.swift does not work: the interpreter does not
link Photos.framework and aborts with Symbols not found. And even once
compiled, macOS grants photo access to the app bundle, not to a loose binary.
cd privat/photo3d/application
./run_photos3d_selector.sh --dry-run --verbose
cd privat/photo3d/application
./run_photos3d_selector.sh
| Flag | Default | Description |
|---|---|---|
--output <dir> |
photos_for_3d/ in the working directory |
Output directory for downloaded photos |
--days-back <n> |
1 |
How many days back to search (1 = yesterday) |
--include-videos |
off | Also include videos (suitable for frame extraction) |
--dry-run |
off | Analyze only, don't download |
--verbose |
off | Print detailed analysis for each photo |
--min-resolution <px> |
1500 |
Minimum long-edge resolution in pixels |
--min-cluster <n> |
3 |
Minimum photos in a time cluster (photo-walk session) |
--cluster-interval <s> |
300 |
Max gap (seconds) between photos in a cluster |
Find photos from 3 days ago, include videos:
./run_photos3d_selector.sh --days-back 3 --include-videos --verbose
Lower the cluster threshold to 2 photos:
./run_photos3d_selector.sh --min-cluster 2 --cluster-interval 600
Dry run to see what would be selected:
./run_photos3d_selector.sh --dry-run --verbose
A photo is considered suitable for 3D reconstruction if:
--min-resolution)--include-videos is set) — enough frames for extractionPhotos are grouped into time clusters — sequences of photos taken within 5 minutes (default) of each other. A cluster of ≥ 3 photos from different angles is ideal for 3D reconstruction (photogrammetry needs overlapping views).
Photos from clusters with fewer than the minimum cluster size are still downloaded individually if they pass the suitability filter.
photos_for_3d/
├── cluster_00/ # First photo-walk session
│ ├── IMG_20260730_143022_000.jpg
│ ├── IMG_20260730_143055_001.jpg
│ └── ...
├── cluster_01/ # Second photo-walk session
│ ├── IMG_20260730_161200_010.jpg
│ └── ...
└── photos3d_metadata.json # Full metadata: dates, GPS, resolution, clusters
After downloading photos, use the video2mesh pipeline:
cd apps/ai-applevoicerecorder/video2mesh
python video2mesh.py --frames /path/to/privat/photo3d/photos_for_3d/cluster_00/
The video2mesh pipeline runs COLMAP for Structure-from-Motion (SfM) and can produce
sparse point clouds on macOS (dense MVS requires CUDA/Linux). See SFM_REFERENCE.md
in the video2mesh directory for details.
This means no Photos Library exists or permission was denied:
tccutil reset Photos--days-back 2 or --days-back 7 for a wider date rangeIf the swift command-line tool can't get Photos permission (auto-denies),
use the compiled app bundle:
cd privat/photo3d/application
# The app bundle is pre-built. If you modified the Swift source, rebuild it:
# swiftc -o Photos3DSelector.app/Contents/MacOS/Photos3DSelector \
# Photos3DSelector.swift -framework Photos -framework Foundation \
# -framework UniformTypeIdentifiers
# Then run via open:
open Photos3DSelector.app --args --dry-run --verbose
# Check output in Console.app or system logs:
# log show --predicate 'process == "Photos3DSelector"' --last 5m
cd privat/photo3d/application
swiftc -typecheck Photos3DSelector.swift -framework Photos -framework Foundation \
-framework UniformTypeIdentifiers