stack op• Datenarten: images → image2d
• Aufruf: import fullseye as fs; fs.ledger.drizzle_resample(frames, shifts=None, scale=2.0, pixfrac=1.0) (die Implementierung direkt: import astrostack; astrostack.drizzle_resample(frames, shifts=None, scale=2.0, pixfrac=1.0); aus dem Register: opsastrostack.get("drizzle_resample"))
• Rückgabewert über das Register: fullseye.ledger.drizzle_resample(...) liefert nur den Wert des deklarierten Out-Typs image2d (die zugrunde liegende Funktion gibt zusätzlich Hilfsinformationen zurück). Wird das Verworfene gebraucht, nutze fullseye.ledger.drizzle_resample.raw(...) oder rufe astrostack.drizzle_resample direkt auf.
• Rückgabe der Funktion: (sci, wht) -> image2d
Drizzle — erzeugt aus mehreren subpixelversetzten Bildern ein feineres Gitter (flächenerhaltend).
Fruchter & Hook, *Drizzle: A Method for the Linear Reconstruction of Undersampled Images*, PASP 114, 144 (2002). Jedes Eingabepixel wird als etwas verkleinerter "Tropfen" (drop, Kantenlänge pixfrac) betrachtet, dessen Fluss proportional zur Überlappungsfläche mit den Pixeln des Ausgabegitters verteilt wird. Da nicht interpoliert wird,
• bleibt der Gesamtfluss erhalten. Solange die Tropfen innerhalb des Ausgabegitters liegen, stimmt sci.sum() exakt mit dem Mittel der Summen der Eingabeframes überein (gemessen: relativer Fehler 0.0 mit shifts=0, scale=2, pixfrac=0.7). Deshalb ist es so gebaut, dass es sich allein am Rückgabewert gegenprüfen lässt.
• Je kleiner pixfrac, desto größer der Anteil eines Tropfens innerhalb eines Ausgabepixels: die Auflösung steigt, aber manche Ausgabepixel bleiben unbedeckt (wht wird dort klein). Dieses Tauziehen ist der einzige Stellknopf von drizzle.
Es hilft nur bei unzureichender Abtastung — das ist das gemessene Fazit. 48x48 mit 10 Sternen, Dithering 1.5 px, 16 Frames (Werte sind FWHM, umgerechnet in Eingabepixel)::
wahre FWHM Einzelframe einfaches Mittel drizzle x2 (pixfrac=0.5)
1.0 1.773 2.249 1.312
1.3 1.929 2.876 1.572
1.8 2.262 2.648 3.086
2.5 4.057 4.295 3.586
Nur wo die FWHM unter 2 Pixel fällt (Nyquist verletzt), gewinnt drizzle. Einfaches Mitteln geditherter Frames macht das Bild sogar unschärfer (1.773 → 2.249) —— weil die Versätze weggemittelt werden; drizzle wandelt genau diese Versätze in Auflösung um. Ab 1.8 px ist bereits ausreichend abgetastet, drizzle gewinnt nichts und verliert nur um die Faltung mit dem Tropfen.
Am anschaulichsten ist, ob zwei Sterne getrennt werden. 2 Sterne mit σ=0.55 px in variierendem Abstand, 16 Frames gedithert, mit Mittelung und drizzle x3 (pixfrac=0.4) gestapelt und mit star_detect gemessen: bei 1.6 Eingabepixeln Abstand fand die Mittelung 1, drizzle 2 (ab 2.0 px finden beide 2).
*shifts* ist (N, 2) aus (dr, dc): wie weit Frame i gegenüber der Referenz versetzt ist (truth["shifts"] von synth_frame_series hat diese Richtung). None bedeutet überall 0.
★ Auf das Vorzeichen achten —— die Translation der von frame_align / align_frames gelieferten Matrix zeigt in die Richtung, die den Frame zur Referenz zurückführt, d. h. sie hat gegenüber dem hier benötigten (dr, dc) das umgekehrte Vorzeichen. Übergibt man die Schätzung unverändert, heben sich die Versätze nicht auf, sondern verdoppeln sich, und ohne Ausnahme entsteht ein Doppelbild (gemessen: 6 Frames 96x96 ergeben est + truth ≈ 0; unverändert übergeben verdoppelt sich das Residuum auf das 2-fache). Um aus einer Matrix shifts in der richtigen Richtung zu bilden, drizzle_shifts verwenden. Rotation wird nicht angenommen —— mit Rotation trennen sich die Achsen nicht mehr und die Überlappungsfläche hat keine geschlossene Form, daher zuerst mit align_frames zurückdrehen (dort zahlt man den Interpolationsfehler; es ist ehrlicher, diesen Handel sichtbar zu halten).
★ Wohin gelangt ein Eingabepixel in der Ausgabe (diese Konvention war nicht dokumentiert). Über die Zuordnung der Pixel-Mittelpunkte::
out = in * scale + (scale - 1) / 2
Bei scale=2 liegt ein Stern bei Eingabe (8, 8) in der Ausgabe bei (16.5, 16.5). Das vom Eingabepixel in belegte Intervall [in, in+1) wird auf [in*scale, (in+1)*scale) der Ausgabe abgebildet, und dessen Mitte ist obige Formel —— nicht einfach in*scale. Lässt man das halbe Pixel weg, ergibt sich bei scale=4 ein systematischer Versatz von 1.5 Ausgabepixeln, umgerechnet 0.375 Eingabepixel, und Photometrie sowie Doppelsternabstände nach der Registrierung werden um genau so viel still verfälscht.
Gemessen (24x24, Einzelpixel-Stern, pixfrac=1, Messung per Schwerpunkt): für scale 2 / 3 / 4 ist die Abweichung von der Formel exakt 0. Bei scale=2.5 beträgt sie 0.05 Ausgabepixel, das ist aber kein Fehler der Formel, sondern liegt daran, dass die Randpixel der Ausgabe nur teilweise bedeckt sind, sodass der Schwerpunkt über Indizes vom kontinuierlichen Schwerpunkt abweicht (bei ganzzahligen Faktoren tritt dieser Rest nicht auf). Wenn Positionen exakt sein müssen, ein ganzzahliges scale verwenden.
Returns (sci, wht):
• sci —— (round(H*scale), round(W*scale)) float64, in Einheiten des Gesamtflusses (dieselben Elektronen wie die Eingabe). Tropfen außerhalb des Gitters verringern die Summe, daher ist die Differenz von sci.sum() zur Eingabesumme genau "die am Rand verlorene Menge".
• wht —— Gewichtskarte derselben Form: von wie vielen Tropfen ein Ausgabepixel bedeckt ist (Ausgabepixelfläche = 1). Mit pixfrac=1 und shifts=0 ist das Innere exakt 1.0.
★ Zum Ansehen / Messen sci / wht verwenden. sci hält die "verteilte Menge" unverändert, um den Gesamtfluss zu erhalten, daher bleibt die ungleichmäßige Bedeckung im Bild erhalten. Bei kleinem pixfrac ist die Bedeckung gitterförmig ungleichmäßig, sodass Detektion auf dem rohen sci dieses Gitter in Sterne verwandelt —— gemessen (scale=3, pixfrac=0.4, 24 Frames von 1 Doppelstern): star_detect lieferte auf dem rohen sci 200 (am Limit festgefahren) und auf sci / wht korrekt 2. Erhaltungsgröße (sci) und Erscheinung (sci / wht) sind verschiedene Größen; die eine statt der anderen zu verwenden ist ausnahmslos falsch.
Raises ValueError: wenn *frames* keine list / tuple ist / die Formen nicht übereinstimmen / *scale* kleiner als 1 ist / *pixfrac* außerhalb von (0, 1] liegt / *shifts* nicht die Form (N, 2) hat / die Ausgabe MAX_OUTPUT_ELEMENTS überschreitet.
• Katalog der Beispieldaten (Download-URLs / Lizenzen) — 2-D nutzt skimage.data (BSD/Public Domain) plus synthetische Bilder, 3-D nennt Download-URLs echter Datenquellen (Stanford, PDS, …).
• Herkunft und Literatur der Operatoren — die Quellen der Forschung/Verfahren, auf denen diese Operatorfamilie beruht.
• Der kanonische Algorithmus (Autor, Jahr) und seine Anwendungen stehen im Familienleitfaden oben.
• astro_stacking — py -3.11 examples/astro_stacking.py
• poc_astro_photometry — py -3.11 examples/poc_astro_photometry.py
• poc_superresolution_limits — py -3.11 examples/poc_superresolution_limits.py
image2d als Eingabe)frame_quality · noise_sigma · cosmic_ray_reject · star_detect · psf_fit · aperture_photometry · frame_align
stack)*Provenance: astrostack.py — ASTROSTACK Operator-Registry. Diese Notiz wird von tools/opdocs.py md erzeugt (nicht von Hand bearbeiten).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.