pupil_blur — OPTICS wave op

• Data kinds: image2d × image2d → image2d

• Call: import fullseye as fs; fs.ledger.pupil_blur(image, pupil, defocus_waves=0.0, wavelength_um=0.55, f_number=5.6, pixel_pitch_um=5.0, oversample=4, opd_waves=None) (implementation को सीधे call करना हो तो import optics; optics.pupil_blur(image, pupil, defocus_waves=0.0, wavelength_um=0.55, f_number=5.6, pixel_pitch_um=5.0, oversample=4, opd_waves=None), registry से लेना हो तो opsoptics.get("pupil_blur"))

उपयोग

एक wavelength band पर pupil shape के PSF से image को blur करता है।

> नीचे का विस्तृत विवरण मूल text में है — सारांश और headings का अनुवाद हो चुका है।

The forward imaging model of *one* spectral band: the PSF of pupil_psf (same pupil / defocus / wavelength / f-number arguments), binned to the image's pixel pitch so the blur is in the image's own units, convolved with the image (FFT, reflect-padded borders so a flat field stays flat and nothing wraps around). Call it once per band with that band's defocus_waves (from defocus_from_shift and a focal shift versus wavelength) and you have the polychromatic image of a lens with longitudinal chromatic aberration seen through any pupil — the ingredient of the "colour from chromatic blur" hypothesis for single-photoreceptor eyes (Stubbs & Stubbs, *PNAS* 113:8206, 2016).

Returns a float64 image2d of the image's shape. Linear: no clipping, no re-normalisation of the image (the PSF sums to 1, so a constant image is returned unchanged to rounding).

Ground truth it reproduces (measured, tests/test_optics.py): a constant image is unchanged to 1e-12; a delta image returns the binned PSF itself (the impulse response, to 1e-12 where the kernel fits); with defocus_waves = 0 and a diffraction spot much smaller than the pixel (lambda N = 0.8 um on a 5 um pitch) a sharp edge is unchanged to within 1 % — the *identity at focus*; the blurred image's total is the input's total to 1e-9 (flux is conserved by the reflect padding).

Raises ValueError: everything pupil_psf raises, plus *image* not 2-D / smaller than 2x2 / over the size cap / complex / masked / non-finite, and a non-finite result (an FFT overflow).

Shift-invariant: one PSF for the whole field. Field-dependent blur (vignetting, off-axis aberration) is lensimage.render_through_lens.

पूरी family का input contract (fail-closed)

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।

उपयोग की विस्तृत guide

• optics_imaging family guide

संदर्भ (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 के स्रोत।

• Algorithm का मानक स्रोत (लेखक, वर्ष) और उपयोग ऊपर की family usage guide में दिए गए हैं।

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

• optics_imaging — py -3.11 examples/optics_imaging.py

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

fraunhofer_pattern · pupil_psf · psf_to_mtf · edge_spread · veiling_glare_index · emva_pair_statistics · emva_defect_pixels · polarization_demosaic

इसी category के (wave)

airy_pattern · angular_spectrum_propagate · fraunhofer_pattern · fourier_plane_filter · four_f_filter · gaussian_beam · defocus_from_shift · pupil_psf


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