frame_align — ASTROSTACK align op

• Datenarten: image2d × image2d → matrix

• Aufruf: import fullseye as fs; fs.ledger.frame_align(reference, frame, model='similarity', threshold_sigma=5.0, max_stars=60, tolerance_px=2.0, max_shift_px=None, ransac_iters=500, seed=0, min_inliers=3) (die Implementierung direkt: import astrostack; astrostack.frame_align(reference, frame, model='similarity', threshold_sigma=5.0, max_stars=60, tolerance_px=2.0, max_shift_px=None, ransac_iters=500, seed=0, min_inliers=3); aus dem Register: opsastrostack.get("frame_align"))

• Rückgabewert über das Register: fullseye.ledger.frame_align(...) liefert nur den Wert des deklarierten Out-Typs matrix (die zugrunde liegende Funktion gibt zusätzlich Hilfsinformationen zurück). Wird das Verworfene gebraucht, nutze fullseye.ledger.frame_align.raw(...) oder rufe astrostack.frame_align direkt auf.

• Rückgabe der Funktion: (matrix, info) -> matrix

Verwendung

Schätzt die 2-D-Transformation frame → reference aus Sternkorrespondenzen.

Der Ablauf hat 3 Stufen, und der Kern jeder Schätzung ist ein bestehendes op:

1. star_detect erfasst die Sterne in beiden Bildern.

2. Eine grobe Translation wird per Versatz-Abstimmung bestimmt (_vote_translation). Dass hier nicht features.match_keypoints verwendet wird, ist eine auf Messung beruhende Entscheidung:

9x9-Patches eines Sternfelds sehen einander fast gleich aus, daher verwirft Lowes Verhältnistest

(Default ratio=0.8) fast alle. 128x128 mit 40 Sternen, wahrer Versatz

(+0.590, -0.540) px, gemessen an einem Framepaar: match_keypoints

lieferte 4 Zuordnungen, davon 0 innerhalb 1 px der Ground Truth (= keine einzige

brauchbare). Am selben Paar ergibt die Abstimmung 26 Stimmen → 26 Zuordnungen → 26 Inlier, Schätzfehler

0.0155 px. Einem Sternfeld "fehlen" nicht die Merkmale, sondern "alle Merkmale sind gleich", daher

ist es richtig, die Geometrie der Anordnung statt Deskriptoren zu verwenden.

3. Mit der groben Verschiebung werden Zuordnungen per nächstem Nachbarn gebildet, mosaic.proj_match_points_ransac verwirft Fehlzuordnungen, und fit_transform.vector_to_similarity (je nach model vector_to_rigid / vector_to_hom_mat2d) passt an. Weder eine RANSAC-Schleife noch Umeyama ist hier geschrieben.

★Für repetitive Strukturen nicht verwendbar (2026-09-08, entdeckt von poc_print_registration). inlier_ratio ist "der Anteil der Zuordnungen, die für dieselbe Antwort gestimmt haben", nicht "die Wahrscheinlichkeit, dass die Antwort richtig ist". In Bildern, in denen dieselbe Form periodisch wiederkehrt, wie Rasterpunkte, Gewebe oder Gitter, stimmen auch einer um einen Gittervektor verschobenen Zuordnung alle zu, sodass die Zustimmungsrate bei 1.00 bleibt, während allein die Antwort um eine Gitterperiode (oder mehrere) daneben liegt.

Gemessen: bei einem Paar 256x256-Rasterpunkte, entsprechend 133 lpi unter 15 Grad, verschoben um nur (0.00, +1.30) px, liefert es inlier_ratio 1.00 / rms_px 0.78, während die Schätzung (+54.24, +30.12) px ist. Im Sternfeld (128x128, 40 Sterne, Ground Truth (+0.59, -0.54)) ist inlier_ratio ebenfalls 1.00 und die Schätzung korrekt. Die Zustimmungsrate kann die 2 nicht unterscheiden.

Unterscheiden kann sie vote_margin —— die Höhe des Gipfels auf Rang 2 der Abstimmung geteilt durch den auf Rang 1; 0 heißt ein einziger Gipfel, je näher an 1, desto mehr "gibt es andere, ebenso plausible Antworten". An denselben 2 Beispielen: Rasterpunkte 0.857 / Sternfeld 0.143. Auf Pfaden, die periodische Strukturen erhalten könnten, diesen Wert statt inlier_ratio ansehen. Wird nur die Translation selbst gebraucht, ist die Korrelationsfläche von piv_cross_correlate direkter; dort kann man selbst zählen, wie viele Gipfel stehen.

*model* "translation" verwendet nur den Median der Zuordnungsdifferenzen (funktioniert schon mit 1 Stern). "rigid" = Rotation + Translation, "similarity" = + isotrope Skalierung, "affine" = 6 Freiheitsgrade. Solange das Sichtfeld nicht weit ist, genügt "similarity" (Nachführfehler einer äquatorialen Montierung sind Rotation und Translation; die atmosphärische Refraktion geht in erster Ordnung in die Skalierung ein).

Returns (matrix, info):

• matrix —— (3, 3) float64. Von links mit (row, col, 1) multipliziert ergibt es Koordinaten in reference (gleiche Konvention wie fit_transform).

• info —— dict. n_stars_ref / n_stars_src / n_pairs / n_inliers / inlier_ratio / shift_row / shift_col / rotation_deg / scale / rms_px (Residuen-RMS der Inlier) / model.

fail-closed: erreichen die Inlier *min_inliers* nicht, wird ValueError ausgelöst. Es wird nicht still die Identität zurückgegeben —— einen Frame mit fehlgeschlagener Registrierung als "Versatz 0" in einen Stapel zu mischen erzeugt ohne Ausnahme oder Warnung ein Doppelbild.

Raises ValueError: wenn nicht 2-D / Formen verschieden / *model* nicht in ALIGN_MODELS / in einem der Bilder kein einziger Stern gefunden / keine Zuordnungen bildbar / zu wenige Inlier.

Referenzen (Beispieldaten, Literatur)

• 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.

Ausführbare Beispiele (verifizierte Samples, die diesen Operator wirklich aufrufen)

• astro_stacking — py -3.11 examples/astro_stacking.py

• poc_exoplanet_transit — py -3.11 examples/poc_exoplanet_transit.py

• poc_print_registration — py -3.11 examples/poc_print_registration.py

Typkompatible Folge-Operatoren (nehmen matrix als Eingabe)

—

Gleiche Kategorie (align)

align_frames


*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.