render_through_lens — OPTICS imaging_sim op

• Data kinds: image2d × table → image2d

• Call: import fullseye as fs; fs.ledger.render_through_lens(image, system, pixel_pitch_um=5.5, field_of_view=None, zones=3, noise=None, seed=0, illumination='traced', size=None, oversample=None) (implementation को सीधे call करना हो तो import lensimage; lensimage.render_through_lens(image, system, pixel_pitch_um=5.5, field_of_view=None, zones=3, noise=None, seed=0, illumination='traced', size=None, oversample=None), registry से लेना हो तो opsoptics.get("render_through_lens"))

उपयोग

ideal irradiance image को वैसा render करता है जैसा *system* के पीछे का sensor record करेगा (image2d)।

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

*image* (H×W, non-negative) is the ideal (paraxial) image on a sensor of *pixel_pitch_um* pixels centred on the optical axis; with *field_of_view* (half field to the sensor corner: degrees for an object at infinity, object height in mm otherwise) the picture is first zoomed so the corner sees that field. Pipeline: (a) inverse distortion remap (distortion_map grid, scipy.ndimage.map_coordinates order 1); (b) spatially varying blur — a zones×zones lattice of tile centres, each with its own pixel-integrated psf_from_opd (the +y-field PSF rotated to the tile azimuth), blended with bilinear (tent) weights so seams vanish; (c) relative illumination: "traced" = fraction of the field's ray bundle that reaches the image (vignetting, from raytrace.ray_bundle) normalised to the axis, times cos⁴ (obliquity, objects at infinity only), "cos4" = the classic law alone, "none"; (d) sensor, when *noise* is True or a dict {"full_well": 20000, "read_e": 3.0, "bits": 12, "exposure": 1.0, "dark_e": 0.0}: electrons = irradiance × exposure × full_well, Poisson shot noise (photoncount.photon_sample), Gaussian read noise, quantisation to *bits*, returned as DN/(2^bits − 1). With noise=None the float irradiance is returned untouched (deterministic; the noisy path is deterministic for a given *seed* too).

*oversample* defaults to whatever keeps at least 2 PSF samples per pixel (max(4, ceil(2·λ·F#/pitch))). Ground truth: a δ image through the f/2 paraboloid gives the pixel-integrated Airy PSF; a checkerboard through it comes back undistorted (correlation > 0.99); energy is conserved to 1 % with illumination off; noise off is bit-reproducible.

पूरी 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

पृष्ठभूमि guides (इस op के पीछे की physics और conventions)

• mv_cables — Cables (standards, speed, power delivery, robot cables)

• mv_cameras — Industrial camera निर्माता (sensor mapping, line scan / TDI)

• mv_frame_grabbers — Frame grabber boards (optics नहीं, पर यही तय करते हैं कि capture हो भी सकता है या नहीं)

• mv_image_sensors — Industrial image sensors (मुख्यतः मौजूदा products)

• mv_standards — Camera interface standards और उनके पीछे की संस्थाएँ

• virtual_machine_vision — Virtual machine vision — parameters की सूची और एक object model

संदर्भ (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 करते हैं)

• lens_defect_dataset_demo — py -3.11 examples/lens_defect_dataset_demo.py

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

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

इसी category के (imaging_sim)

psf_from_opd · distortion_map · defect_dataset · calibration_views


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

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