Newer
Older
SmTIAS-LightSim / docs / 04_SPEC / SPEC_04_評価仕様.md
@rintoHasegawa rintoHasegawa on 1 Jun 19 KB [add] S3 Step D sm-evaluate に動径 min/max 比を統合 — S3 方針見直し: 「sm-evaluate に DNG 入力経路を追加」当初案は不採用 (実機 DNG 評価は MiniTias-Evaluation の本業で完結.SmTIAS-LightSim 側で重複実装する必要なし).S3 を 3 項目に絞り込み: Step D (sm-evaluate に動径 min/max 比統合) + Step C' (新規シミュ baseline config 作成) + Step G (シミュ再評価 → Step 8-13 として TEST_01 記録).本コミットは Step D.MetricsConfig.radial_min_max: bool = False をスキーマ追加 (schema.py),cli/evaluate.py で _run_radial_min_max() 関数追加・main() 内で算出ステップ統合・_print_summary に代表 2 行追加.radial_profile を再利用 (重複算出回避),未算出時 (radial_profile: false) は関数内部で calc_radial_profile を呼んで自力算出 → 独立有効化可能.metrics.radial_min_max: true 時に metrics.csv 末尾に 4 列 (radial_min_max_ratio / radial_min_distance / radial_min / radial_max) を追加,既存列順序は不変で後方互換維持.既定 False で既存 3 configs (eval_baseline.yaml / eval_baseline_linear.yaml / eval_real.yaml) は無修正で動作.新規テスト 39 件追加 (tests/scene/test_metrics_radial_min_max_schema.py 250 行: A1-A4 スキーマ仕様 + tests/cli/test_evaluate_radial_min_max.py 740 行: B1-B5 関数仕様 + C1-C5 CLI 統合 + D2 slow 統合).既存 569 + 新規 39 = 608 件全通過.Refactorer 判断: プロダクションコード変更なし (既存パターン一貫性あり),テストコードのみ軽微な lint 修正 (未使用 import 削除・I001/E501).SPEC_04 §動径 min/max 比 (オプション) セクション新規追加 (4 列出力・nan 除外・独立有効化の仕様明記.evaluation/radial.py:calc_radial_min_max_ratio は MiniTias-Evaluation src/analysis/spatial.py からのマージと明記).CLAUDE.md 進捗欄に S3 方針見直しと Step D 完了 (608 件全通過) を追記.handoff_smtias_lightsim/ ディレクトリは S3 全体完了後に削除予定で本コミットには含めない.次フェーズ: Step C' (configs/eval_baseline_dng_target.yaml 作成: 既存 eval_baseline_linear.yaml ベース,target_mean=207.82,radial_min_max=true) → Step G (Step 8-13 計測)

評価仕様 (Evaluation Specification)

sm-evaluate CLI が担う シミュレーション結果 / 実測 PNG の照明均一性評価 の方法論を定義する.本書はアルゴリズム・物理動機・規約をまとめ,実装の根拠(why)と入出力(what)を記述する.評価設定 YAML のスキーマ詳細は SPEC_02_シーン定義仕様 の evaluation セクションを参照.

関連:

概要 (Overview)

