fit_zernike — 3D curvilinear op

• Data kinds: image2d → table

• Call: import fullseye as fs; fs.ledger.fit_zernike(disk_image, n_max=6, device='cpu', nr=48, nt=72, center=None, radius=None) (implementation को सीधे call करना हो तो import match3d; match3d.fit_zernike(disk_image, n_max=6, device='cpu', nr=48, nt=72, center=None, radius=None), registry से लेना हो तो ops3d.get("fit_zernike"))

• GPU: इस op का GPU path है (device="cuda")

उपयोग

disc image → Zernike coefficients (optics/wavefront मापन का polar coordinate surface approximation)। return value {(n,m): coef}।

orthogonal polynomials से disc पर की surface (wavefront aberration, lens का आकार) को कुछ coefficients में बदलता है। tilt/defocus/astigmatism/ coma/spherical आदि विशिष्ट (n,m) से मेल खाते हैं, और rotation से m मिल जाते हैं (band = rotation invariant)।

pupil (unit disc ρ=1) default रूप से image के केंद्र ((H-1)/2, (W-1)/2) पर, त्रिज्या min(H, W)/2 - 1 pixel के साथ रखा जाता है। image का pupil इससे अलग हो तो center=(row, col) और radius (pixel) दें —— न देने पर त्रिज्या का अंतर सीधे low-order modes में leakage बन जाता है (129×129 पर pupil त्रिज्या (H-1)/2 वाले शुद्ध defocus को default से पढ़ने पर (2,0)=0.984 / (0,0)=−0.015, radius=(H-1)/2 देने पर 0.999998)। जिस center / radius का pupil वृत्त image से बाहर निकले, वह ValueError है।

honest प्रकटीकरण (2026-10-07 सुधार): पहले यहाँ लिखा था "discrete sampling (nr=48, nt=72) से अधिकतम ~10% का crosstalk, nr/nt बढ़ाने से घटता है", पर कारण resolution नहीं था। यदि pupil की त्रिज्या और केंद्र मेल खाते हों और pupil के बाहर भी मान जारी रहें, तो default nr/nt से coefficient लगभग 1 (129×129 पर 0.999998) पर लौट आते हैं। leakage के वास्तविक कारण हैं

(1) ऊपर बताया pupil त्रिज्या और केंद्र का अंतर (nr/nt बढ़ाने पर भी 1 order भी नहीं घटता), और (2) pupil के बाहर 0 वाली image में

सबसे बाहरी ring (ρ=1) किनारे पर पड़ती है और bilinear interpolation बाहर के 0 को खींच लेता है (examples/poc_zernike_aberrations.py का माप)।

★सुधार 2026-10-14 (क्षेत्रफल भार): पहले polar grid (ρ को 0..1 पर समान अंतराल) को बिना भार के least squares से हल किया जाता था। हर ring में samples की संख्या समान होने से छोटे क्षेत्रफल वाला केंद्र ज़्यादा गिना जाता था और कटे हुए ऊँचे क्रम नीचे के क्रमों में रिसते थे (Z80 + 0.3·Z20 को n_max=4 से पढ़ने पर Z40 = 0.39, सही projection 0 है)। अब ρ को nr Gauss–Legendre nodes (0 और 1 को छोड़कर) पर रखा जाता है और भार w_i·ρ_i (क्षेत्रफल तत्व ρ dρ dθ) से हल किया जाता है —— band के भीतर के polynomial का projection सटीक होता है। कोई node ρ = 1 पर नहीं पड़ता, इसलिए pupil के बाहर 0 वाली image में किनारे का 0 कम खिंचता है (पूरी तरह नहीं मिटता: bilinear interpolation का दायरा किनारे के पार रहता है)।

Raises ValueError: इनपुट 2-D न हो, 2x2 से छोटा हो, NaN/Inf/float32 overflow हो, या pupil image से बाहर निकले।

संदर्भ (sample data, साहित्य)

• 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 के स्रोत।

चलाए जा सकने वाले उदाहरण (verified samples जो सच में यह op call करते हैं)

• curvilinear_proj — py -3.11 examples_3d/curvilinear_proj.py

वे अगले ops जिनसे type जुड़ता है (table को input के रूप में लेते हैं)

fuse_to_voxel · mesh_select_lod

इसी category के (curvilinear)

polar_unwrap · cylinder_unwrap


*Provenance: match3d.py — 3D operator registry. यह per-op note tools/opdocs.py md से अपने-आप generate होता है (हाथ से edit न करें)।*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.