fullseye

偏光カメラの生フレームを Stokes・DoLP・Mueller に読む

できること

偏光カメラ(画素の上に偏光子を載せた市販の偏光イメージセンサを使う機種)は 2×2 の画素ブロックに 0/45/90/135 度の偏光子を並べたモザイクを 1 枚で出します。polarization_demosaic がそれを 4 枚(0/45/90/135)に戻し(双線形。1 次の場は厳密に戻り、縁はモザイクを鏡映して位相を保つ)、そのまま polarization_stokes / polarization_dolp_map / polarization_separate に渡せます(角度の既定が一致しているので引数無しで繋がる)。センサの配列が違えば layout=((a00, a01), (a10, a11)) で渡します。カラー偏光センサ(4×4 ブロック)は polarization_demosaic_color が (4, H, W, 3) に戻します —— 各偏光子位置の画素は半解像度の Bayer なので raw_demosaic_bilinear で展開し、戻してから各チャネルを偏光 demosaic する(2 つの厳密な段の合成)。

試料の Mueller 行列は、既知の生成器(PSG)と検光子(PSA)の列で撮った強度から mueller_from_intensities が最小二乗で取り戻します。強度は 16 成分に線形なので観測行列 outer(a_i, g_i) を積んで解くだけです。★設計が S3 を見られないとき(偏光板だけ、階数 9)は階数を言って断り、擬似逆行列のもっともらしい答えを返しません。画像ごと(N, H, W)に渡せば画素ごとに解けます。

取り戻した行列が物理的か(Cloude の coherency 行列が半正定値)、純粋か(脱偏光しない)、どれだけ脱偏光しているか(Gil–Bernabeu 指数)、受動か(透過率 ≤ 1)は mueller_checks が一度に返します。数値は固有値ごと載せるので、「どれだけ非物理か」まで見えます。

What it does

Turn a polarisation camera’s mosaic (a 2×2 block of 0/45/90/135° analysers, as on commercial on-chip polarisation sensors) into four full-resolution images with polarization_demosaic (bilinear, exact on affine fields, phase-preserving mirrored border) that chain straight into polarization_stokes / polarization_dolp_map. Recover a sample’s Mueller matrix from intensities measured through known generator/analyser states with mueller_from_intensities (linear least squares on outer(a_i, g_i); refuses rank-deficient designs with the rank instead of returning a pseudo-inverse guess). Check any 4×4 matrix with mueller_checks: Cloude coherency eigenvalues (physical), purity, the Gil–Bernabeu depolarisation index and passivity.

向くところ / 向かないところ

向く: 偏光カメラの生フレームの前処理、鏡面反射と拡散の分離(polarization_separate)、偏光素子や試料の Mueller 行列の計測と健全性確認、光弾性・応力可視化の前段。

向かない: ★demosaic は双線形だけで、エッジ適応や勾配法はありません(輪郭では 1 画素幅のにじみが出ます)。★mueller_from_intensities は生成器・検光子が正確に既知である前提で、素子の誤差は結果にそのまま乗ります(較正は別の問題)。★mueller_checks の tol は測定雑音の水準で置いてください。雑音つきで回復した行列は最小固有値が僅かに負に出るのが普通で、tol を勘で小さくすると「非物理」に化けます(例で実演)。

最初の 1 本

import fullseye as fs
import numpy as np

raw = np.load("polarcam_frame.npy")                     # (H, W) のモザイク、値は [0, 1]
sweep = fs.polarization_demosaic(raw)                   # (4, H, W): I_0, I_45, I_90, I_135
dolp = fs.polarization_dolp_map(sweep)                  # 画素ごとの直線偏光度
print(fs.stokes_analyze(fs.polarization_stokes(sweep)))  # 場全体の Stokes → dop / azimuth

# Mueller: 既知の PSG / PSA(各 N 個の 4x4)で撮った N 個の強度から
M = fs.mueller_from_intensities(intensities, psg, psa)  # (4, 4)。階数 < 16 なら ValueError
print(fs.mueller_checks(M, tol=1e-3))                   # physical / pure / depolarization_index / passive

裏づけ