polarization op• Datenarten: image2d → polsweep
• Aufruf: import fullseye as fs; fs.ledger.polarization_demosaic(raw, layout=((90.0, 45.0), (135.0, 0.0))) (die Implementierung direkt: import optics; optics.polarization_demosaic(raw, layout=((90.0, 45.0), (135.0, 0.0))); aus dem Register: opsoptics.get("polarization_demosaic"))
Zerlegt das Mosaik eines Polarisationssensors in die vier Analysatorbilder (0/45/90/135 Grad).
> Die ausführliche Beschreibung unten ist der Originaltext — Zusammenfassung und Überschriften sind übersetzt.
A polarisation camera puts four micro-polarisers on each 2x2 block of
pixels; the raw frame is one (H, W) array in which neighbouring pixels saw
the scene through different analysers. This returns a `(4, H, W)` array
of images `[I_0, I_45, I_90, I_135] (the polsweep` sort, in
:data:POLARIZATION_SWEEP_ANGLES order, so the result feeds
:func:specularity.polarization_stokes and `polarization_dolp_map`
directly), each interpolated to full resolution.
Interpolation is bilinear, the same estimate a Bayer demosaic makes for
a colour plane that occupies one pixel in four: a missing pixel is the mean
of its measured 4-neighbours (edge-adjacent) or 4-neighbours (diagonal),
which is exactly the `[[1, 2, 1], [2, 4, 2], [1, 2, 1]] / 4` kernel applied
to the masked plane. Ground truth: on a plane that is linear in x and y
the interpolation is exact (a bilinear estimate of an affine field is the
field), so the test plants four affine fields, mosaics them, and demands
every returned image equal its field to 1e-12 away from the border. The
border is handled by mirroring the mosaic two pixels outward before
interpolating (an even, non-duplicating reflection keeps the 2x2 phase), so
a uniform field is exact up to the edge and a gradient is mirrored there —
a symmetric bias on the outermost row and column, and said so. Against
Polanalyser's OpenCV bilinear path the interior agrees to the 16-bit
quantisation (1.8e-5) and only the outer two pixels differ (2026-09-18).
*layout* is the angle at each 2x2 position, `((a00, a01), (a10, a11))` in
degrees; the default is the Sony IMX250MZR block. Every angle in
:data:POLARIZATION_SWEEP_ANGLES must appear exactly once.
Raises `ValueError`: *raw* is not a 2-D array, has an odd height or
width (the block would be cut), contains non-finite values, or *layout* is
not a permutation of the four sweep angles.
Provenance: the layout convention and the "four Bayer planes" reading of
the mosaic follow Polanalyser (Maeda, MIT); the interpolation is the
classic bilinear Bayer demosaic. This is a re-implementation from that
description, not copied code, and it does not depend on OpenCV. Colour
polarisation sensors (IMX250MYR, a 4x4 block) are handled by
:func:polarization_demosaic_color.
Jeder optics-Operator prüft seine Eingabe vor der Berechnung (nichts rutscht stillschweigend durch):
• Einheiten stecken im Argumentnamen — _mm / _um / _deg / _mrad. Eine Verwechslung von mm und µm stürzt nicht ab, sondern liefert eine plausibel aussehende falsche Antwort; der Name verhindert das. Aus der Größenordnung wird nie auf die Einheit geschlossen.
• **Strings lösen ValueError aus** — float('50') gelingt, sodass ein ungeparster Konfigurationswert als Länge durchrutschen würde (gemessen: thin_lens('50', '200') lieferte plausible 66,667 mm). bool wird als implizite Hochstufung True == 1 ebenfalls abgelehnt.
• **complex / Masked Arrays lösen ValueError aus (nur reelle Slots; das stille Verwerfen des Imaginärteils bzw. Abstreifen der Maske wird abgelehnt). NaN/Inf löst bei jeder Eingabe ValueError aus.**
• Division durch null und Verwandtes wird namentlich abgelehnt: Brennweite 0, Krümmungsradius 0, Brechzahl <= 0, undurchlässige Blende (alles 0, die Normierung wird 0/0), PSF mit Summe <= 0, Stokes-Vektor mit S0 = 0 und ein Objekt im vorderen Brennpunkt (Bild im Unendlichen).
• Nur zwei Operatoren liefern einen nicht-endlichen Wert, und beide halten das vertraglich fest: depth_of_field liefert jenseits der hyperfokalen Distanz far_mm = inf (genau das bedeutet die hyperfokale Distanz), und gaussian_beam liefert an der Taille wavefront_radius_mm = inf (der Krümmungsradius einer ebenen Wellenfront). Beide liefern zusätzlich einen endlichen Partner (far_is_infinite / curvature_per_mm). **Jedes andere stille NaN/Inf wird intern erkannt und löst ValueError aus** — "float64 ist übergelaufen" und "die Antwort ist unendlich" sind verschiedene Aussagen; die erste wird nie im Gewand der zweiten geliefert.
• Größenobergrenzen: erzeugte Gitter durch optics.MAX_GRID (4096), übergebene Felder/PSFs/Blenden durch optics.MAX_FIELD_ELEMENTS (2^24), ABCD-Elementketten durch optics.MAX_SYSTEM_ELEMENTS (1024), Zernike durch MAX_ZERNIKE_TERMS (512) / MAX_ZERNIKE_ORDER (40) / MAX_ZERNIKE_BASIS (2^25). Damit werden Pfade fail-closed geschlossen, in denen ein kleines Argument eine riesige interne Allokation auslöst (gemessen: n_max=40 × 4096² braucht 108 GB).
• Physikalisch unmögliche Zustände werden ebenfalls abgelehnt: Stokes-Vektor mit Polarisationsgrad > 1, negative Transmission, negative Intensität und ungültige Zernike-Indizes wie ungerades n-|m|.
• Leitfaden zur Familie optics_imaging
• Katalog der Beispieldaten (Download-URLs / Lizenzen) — 2-D nutzt skimage.data (BSD/Public Domain) plus synthetische Bilder, 3-D nennt Download-URLs echter Datenquellen (Stanford, PDS, …).
• Herkunft und Literatur der Operatoren — die Quellen der Forschung/Verfahren, auf denen diese Operatorfamilie beruht.
• Der kanonische Algorithmus (Autor, Jahr) und seine Anwendungen stehen im Familienleitfaden oben.
• polarization_camera_pipeline — py -3.11 examples/polarization_camera_pipeline.py
polsweep als Eingabe)—
polarization)jones_element · jones_apply · stokes_from_jones · mueller_element · mueller_apply · stokes_analyze · polarization_demosaic_color · mueller_from_intensities
*Provenance: optics.py — OPTICS Operator-Registry. Diese Notiz wird von tools/opdocs.py md erzeugt (nicht von Hand bearbeiten).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.