align op• Data kinds: image2d × image2d → matrix
• Call: 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) (implementation को सीधे call करना हो तो 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), registry से लेना हो तो opsastrostack.get("frame_align"))
• Ledger के ज़रिए return value: fullseye.ledger.frame_align(...) केवल घोषित out type matrix का value लौटाता है (मूल function सहायक जानकारी भी लौटाता है)। जो हिस्सा छोड़ दिया गया है उसकी ज़रूरत हो तो fullseye.ledger.frame_align.raw(...) का उपयोग करें, या astrostack.frame_align को सीधे call करें।
• मूल function का return: (matrix, info) -> matrix
तारों की correspondence से frame → reference का 2-D transform अनुमानित करता है।
Process के 3 stage हैं, और हर estimate का मूल एक मौजूदा op है:
1. star_detect दोनों images में stars ढूँढता है।
2. एक मोटा translation offset voting (_vote_translation) से मिलता है।
यहाँ features.match_keypoints का इस्तेमाल न करना measurement पर आधारित निर्णय है:
star field के 9x9 patches एक-दूसरे जैसे लगभग एक जैसे दिखते हैं, इसलिए Lowe का ratio test
(default ratio=0.8) लगभग सभी को हटा देता है। 40 stars वाला 128x128, true offset
(+0.590, -0.540) px, एक frame pair पर measured: match_keypoints ने
4 correspondences लौटाए, जिनमें से 0 ground truth के 1 px के अंदर थे (= एक भी
इस्तेमाल लायक नहीं)। उसी pair पर voting method देता है 26 votes → 26 correspondences → 26 inliers, estimation error
0.0155 px। Star field में "features की कमी" नहीं है; "उसके सारे features एक जैसे हैं", इसलिए
सही तरीका descriptors नहीं, बल्कि arrangement की geometry का इस्तेमाल करना है।
3. मोटे shift से nearest-neighbour correspondences बनाए जाते हैं, mosaic.proj_match_points_ransac गलत correspondences हटाता है, और fit_transform.vector_to_similarity (model के अनुसार, vector_to_rigid / vector_to_hom_mat2d) fit करता है। यहाँ न RANSAC loop लिखा गया है और न Umeyama।
★Repetitive structures पर इस्तेमाल लायक नहीं (2026-09-08, poc_print_registration से मिला)। inlier_ratio "उन correspondences का हिस्सा है जिन्होंने एक ही उत्तर को vote दिया", न कि "उत्तर के सही होने की probability"। Halftone dots, कपड़े या grids जैसी images में जहाँ एक ही shape periodic रूप से दोहराती है, lattice vector जितना खिसका matching भी सबकी सहमति पाता है, इसलिए agreement ratio 1.00 पर ही रहता है जबकि केवल उत्तर एक lattice period (या कई) से गलत होता है।
Measured: 15 degrees पर 133 lpi के समकक्ष 256x256 halftone dots के एक pair पर, जो (0.00, +1.30) px खिसका है, यह inlier_ratio 1.00 / rms_px 0.78 लौटाता है जबकि estimate (+54.24, +30.12) px है। Star field पर (128x128, 40 stars, ground truth (+0.59, -0.54)) inlier_ratio वही 1.00 है और estimate सही है। Agreement ratio इन 2 में फ़र्क नहीं कर सकता।
जो फ़र्क कर सकता है वह vote_margin है —— vote के 2nd peak की ऊँचाई को 1st से भाग; 0 का अर्थ एक ही peak, और 1 के जितना पास, उतना "दूसरे समान रूप से संभव उत्तर भी हैं"। उन्हीं 2 उदाहरणों पर: halftone 0.857 / star field 0.143। जिन paths पर periodic structures आ सकते हैं, वहाँ inlier_ratio की बजाय इसे देखें। अगर केवल translation चाहिए, तो piv_cross_correlate की correlation surface देखना ज़्यादा सीधा है, जहाँ आप खुद गिन सकते हैं कि कितने peaks खड़े हैं।
*model* "translation" केवल correspondence differences का median इस्तेमाल करता है (1 star पर भी काम करता है)। "rigid" = rotation + translation, "similarity" = + isotropic scale, "affine" = 6 degrees of freedom। जब तक field of view चौड़ा न हो, "similarity" काफ़ी है (equatorial-mount का tracking error rotation और translation है; atmospheric refraction first order में scale में आता है)।
(matrix, info) लौटाता है:
• matrix —— (3, 3) float64। (row, col, 1) को बाईं ओर से गुणा करने पर reference में coordinates मिलते हैं (fit_transform जैसी ही convention)।
• info —— dict। n_stars_ref / n_stars_src / n_pairs / n_inliers / inlier_ratio / shift_row / shift_col / rotation_deg / scale / rms_px (inliers का residual RMS) / model।
fail-closed: अगर inliers *min_inliers* से कम हों, तो ValueError raise होता है। यह चुपचाप identity नहीं लौटाता —— जिस frame का registration विफल हुआ उसे "offset 0" मानकर stack में मिलाने से बिना exception या warning के double image बनती है।
Raises ValueError: अगर 2-D नहीं है / shapes अलग हैं / *model* ALIGN_MODELS में नहीं है / किसी भी image में एक भी star नहीं मिला / कोई correspondence नहीं बन सका / पर्याप्त inliers नहीं हैं।
• Sample data catalog (DL URL / license) — 2-D के लिए skimage.data (BSD/public) + synthetic, 3-D के लिए real data sources (Stanford/PDS आदि) के DL URL।
• Operators का स्रोत और संदर्भ — इस op family के मूल research/methods के स्रोत।
• Algorithm का मानक स्रोत (लेखक, वर्ष) और उपयोग ऊपर की family usage guide में दिए गए हैं।
• 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
matrix को input के रूप में लेते हैं)—
align)*Provenance: astrostack.py — ASTROSTACK operator registry. यह per-op note tools/opdocs.py md से अपने-आप generate होता है (हाथ से edit न करें)।*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.