Newer
Older
SmTIAS-LightSim / docs / 04_SPEC / SPEC_04_評価仕様.md

評価仕様 (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 符号化ドメインに揃える操作である(後述).

設計目的は SmTIAS-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 と演算順序の整合

実測 SmTIAS-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(SmTIAS-Evaluation の src/analysis/spatial.py からマージ).

画像全体 min/max 比(オプション,2026-09-14 導入)

metrics.fullimage_min_max: true で有効化.画像全体で評価する,ノイズ補正付きの最小/最大比. 動径 min/max 比は方位方向に平均するため,同心円状でない輝度分布(オフ軸 LED 配置など)では 明るい側と暗い側が同じ輪帯で混ざり非対称を過小評価する(TEST_18 では非対称が強い条件で 0.97〜0.99 に張り付き,差は非対称の大きさ |a1| と相関 0.93〜0.95).一方,画素単位や平滑化後の パーセンタイルは MC ノイズの裾を拾い,生の輝度が低い(相対ノイズが大きい)条件で頭打ちになる. 本指標はその両方を避ける.

定義(evaluation/fullimage.py:calc_fullimage_min_max_ratio):

  1. ROI 輝度を σ = fullimage_sigma(既定 12 px)のガウス平滑化して smooth を得る.
  2. ノイズ場を推定する: 残差(ROI − ガウス(σ=4)(メディアン 5 px)(ROI))を空間シャッフルして同じ σ で平滑化し,その最小値 noise_min・最大値 noise_max を 4 回の平均で求める(構造を壊して ノイズの統計だけ残す.構造 CoV と同じ発想).
  3. fullimage_min = min(smooth) − noise_min,fullimage_max = max(smooth) − noise_max, fullimage_min_max_ratio = fullimage_min / fullimage_max.
指標定義値域
画像全体 min/max 比ノイズ補正後の min / max0〜1(1.0 で均一.小さいほどムラ大)

metrics.csv に fullimage_min_max_ratio / fullimage_min / fullimage_max / fullimage_noise_min / fullimage_noise_max の 5 列を追加(動径 min/max の後・形状指標の前).既定 False(既存挙動互換). 線形ゲインに不変(mean anchor 正規化の前後で同じ値).同じ画像・同じ設定なら常に同じ値(乱数は 関数内で seed 固定).入力が 2D でない・σ ≤ 0・min(H, W) < 4σ・補正後の max ≤ 0 は ValueError.

検証(scripts/build_fullimage_minmax.py,軸上スイープ 20 条件): 対称な分布では動径 min/max 比と ±0.01 以内で一致し,一様像+同量のノイズで測ったノイズ床は ±0.004.ブロック平均・多項式フィット ・補正なし平滑化の各候補より偏りとノイズ床の両方で優れた.

使用上の注意:

  • 平滑化による偏り: σ の平滑化が構造をなますため,比は真値より少し大きく(均一寄りに)出る (256² の線形勾配で真値 0.800 → 0.813,ガウス山で 0.857 → 0.865).偏りは σ と ROI サイズの比で 決まるので,σ を固定して条件間を比較する用途に使い,絶対値を他の定義と直接比べない.
  • ノイズ床はノイズ量に比例: 一様像で相対ノイズ 5% → 0.003,10% → 0.006,20% → 0.012. 構造のある像ではノイズが増えると比が均一寄りに上振れするので,同じ spp(同じノイズ水準) の条件同士で比較する.
  • ROI が小さいときは σ を下げる(fullimage_sigma).4σ 未満の辺は受け付けない.

形状指標 (Shape Metrics — オプション、2026-06-03 導入)

動機: 既存の 4 指標 (CoV/勾配/C/P/動径 min/max) は 不均一性の絶対量しか測れず、「形」を構造的に区別できない.シミュ「Y 軸単調勾配」と実機「中央ピーク楕円」のように形が違う 2 つの画像でも、数値だけは似通うことがある.詳細は TECH_11 形状指標の見直しと新指標導入.

metrics.shape_metrics: true で有効化.metrics.csv に末尾 12 列を追加.既定 False(既存挙動互換).実装: evaluation/shape_metrics.py.

5 つの形状指標

指標定義値域何を測るか
輝度重心 (Intensity Centroid)輝度を重みとする画像内重心 (x, y)画像座標 + 正規化 [-1, +1]評価板内の 重心位置の偏り(Y 単調勾配 → 下方偏り)
角度/半径分解 (Angular/Radial Decomposition)極座標で I(r, θ) に分解し角度方向 var と半径方向 var を計算angular_ratio: 0〜10=完全同心円 / 1=完全角度依存.中央ピーク楕円は小,Y 単調勾配は大
SSIM (Structural Similarity Index)参照画像との構造的類似度 (skimage)0〜1 (1=完全一致)シミュ vs 実機の直接比較.shape_reference が必要
NCC (Normalized Cross-Correlation)mean 中心化した画像同士の相関-1〜+1 (1=完全相関)絶対輝度スケール不変な形の一致度
PCA 主軸 (Intensity PCA)輝度を重みとする weighted PCA で主軸方向と楕円率角度 [-90°, +90°] / 楕円率 0, 1不均一性の 主軸方向と楕円率

CSV 列名(末尾 12 列)

カテゴリ列名
重心intensity_centroid_x_px / intensity_centroid_y_px / intensity_centroid_x_norm / intensity_centroid_y_norm / intensity_centroid_offset_norm
角度/半径分解angular_variance / radial_variance / angular_ratio
PCApca_primary_axis_angle_deg / pca_eccentricity
構造的類似度ssim / ncc(shape_reference 未指定なら NaN)

設定例

metrics:
  shape_metrics: true
  shape_reference: ../reference_measurement/quantitative/expected_results/MiniTIAS_QM_20260601_124500_luminance_map.npy  # 任意

shape_reference 相対パスは config YAML のディレクトリ基準で解決.未指定(null)なら SSIM/NCC は NaN になり他の指標は計算される.

注意

  • 完全均一画像で angular_ratio は NaN(variance ゼロ割り).呼び出し側で扱うこと
  • 合成純粋 Y 勾配は angular_ratio = 1.0(角度方向 var 支配).実シミュ画像(ノイズや非一様性込み)の典型値は 0.3〜0.5
  • shape_reference の shape mismatch は SSIM/NCC で NaN を返しエラーは出さない(警告ログのみ)

可視化規約 (Figure Conventions)

sm-evaluate は figures/ に以下 4 種を生成.SmTIAS-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

--no-figures を付けると figures/ を作らず metrics.csv だけを出す(指標の値は同一. スイープで図の描画分 約 2 秒/条件 を省くため).本体は evaluation/pipeline.py:evaluate_image で,スイープスクリプトはこれをプロセス内で呼ぶ(save_figures=False).

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)