Files
sky-cam/test_moon_composite.py
T
Claude 09fda8d8af Add smoke-test script for cloud-veil composite
test_moon_composite.py uses the existing repo sample frames
(21-07-00.jpg east frame with thin cloud cover + full_moon_closeup.jpg
as NASA render stand-in) to produce test_composite_out.jpg without
needing a live NASA API call or moon detection run.

Run: python3 test_moon_composite.py

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 17:16:50 +00:00

112 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""test_moon_composite.py — smoke-test the cloud-veil composite using local files.
Uses the sample east frame (21-07-00.jpg) and the reference moon photo
(full_moon_closeup.jpg) already in the repo to produce a composite without
needing a live NASA API call or actual moon detection.
Run from the sky-cam directory:
python3 test_moon_composite.py
Output: test_composite_out.jpg in the same directory.
The east frame (2026-04-29 21:06:45) shows the moon with visible thin cloud
cover across the sky, so the cloud-veil layer should be clearly active.
"""
import pathlib
import sys
from datetime import datetime, timezone
HERE = pathlib.Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
EAST_FRAME = HERE / "21-07-00.jpg"
NASA_RENDER = HERE / "full_moon_closeup.jpg"
OUT_PATH = HERE / "test_composite_out.jpg"
# Approximate moon centroid in the east frame, estimated visually.
# The moon appears at roughly 68% from left, 31% from top of the 1920×1080 frame.
# moon_detect.py would compute these exactly at runtime.
MOON_CX_FRAC = 0.68
MOON_CY_FRAC = 0.31
# Apparent diameter in source pixels — roughly 38 px for a typical wide-field
# IP camera at full-moon. Adjust if your camera gives a larger blob.
MOON_DIAM_PX = 38
def _make_fake_detection(frame_path):
"""Return a detection-like object with centroid_xy and diameter_px."""
from PIL import Image
im = Image.open(frame_path)
w, h = im.size
cx = w * MOON_CX_FRAC
cy = h * MOON_CY_FRAC
print(f" frame size : {w}×{h}")
print(f" moon centroid: ({cx:.0f}, {cy:.0f})")
print(f" moon diameter: {MOON_DIAM_PX} px")
class _Det:
centroid_xy = (cx, cy)
diameter_px = MOON_DIAM_PX
quality = 0.82 # plausible for a hazy but visible moon
return _Det()
def main():
for p in (EAST_FRAME, NASA_RENDER):
if not p.exists():
print(f"ERROR: missing {p}", file=sys.stderr)
sys.exit(1)
print("=== moon composite smoke-test ===")
print(f"east frame : {EAST_FRAME.name}")
print(f"NASA render : {NASA_RENDER.name}")
print(f"output : {OUT_PATH.name}")
print()
det = _make_fake_detection(EAST_FRAME)
# Timestamp matching the east frame filename
when_utc = datetime(2026, 4, 29, 21, 7, 0, tzinfo=timezone.utc)
from moon_composite import render_phase_closeup
caption = (
"Full Moon — April 2026 — "
"sky-cam east witnessed at 2026-04-29 21:07:00 UTC "
"(+7 min from exact full) — render: NASA SVS Dial-a-Moon [SIMULATED]"
)
print("rendering composite …")
render_phase_closeup(
nasa_render_path=str(NASA_RENDER),
out_path=str(OUT_PATH),
output_size=(1920, 1080),
moon_height_pct=0.92,
caption=caption,
east_frame_path=str(EAST_FRAME),
east_detection=det,
cloud_overlay_enabled=True,
cloud_overlay_max_opacity=0.40,
cloud_overlay_blur=0, # auto
)
print(f"\ndone → {OUT_PATH}")
print()
print("What you should see:")
print(" • Full moon disk filling ~92% of the 1920×1080 frame")
print(" • Thin grey-blue cloud veil over the composite — sourced from")
print(" the sky ring around the moon in 21-07-00.jpg, blurred to haze")
print(" • Moon disk re-pasted sharp on top of the veil layer")
print(" • Caption at bottom-left with phase / date / witness text")
print()
print("Sky brightness in the annular ring drives veil opacity.")
print("The hazy sky visible in 21-07-00.jpg should produce a visible but")
print("partial veil (estimated ~2030% opacity for that frame).")
if __name__ == "__main__":
main()