fullseye

偏光 4 方向で鏡面反射を除く(誘電体と金属で分ける)

できること

偏光板を 0/45/90/135° に回した 4 枚(または DoFP センサの 4 画素)から、画素ごとに Malus の正弦波を当てはめ、無偏光成分(2·I_min)と直線偏光成分(I_max − I_min)に分けます。前者を拡散・後者を鏡面と呼ぶのは物理的仮定で、それが成り立つ誘電体と成り立たない金属を、この項目は分けて扱います。

What it does

Fit Malus’s law per pixel to a 0/45/90/135° polariser sweep and split the radiance into its unpolarised part (2·I_min) and its linearly polarised part (I_max − I_min). Calling those “diffuse” and “specular” is a physical assumption that holds for dielectrics near Brewster’s angle and fails for metals; this entry keeps the two cases apart.

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

向く: 誘電体(塗装・樹脂・ガラス・濡れた面)で、入射角を Brewster 角(brewster_angle_deg、n=1.5 で 56.3°)の近くに置けるとき。テクスチャがあっても多材質でも効く(色による分離と違い光源色が要らない)。

向かない: ★金属。鏡面反射の偏光度 p は fresnel_conductor の (R_s − R_p)/(R_s + R_p) で 1 に届かず、(1−p)·S が diffuse に残る —— 「鏡面を除いた」つもりの像にハイライトが残る。★法線入射(p → 0)。★フレーム列と角度列の対応は配列から検証できない(等間隔角度の並べ替えは別の方位の正しい掃引に見え、違反率 0 のまま通る —— 2026-09-15 に全順列で実測)。

推奨パイプライン

polarization_dolp_map → polarization_separate → polarization_stokes → stokes_analyze → specular_diffuse_split

polarization_dolp_map で偏光板を付ける価値があるかを先に見る(DoLP ≈ 0 なら露出を 1 段失うだけ)→ polarization_separate で (diffuse, specular) → polarization_stokes → stokes_analyze で場面の偏光度と方位を数字に。金属で残った鏡面は色の経路 specular_diffuse_split(二色性モデル、RGB 入力)で追う —— 2 つの経路は相補で、代替ではない。

代替

材質が分かっているなら先に fresnel_dielectric / fresnel_conductor で s/p の反射率を計算し、p = (R_s − R_p)/(R_s + R_p) から残る鏡面の量を予測する。色の経路は specular_free_transform / specular_coefficient_map。

限界

実寸校正

画素 → mm は不要。校正に相当するのは偏光板の角度の原点(方位は原点に相対)と max_violation_frac(暗部の雑音床から決める。3 σ を切る画素の割合を見積もり、その程度に置く)。

最初の 1 本

import fullseye as fs
import numpy as np

d = np.full((64, 64), 0.4); s = np.zeros((64, 64)); s[24:40, 24:40] = 0.5
frames = fs.ledger.polarization_render(d, s, (0, 45, 90, 135), azimuth_deg=30.0)
print("DoLP max", float(np.asarray(fs.ledger.polarization_dolp_map(frames)).max()))
diffuse, specular = fs.ledger.polarization_separate.raw(frames)
print("残った鏡面", float(np.abs(diffuse - d).max()))     # 誘電体の仮定どおりなら ~0

裏づけ