composite: add unsharp mask after Lanczos resize to restore crater crispness

Lanczos downsampling (NASA 2048 px → 756 px output) anti-aliases fine
crater rims and mare boundaries to a blur of ~1-2 px.  Apply Pillow's
UnsharpMask(radius=2, percent=160, threshold=2) immediately after resize
in both composite_full_moon and render_phase_closeup.  This restores the
perceived sharpness to match what the NASA source actually contains, and
brings crater detail in line with what a 52x optical zoom camera shows on
a clear night from the same location.  No AI or upscaling involved.

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
This commit is contained in:
Claude
2026-05-03 18:31:24 +00:00
parent 15ece6ff3f
commit b21803151b
+6 -3
View File
@@ -250,6 +250,9 @@ def composite_full_moon(
target_size = int(round(output_size[1] * moon_height_pct))
target_size += target_size % 2 # even
ref_resized = ref.resize((target_size, target_size), LANCZOS)
ref_resized = ref_resized.filter(
ImageFilter.UnsharpMask(radius=2, percent=160, threshold=2)
)
# ── Phase shadow (skip when essentially full) ──
illum = moon_phase.illumination(when_utc)
@@ -260,9 +263,6 @@ def composite_full_moon(
# ── Parallactic-angle rotation ──
par = moon_phase.parallactic_angle(when_utc)
# PIL rotates counter-clockwise for positive angles; we want celestial
# north to end up "up" in the camera image. Negate so the rotation
# direction matches image-space y-down convention.
ref_rot = ref_resized.rotate(-par, resample=BICUBIC, expand=False)
# ── Composite with feathered circular mask ──
@@ -311,6 +311,9 @@ def render_phase_closeup(
target = int(round(output_size[1] * moon_height_pct))
target += target % 2
moon_resized = moon.resize((target, target), LANCZOS)
moon_resized = moon_resized.filter(
ImageFilter.UnsharpMask(radius=2, percent=160, threshold=2)
)
# Rotate by parallactic angle so "up" on the moon matches east's sky
if when_utc is not None: