"""linear ドメイン正規化モジュール.
シミュの生 luminance 配列に対して,mean を指定値(target_mean)に揃える
線形ゲインを適用する.
線形ゲインは形状指標(CoV / 勾配 / C/P 比 / max-min 比)に厳密に不変であり,
絶対値スケールだけを合わせる操作である.これにより複数設計のシミュ結果を
linear ドメインで公平比較できる.
OETF 順方向適用(oetf.py の露出アンカー)と同じ思想を linear モードに
対称に展開したものであり,OETF との併用は禁止する(EvaluationConfig の
model_validator で検証する).
"""
from __future__ import annotations
import numpy
def apply_mean_anchor(
values: numpy.ndarray,
target_mean: float,
) -> tuple[numpy.ndarray, float]:
"""入力配列の mean を target_mean に揃える線形ゲインを適用する.
$\\alpha = \\text{target\\_mean} / \\text{values.mean()}$
として,``values * alpha`` を返す.
CoV = std / mean,max-min 比,勾配,C/P 比などの形状指標はスカラー倍で
不変なので,絶対値スケールだけが揃う(線形ゲインの性質).
Args:
values: 入力 ROI 配列(任意形状・任意次元,float64 推奨).
target_mean: 目標 mean 値(uint8 スケール [0, 255] 想定だが任意 float 可).
Returns:
(normalized, alpha) のタプル.
normalized: ``values * alpha`` の配列(dtype は values と同じ).
alpha: 適用した線形ゲイン(target_mean / values.mean()).
Raises:
ValueError: values.mean() が 0 の場合(ゼロ除算を防ぐ).
"""
src_mean = float(numpy.mean(values))
if src_mean == 0.0:
msg = "values の mean が 0 のため,mean anchor 正規化を適用できません."
raise ValueError(msg)
alpha = target_mean / src_mean
return values * alpha, alpha