imaging op• Data kinds: image2d → pairs
• Call: import fullseye as fs; fs.ledger.psf_to_mtf(psf, pixel_pitch_um=1.0) (implementation को सीधे call करना हो तो import optics; optics.psf_to_mtf(psf, pixel_pitch_um=1.0), registry से लेना हो तो opsoptics.get("psf_to_mtf"))
measured point-spread function का radially-averaged MTF।
> नीचे का विस्तृत विवरण मूल text में है — सारांश और headings का अनुवाद हो चुका है।
OTF = FFT{PSF}, MTF = |OTF| / |OTF(0)|, then averaged over annuli of constant spatial frequency out to the Nyquist limit 1/(2*pitch). This is the measurement side of resolution: image a point source (or a slit, or differentiate a knife edge), hand the spot here, and compare the curve with the diffraction limit from mtf_diffraction.
Returns an (n, 2) float64 pairs array: column 0 the spatial frequency in cycles per millimetre, column 1 the MTF in [0, 1]. One row per non-empty radial bin (a very anisotropic array can leave a bin empty; those rows are dropped rather than filled with a NaN).
Ground truth it reproduces (measured): a delta PSF gives MTF == 1 at every frequency exactly (max deviation 0.0); a Gaussian PSF of sigma pixels gives the closed form exp(-2*pi^2*sigma^2*f^2) — the maximum absolute deviation over the whole curve is 4.1e-4 at sigma = 2 px on 128x128, 8.3e-4 at sigma = 1.5 px on 64x64 and 2.4e-4 at sigma = 3 px on 256x256 (the residual is the radial average over a square grid, not an error in the transform). Doubling *pixel_pitch_um* halves every reported frequency and leaves the MTF column bit-identical.
The PSF is not re-normalised or re-centred: a PSF whose energy is not centred carries a linear phase, which the modulus discards, so the MTF is unaffected — but the *phase* transfer function, which is where a decentred/asymmetric PSF shows up, is deliberately not summarised here.
Raises ValueError: *psf* is not 2-D / smaller than 2x2 / over the size cap / complex / masked / non-finite; a PSF that sums to zero or less (the DC normalisation would be 0/0 — an all-zero "PSF" is not a PSF); non-positive or non-finite *pixel_pitch_um*.
optics के सभी ops गणना से पहले input की जाँच करते हैं (कुछ भी चुपचाप पास नहीं होता):
• Unit argument के नाम में ही लिखी होती है — _mm / _um / _deg / _mrad। mm और µm की गड़बड़ी crash नहीं करती, बल्कि "सही दिखने वाला पर गलत उत्तर" देती है, इसलिए नाम से इसे रोका जाता है। मान के आकार से unit का अनुमान बिल्कुल नहीं लगाया जाता।
• String से ValueError — float('50') सफल हो जाता है, इसलिए बिना parse किया config value length के रूप में निकल जाता (मापा गया: thin_lens('50', '200') सही दिखने वाला 66.667 mm लौटा रहा था)। bool को भी True == 1 वाले implicit promotion के रूप में अस्वीकार किया जाता है।
• complex / masked array से ValueError (केवल real-valued slots; imaginary part को चुपचाप छोड़ना या mask हटाना अस्वीकार)। हर input पर NaN/Inf से ValueError।
• शून्य से भाग और उससे जुड़े मामलों को नाम लेकर अस्वीकार किया जाता है: focal length 0, radius of curvature 0, refractive index <= 0, पूरी तरह opaque aperture (सब 0, इसलिए normalisation 0/0), ऐसा PSF जिसका योग <= 0 हो, S0 = 0 वाला Stokes vector, और front focal point पर रखा object (image अनंत पर)।
• केवल 2 ops non-finite value लौटाते हैं, और वह भी contract के रूप में लिखा हुआ: depth_of_field hyperfocal distance से आगे far_mm = inf (hyperfocal distance की परिभाषा यही है) और gaussian_beam waist पर wavefront_radius_mm = inf (plane wavefront की radius of curvature)। दोनों साथ में एक finite साथी (far_is_infinite / curvature_per_mm) भी लौटाते हैं। इसके अलावा कोई भी चुपचाप आया NaN/Inf अंदर ही पकड़ा जाता है और ValueError देता है — "float64 overflow हुआ" और "उत्तर अनंत है" अलग-अलग दावे हैं, इसलिए पहले को दूसरे का चेहरा पहनाकर नहीं लौटाया जाता।
• Size की सीमा: generate होने वाले grid के लिए optics.MAX_GRID (4096), दिए गए field/PSF/aperture के लिए optics.MAX_FIELD_ELEMENTS (2^24), ABCD element chain के लिए optics.MAX_SYSTEM_ELEMENTS (1024), Zernike के लिए MAX_ZERNIKE_TERMS (512) / MAX_ZERNIKE_ORDER (40) / MAX_ZERNIKE_BASIS (2^25)। छोटे argument से बहुत बड़ा internal allocation होने वाले रास्तों (मापा गया: n_max=40 × 4096² पर 108 GB) को fail-closed ढंग से बंद किया गया है।
• भौतिक रूप से असंभव states भी अस्वीकार: degree of polarisation > 1 वाला Stokes vector, ऋणात्मक transmittance, ऋणात्मक intensity, और n-|m| odd जैसे अमान्य Zernike indices।
• measurement_uncertainty — Measurement uncertainty और calibration — 'हम माप रहे हैं' कहने के लिए क्या चाहिए
• mv_cameras — Industrial camera निर्माता (sensor mapping, line scan / TDI)
• virtual_machine_vision — Virtual machine vision — parameters की सूची और एक object model
• 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 में दिए गए हैं।
• optics_imaging — py -3.11 examples/optics_imaging.py
• poc_veiling_glare — py -3.11 examples/poc_veiling_glare.py
pairs को input के रूप में लेते हैं)imaging)mtf_diffraction · wavefront_stats · edge_spread · sfr_from_edge · mtf50 · veiling_glare_index
*Provenance: optics.py — OPTICS operator registry. यह per-op note tools/opdocs.py md से अपने-आप generate होता है (हाथ से edit न करें)।*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.