シミュレーション結果(output/<run>/luminance.npy または render_uint8.png)と実測 PNG (reference_measurement/.../*.png) を 同一の評価パイプラインに通し,無次元の均一性指標(CoV,勾配 %,中心/周辺比 等)を算出する.シミュと実測を比較可能にする鍵は OETF 順方向適用 で,シミュの linear ドメインを実機の sRGB 符号化ドメインに揃える操作である(後述).

設計目的は MiniTias-Evaluation との 数値整合性(実測 PNG に対し小数点 14 桁レベルで一致確認済み,TEST_01 既知差分 #9)と,シミュ⇄実測の 公平な比較.

評価パイプライン (Evaluation Pipeline)

入力 (PNG / luminance.npy)
    │
    ▼  uint8 PNG → 0..255 配列, luminance.npy → float32 配列のまま
[1] 読み込み
    │
    ▼  Rec.709 加重和 Y = 0.2126R + 0.7152G + 0.0722B (RGB 入力時)
[2] luma 変換
    │
    ▼  ROI 設定 (image_pixel 型) に従い (x, y, width, height) 領域を切り出す
[3] ROI 抽出
    │
    ▼  normalization.enabled = true のとき: linear ドメインで mean を target_mean に揃える線形ゲイン
[4] mean 正規化 (任意・linear モード用、OETF と排他)
    │
    ▼  oetf.enabled = true のとき: 標準 sRGB OETF を順方向適用 + 実測 mean アンカー
[5] OETF 順方向適用 (任意・シミュ用、normalization と排他)
    │
    ▼  (任意) quantize_uint8: float → uint8 量子化
[6] 量子化
    │
    ▼  CoV, std, max-min, mean, max, min を計算
[7] 全体指標
    │
    ▼  3 ゾーン分類 (center/middle/periphery) → 中心/周辺比,勾配 %
[8] ゾーン指標
    │
    ▼  20 ビンの放射状プロファイル
[9] 動径指標
    │
    ▼  metrics.csv, figures/{luminance_map, histogram, radial_profile, zone_map}.png
[10] 出力

各ステージの実装は以下のモジュールに分かれる:

ステージモジュール
1 読み込みcli/evaluate.py(PNG: PIL,npy: numpy)
2 luma 変換uniformity.py(Rec.709 加重和)
3 ROI 抽出evaluation/roi.py
4 mean 正規化evaluation/normalize.py
5 OETFevaluation/oetf.py
6-8 指標uniformity.py + evaluation/zones.py
9 動径evaluation/radial.py
10 可視化evaluation/visualize.py

ROI 仕様 (Region of Interest)

評価板の 撮影範囲内の有効領域 を矩形で切り出す.評価設定 YAML の roi セクションで指定する.

image_pixel 型

実測 PNG の座標系(左上原点,X 右,Y 下)で 絶対ピクセル座標を直接指定する.シミュ画像と実測画像で 物理対応する同じ領域を切り出すために,シミュ側の ROI は実測 ROI の物理対応関係から決定する.

roi:
  type: image_pixel
  x: 24          # 左上 X
  y: 37          # 左上 Y
  width: 464
  height: 450

実機 ⇄ シミュの物理対応(既存値)

ROI 名用途x, y, w, h
configs/eval_baseline.yamlシミュ 512×51224, 37, 464, 450
configs/eval_real.yaml実機 1500×1500 ベースreference_measurement の roi_config.json 参照

シミュ ROI と実機 ROI は 物理対応済み(評価板の同じ XY 領域).シミュの orthographic センサと実機カメラの向き変換は SPEC_03 画像 ↔ 物理 の向き を参照.

OETF 順方向適用の仕様 (Forward OETF Application)

最重要セクション.シミュ linear 結果と実測 sRGB PNG を直接比較すると CoV や勾配の絶対値は不一致になる.これを データに合わせて回す係数ゼロで解消するのが OETF 順方向適用.

物理動機

  • 実機 PNG は ISP 内で sRGB OETF (IEC 61966-2-1) が掛かった非線形符号化値.Camera2 YUV_420_888 → BT.601 は定義上ガンマ済み R'G'B' 上の量.
  • シミュは Mitsuba の linear 放射輝度.
  • 無次元指標 (CoV / 勾配 / C/P) は線形変換に対してのみ不変.非線形 OETF を介すと値が変わる.
  • 両者を同じドメイン(gamma 空間 luma)に揃えれば,「物理が同じなら指標も同じ」が成り立つ.

標準 OETF(IEC 61966-2-1)

        ┌─ 12.92 · L                       (L ≤ 0.0031308)
V(L) = ─┤
        └─ 1.055 · L^(1/2.4) − 0.055       (L  > 0.0031308)

L は linear(0..1 正規化),V は sRGB 符号化値(0..1).実装は evaluation/oetf.py の apply_srgb_oetf().

露出アンカー(mean 一致)

露出(線形ゲイン)は AE が制御する量で,シミュ側で任意に決められない.実測 ROI mean に対数二分でアンカーする:

  1. シミュ linear ROI 全体に係数 α を掛ける
  2. OETF を順方向適用し uint8 量子化
  3. 量子化後 mean が実測 mean (146.7146) に一致する α を対数二分で求める
  4. 線形ゲインなので 形状指標 (CoV / 勾配 / C/P) は α に対し不変.データに合わせて回す自由度はゼロ.

二重適用禁止規則

  • 実測 PNG には絶対に OETF を適用しない.ISP で既に sRGB 符号化されているため二重適用になる.
  • configs/eval_real.yaml は oetf セクション無し(無効).configs/eval_baseline.yaml は oetf.enabled: true(シミュ用).
  • スキーマ詳細は SPEC_02 §evaluation 参照.

luma vs luminance と演算順序の整合

実測 MiniTias-Evaluation の「輝度値」は厳密には Rec.709 luma Y'(ガンマ済み成分への加重和 Y' = 0.2126R' + 0.7152G' + 0.0722B',ガンマを戻さない).シミュ側は linear luminance に直接 OETF を当てている.OETF は非線形なので一般に Σwᵢ·f(xᵢ) ≠ f(Σwᵢ·xᵢ) だが,矛盾しない:

  • Rec.709 重みは合計 1 (0.2126 + 0.7152 + 0.0722 = 1.0000).
  • R=G=B=x の無彩色画素では「チャネル別 OETF→加重和」Σwᵢ·f(x) = f(x) も「加重和→OETF」f(x·Σwᵢ) = f(x) も厳密に一致.
  • シミュは白色 LED(RGB 等価 radiance)+無彩色拡散材で厳密に R=G=B → 「luminance に直接 OETF」 = 「実測の演算順(チャネル別 OETF → Rec.709 加重和)」と数値同値.
  • 本質: OETF は不整合を作る操作ではなく消す操作.OETF 前のシミュ=linear 空間 luma,実測=gamma 空間 luma で別ドメイン(真の不整合).OETF 後は両者とも gamma 空間 luma になり,突合が正当化される.

残る近似(モデル誤差として正直に保持)

  1. 無彩色等価が厳密なのはシミュ側のみ.実測白板画像は LED 分光・ISP ホワイトバランス・センサ応答で微小に非グレー(R'≈G'≈B' が完全でない分の luma vs luminance 差).
  2. カメラ実 OETF ≠ 厳密 sRGB(独自トーンマップ).
  3. ISP レンズシェーディング補正の残差(TEST_01 既知差分 #6,未対処).

量子化(任意)

oetf.quantize_uint8: true で float → uint8 量子化を施す.実測 PNG が uint8 のため,公平比較には量子化を入れる.量子化ノイズ ≈ ±0.5 単位は無次元指標にほぼ影響しない(spp=1024 の MC ノイズの方が大きい).

mean 正規化(linear モード用) (Mean Anchor Normalization for Linear Mode)

OETF を適用しない linear ドメインでの評価結果について mean を target_mean に揃える線形ゲイン正規化 を行う.OETF の露出アンカーと同じ思想を,OETF を介さない linear 評価モードに対称展開したもの.

物理動機

シミュ側の radiance 値は scene YAML での暫定値(実測 mean アンカー)で決まるが,シーン設定を変えると(例: 発光面サイズや反射率の変更)絶対値スケールが大きく動く (Step 8-7 で実証.size を 2.8×3.5 → 1.5×1.5 mm に変えると mean が 2.83× 上昇).数値指標 (CoV / 勾配 / C/P) は 線形ゲインに対し不変 なので形状指標の比較は問題ないが,輝度マップを画像で見比べる際に color scale が桁違いになり「形」の比較が阻害される .

linear ドメインで mean を共通の target_mean に揃えれば,color scale を揃えた状態で複数シミュ結果の形を視覚的・数値的に公平比較できる.

計算式

α = target_mean / values.mean()
normalized = values × α

線形ゲイン α を全要素に乗算するのみ.返り値は (normalized, α) のタプル.values.mean() == 0 の場合は ValueError.

不変性(厳密)

指標正規化前後で
meantarget_mean に厳密一致
CoV (std / mean)不変(分子分母同時 α 倍)
max/min 比不変
中心/周辺比 (C/P)不変
勾配 %不変
stdα 倍
max, minα 倍

OETF との排他制御

oetf.enabled=true と normalization.enabled=true を同時指定すると ValidationError(OETF の露出ソルバが既に mean アンカーを行うため二重適用になる).EvaluationConfig._validate_oetf_normalization_exclusive で保証.

OETFnormalization挙動
有効省略 or 無効OETF 内の露出ソルバが mean アンカー(既存動作)
有効有効ValidationError(排他制約違反)
無効有効linear ドメインで mean 揃え(本機能の主用途)
無効省略 or 無効無変換(生 luminance のまま,後方互換)

後方互換

normalization キー省略時は無変換.既存設定(configs/eval_real.yaml,configs/eval_baseline.yaml)は変更不要.configs/eval_baseline_linear.yaml のみ新規追加された設定.

主用途

TEST_03 輝度マップ形状追跡 における 複数 Step の輝度マップ形状比較.発光面サイズ・反射率等を変えたシミュレーション結果を,共通の色スケールで並べることで「形」の異同を視覚的に判定できる.

メトリクス定義 (Metrics Definitions)

ROI 内の輝度配列 Y を入力に,以下を算出.計算式は uniformity.py 実装と一致.

全体指標

指標記号定義物理的意味
平均meanY.mean()ROI 平均輝度(露出に依存)
標準偏差stdY.std(ddof=0)ばらつきの絶対量
変動係数CoVstd / mean無次元のばらつき.均一性の主要指標
max/min 比max-minY.max() / Y.min()最大/最小比.外れ値に敏感(MC ノイズ感度高)

ゾーン分類 (3 zones)

ROI 中心からの 正規化楕円距離 d に基づき分類:

d = sqrt( ((x - cx) / (W/2))² + ((y - cy) / (H/2))² )
ゾーン範囲
centerd < 0.33
middle0.33 ≤ d < 0.66
periphery0.66 ≤ d

ゾーン指標

指標定義物理的意味
中心/周辺比 (C/P)center_mean / periphery_mean中心と周辺の明るさ比 (>1 は中心優位)
勾配 %(center_mean − periphery_mean) / center_mean × 100中心からの相対的明るさ低下率

ゾーン境界 (0.33, 0.66) は評価 YAML の zones.boundaries で変更可.

動径プロファイル

正規化距離 d を 20 ビン(既定)に分け,各ビンの平均輝度を取る.figures/radial_profile.png でグラフ化.

動径 min/max 比(オプション)

metrics.radial_min_max: true で有効化.動径プロファイル(20 ビン平均)の 最小ビン値 ÷ 最大ビン値.画素単位 max_min 比よりノイズ・外れ値に対しロバスト.

指標定義値域
動径 min/max 比min(bins) / max(bins)(空ビンは nan で除外)0〜1(1.0 で均一.小さいほどムラ大)
動径 min ビン距離最小値ビンの正規化距離0〜1(1.0 が最周辺ビン)

metrics.csv に radial_min_max_ratio / radial_min_distance / radial_min / radial_max の 4 列を末尾に追加.既定 False(既存挙動互換).metrics.radial_profile の有無に関わらず内部で動径プロファイルを算出するため独立して有効化可能.実装: evaluation/radial.py:calc_radial_min_max_ratio(MiniTias-Evaluation の src/analysis/spatial.py からマージ).

可視化規約 (Figure Conventions)

sm-evaluate は figures/ に以下 4 種を生成.MiniTias-Evaluation 互換スタイル.

ファイル内容カラーマップ・スタイル
luminance_map.pngROI 輝度マップ(X-Y)hot cmap,個別正規化(min-max を自動),カラーバー付き
histogram.png輝度ヒストグラム256 bin,ROI 全体
radial_profile.png動径プロファイル20 ビン平均輝度の line plot
zone_map.png3 ゾーン分類マップluminance 背景 + 境界線(楕円)

実装: evaluation/visualize.py.

出力ファイル仕様 (Output Files)

sm-evaluate --output <dir>/ で以下を生成:

<dir>/
├── metrics.csv          # 1 行 ヘッダ + 1 行 値(評価結果サマリ)
└── figures/
    ├── luminance_map.png
    ├── histogram.png
    ├── radial_profile.png
    └── zone_map.png

metrics.csv カラム定義(ヘッダ順)

cov, std, max_min_ratio, mean, max, min,
center_mean, center_std, middle_mean, middle_std, periphery_mean, periphery_std,
center_periphery_ratio, gradient_magnitude

すべて float.gradient_magnitude は上記「勾配 %」と同じ値.

キャリブレーション目標 (Calibration Target)

PLAN_02_開発ステップ より,実測 baseline 1 枚 (MiniTIAS_20260408_144434) に対する数値:

指標実測値仮置き許容範囲
CoV0.0426±0.005
中心/周辺比1.064±0.02
勾配 (%)6.23±1.5

シミュ側はこれらの値に 数値だけでなく形(輝度マップ分布)も近づけることが目標.形の追跡は TEST_01 輝度マップ形状の追跡 を参照.

キャリブレーション経過(要約) (Calibration Progression Summary)

Step 8 で実施した検証イテレーションの結論サマリ.各 Step の仮説・変更・数値・解釈・学びの詳細は TEST_01_キャリブレーション検証履歴 を参照.

確定基準

  • 設定: R=0.85, max_depth=8, spp=1024, OETF=on
  • 評価: sRGB ドメイン(OETF 順方向適用後の uint8 量子化値で比較)
  • 残差: CoV 0.089 vs 実測 0.0427 = 2.1×(初期 spp=128 時の 5.5× から大幅縮小)

寄与順(訂正済み)

OETF(最大・約 2/3,解消済み)> ISP LSC(残差主因候補・未対処)> 反射率(弱いレバー)

旧版「主因は ISP レンズシェーディング (83%)」は OETF を抜かした交絡判断で誤りだった.OETF 適用後で寄与順を訂正.

主要な発見(時系列)

Step内容主要な学び
8-1spp 校正 128→1024spp は CoV 0.183→0.174 で頭打ち.残差はノイズではなく物理勾配.
8-2反射率スイープ (0.75〜0.92)弱い二次レバー(∂勾配/∂R ≈ -38%/単位).これ単独では差を閉じられない.
8-3OETF 順方向適用パラメータフリーで見かけ差の 2/3 を解消.非線形変換下では無次元指標は不変ではない.
8-4max_depth 検証 (8→12)depth=8 は勾配を過大評価(-2.6pt/linear).確定 YAML は 8 のまま,3D ベイクは独立化.
8-53D 可視化改善「見え方」と「物理」を厳格に分離.同手法で計算すれば物理は均一.
8-6LED 物性確定 (LP-2835D90VW)規格推定 radiance 2030 vs 校正値 2807 = 1.38× 差は反射率 0.89 で説明可能(既知差分 #3 クローズ).
8-7発光面サイズ検証 (2.8×3.5 vs 1.5×1.5)形状指標は不変(点光源近似実証),絶対値は LED 周辺幾何と縮退.校正値は局所幾何依存と理解する.

次のアクション

残差 1.6〜1.9× に対する LSC(ISP レンズシェーディング)順方向モデルの設計・実装.物理動機づけ低自由度形(cos⁴ ベース等)に限定し overfitting を回避.詳細は TEST_01 Step 8-N 候補 参照.

反射率は均一性からは一意に定まらない(物理範囲内で縮退)ため暫定 0.85 据え置き.実フィラメント分光反射率データ入手時に再校正.

参照 (References)