"""暗闇 vs 室内(外乱光)の輝度マップを共通スケールで並べるスライドを生成する.
REPORT_03(外乱光影響評価)に対応.compare_ambient_radial.py(動径オーバーレイ)の
輝度マップ版で,同一 DNG 定量モード(linear + LSC 補正,露出/ISO 固定)の 2 枚を
**共通の絶対カラースケール** で並置し,空間パターンがほぼ同じこと(外乱光ロバスト性)を示す.
共通スケールにする理由(各自正規化しない):
- 両者は同じ linear 単位・同じ露出/ISO・同じ LSC 補正なので絶対値が正当に比較可能.
- 共通カラースケールでないと「2 枚がほぼ同じ」が言えない(各自スケールだと差が誇張/隠蔽される).
対象(REPORT_03 の条件 A/B):
- 暗闇 (lights OFF) : SmTIAS_QM_20260601_124500
- 室内 (lights ON) : SmTIAS_QM_20260601_102753
使い方:
python scripts/compare_ambient_maps.py
"""
import sys
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
from src.config import load_roi_config # noqa: E402
from src.io.dng_pipeline import dng_luminance # noqa: E402
from src.io.loader import extract_roi # noqa: E402
# REPORT_03 の条件 A(暗闇=室内灯OFF)/ 条件 B(室内=室内灯ON)
DARK_PATH = PROJECT_ROOT / "data" / "smtias" / "quantitative" / "SmTIAS_QM_20260601_124500.dng"
INDOOR_PATH = PROJECT_ROOT / "data" / "smtias" / "quantitative" / "SmTIAS_QM_20260601_102753.dng"
ROI_CONFIG = PROJECT_ROOT / "config" / "roi_config.json"
ROI_KEY = "smtias.whiteboard"
OUTPUT_PATH = PROJECT_ROOT / "output" / "figures" / "compare_ambient_maps.png"
def _roi_luminance(path: Path, roi: dict) -> np.ndarray:
"""DNG(linear + LSC)の ROI 輝度画像を返す."""
luma = dng_luminance(str(path), apply_lsc=True)
return extract_roi(luma, roi["x"], roi["y"], roi["width"], roi["height"])
def main() -> None:
"""共通スケールの 2 枚並べスライドを生成して保存する."""
roi = load_roi_config(str(ROI_CONFIG), ROI_KEY)
if roi is None:
raise SystemExit(f"ROI '{ROI_KEY}' が config に見つかりません")
dark = _roi_luminance(DARK_PATH, roi)
indoor = _roi_luminance(INDOOR_PATH, roi)
# 共通カラースケール: 2 枚を結合した 1〜99 パーセンタイル(ノイズ外れ値にロバスト)
both = np.concatenate([dark.ravel(), indoor.ravel()])
vmin = float(np.percentile(both, 1))
vmax = float(np.percentile(both, 99))
fig, axes = plt.subplots(1, 2, figsize=(13, 6))
panels = [
(axes[0], dark, "Dark (lights OFF) 124500"),
(axes[1], indoor, "Indoor (lights ON) 102753"),
]
im = None
for ax, luminance, title in panels:
im = ax.imshow(
luminance, cmap="hot", interpolation="nearest", vmin=vmin, vmax=vmax
)
ax.set_title(title, fontsize=11)
ax.set_xlabel("X (px)")
ax.set_ylabel("Y (px)")
cbar = fig.colorbar(im, ax=axes, fraction=0.025, pad=0.02)
cbar.set_label("Luminance (absolute, linear 0-255 scale)")
fig.suptitle(
"Ambient light effect on luminance map (DNG, linear + LSC, shared scale)",
fontsize=13, y=0.98,
)
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(str(OUTPUT_PATH), dpi=150, bbox_inches="tight")
plt.close(fig)
print(f"共通スケール比較スライドを保存しました: {OUTPUT_PATH}")
print(f" 共通カラースケール vmin={vmin:.1f} vmax={vmax:.1f}")
print(f" Dark (124500) ROI mean = {dark.mean():.2f}")
print(f" Indoor (102753) ROI mean = {indoor.mean():.2f}")
if __name__ == "__main__":
main()