fullseye

測色と分光の知識 — 色は「分光 × 光源 × 観測者」でしか決まらない

fullseye には測色そのものがある(imgmetrics 族の rgb_to_lab / delta_e_2000 ほか)。 一方で 2-D の色 op(trans_from_rgb / trans_to_rgb / cfa_to_rgb / linear_trans_color ほか)は色空間の変換であって、測色ではない。 外観検査で「色が違う」を判定するとき、RGB の差だけを見ると必ずどこかで外す。 この文書は op の説明ではなく、その手前にある物理と規約を書く教材である。 optics/guides/mv_*.md(撮像系)、3d/guides/depth_sensors.md(深度)、 annotate/guides/dataset_conventions.md(出口)と同じ位置づけ。


1. 色の定義式(ここから全部出る)

物体色は物体だけでは決まらない。三刺激値は 3 つの掛け算の積分:

X = k ∫ S(λ) · R(λ) · x̄(λ) dλ
Y = k ∫ S(λ) · R(λ) · ȳ(λ) dλ
Z = k ∫ S(λ) · R(λ) · z̄(λ) dλ

S(λ) = 光源の分光分布   R(λ) = 物体の分光反射率   x̄ȳz̄ = 等色関数(観測者)
k は完全拡散反射面で Y = 100 になるよう正規化する

この式に無いものは色を決められない。 つまり:


2. 標準光源 —— 名前と実体がずれている

記号 実体 相関色温度
D65 平均昼光(D 系列は 1964 年に実測から統計的に定義) 約 6504 K
D50 印刷・グラフィックアートの基準 約 5003 K
A タングステン電球(黒体) 2856 K
F1–F12 蛍光灯(12 種) 種による

D65 の相関色温度が 6500 K ちょうどでないのは、標準を定めた後にプランクの法則の 定数 c₂ の推定値が改定されたため。名前は 6500 のまま残っている。

そして重要なのは —— D 系列も F 系列も、実際には artificially にはほとんど再現できない (数学的に定義された分布であって、実在の光源ではない)。さらに:

LED は D 系にも F 系にも当てはまらない。

外観検査の照明は今ほぼ LED である。つまり規格光源の表を引いても現場の S(λ) は出てこない。 分光放射計で実測するか、メーカーの分光データを使うのが唯一確実な道である。


3. メタメリズム —— 検査で最もよく踏む地雷

分光反射率 R(λ) が違うのに、ある光源下では三刺激値が一致する組が存在する。 これをメタメリック・ペアと呼ぶ。

積分してから比べる以上、これは避けられない。3 つの数字(XYZ)に落とす時点で、 無限次元の R(λ) の情報は捨てられている。結果として:

判別したいなら分光で測るしかない。 RGB でも XYZ でも足りない。 逆に言えば「色差で管理している」と言うとき、どの光源で・どの観測者でが 決まっていなければ、その管理は再現しない。


4. カメラは観測者ではない

カメラの分光感度が等色関数の線形結合になっている(Luther–Ives 条件)ことは、 実機ではまず無い。したがって:

前処理の順番(ここを崩すと色が壊れる)

  1. 暗電流・オフセット減算
  2. シェーディング(平場)補正 —— 照明ムラとレンズの cos⁴ を取る
  3. ホワイトバランス —— von Kries 型の対角スケーリング、より正確には Bradford CAT
  4. 線形空間で演算 —— ここが要点。sRGB のガンマを外さずに平均・リサイズ・補間すると 暗く濁る(非線形空間での平均は物理的に意味が無い)
  5. 表示するときだけガンマを戻す

飽和した画素は色として無効。 1 チャンネルでもクリップすると色相が回る。 検査では飽和マスクを別に持ち、色差の計算から外す。


5. 色差 ΔE —— どれを使うか

性質
ΔE*ab(CIE76) 1976 Lab のユークリッド距離。実装は簡単だが知覚均等でない(特に高彩度でずれる)
ΔE94(CIE94) 1994 明度・彩度・色相に重みを入れた。CIE76 からの改善が大きい
ΔE00(CIEDE2000) 2001 さらに回転項とグレー補正を追加。最も洗練されているが式が複雑

研究上の知見として、CIE76 → CIE94 の改善のほうが、CIE94 → CIEDE2000 の改善より 大きいと報告されている。CIEDE2000 の補正項の寄与も、彩度差補正を 100 とすると 色相差 29・回転項 8・明度差 8・グレー補正 6 という順で、彩度差補正が支配的

kL(明度の重み)は用途で変える —— グラフィックアートで 1、繊維で 2 が慣例。 検査対象に合わせて決める値であって、既定値をそのまま使う性質のものではない。

「ΔE = 1 が識別限界」は俗説として扱うこと。実際の弁別閾は色相・彩度・明度・ 背景・観察条件で変わる。自社の対象で、自社の観察条件で、閾値を実測して決める。


6. fullseye での現在地(正直に)

要素 今あるもの 足りないもの
光源 S(λ) light_spec(source=led/halogen/laser, wavelength_nm, bandwidth_nm) —— 中心波長 + 帯域幅のモデル(実機の照明カタログ付き) 実測の分光分布を持てない。D65/A/F 系の表も無い
反射率 R(λ) scene_material(albedo=...) —— スカラまたは RGB 分光反射率を持てない。だからメタメリズムが原理的に再現できない
観測者 x̄ȳz̄ 無し CIE 1931 2° / 1964 10° の等色関数表
カメラ感度 sensor_spec(qe=...) —— スカラの QE QE(λ) 曲線、カラーフィルタの分光透過
色空間変換 imgmetricsrgb_to_xyz / xyz_to_lab / rgb_to_lab / lab_to_rgb —— CIE 定義で、白色点は white= で選べる(既定 D65 2°) 白色点の適応(Bradford CAT)。逆変換は色域外を切り詰めるので往復は色域内でしか一致しない
色差 delta_e_76 / delta_e_2000 / delta_e_map —— CIEDE2000 は Sharma らの 34 組の検証対で固定(kL / kC / kH を渡せる) ΔE94。分光ベースの色差

指標そのものの使い方(data_range の罠、SSIM の実装差、報告に条件を添える型)は imgmetrics/guides/image_difference_metrics.md に分けてある。

★ 同じ変換が 3 つある —— 名前が同じでも尺度が違う

fullseye には RGB → L*a*b* が 3 つある:

どこ 実装 尺度・精度
imgmetrics.rgb_to_lab CIE 定義(sRGB 原色、白色点を選べる) float、L* は 0–100これが正
color_pca.trans_from_rgb(img, "lab") 上への委譲 同じ値
op 台帳の trans_from_rgbbackends_color OpenCV uint8 に量子化してから変換し 255 で割った 8-bit スケール

この文書を書いている途中に見つけた不整合が、まさにこれだった —— color_pca.trans_from_rgb()hsv / yuv / gray しか受け付けず、"lab""xyz" を渡すと ValueError になっていた。正しい実装は imgmetrics に既に あったのに、色空間変換の入口からそこへ到達する道が無かった。

直し方は「もう一組実装を書く」ではなく 委譲にした。行列と伝達関数を二組持つと、 片方だけ直したときに例外を出さずに違う色が出る(imgmetrics 自身も同じ理由で sRGB の伝達関数を gfx2d に委譲している)。

検証(tests/test_colorimetry.py): 白 → (100, 0, 0)(残差 2e-5 ―― 公表されている sRGB 行列が 7 桁に丸められているぶん)、sRGB 原色 → (53.241, 80.092, 67.203) ほか 公表値と一致、中間グレー 0.5 → L* = 53.389(50 ではない)、そして color_pcaimgmetrics同一の値を返すこと。


7. まとめ(判断の芯)


8. 診断表 —— 症状から原因へ

症状 まず疑う 確かめ方
目視 OK なのにカメラ NG カメラの分光感度が人と違う(カメラ内メタメリズム) 分光反射率を測る。無理なら校正チャートを同条件で撮り、その色の近傍で残差が大きいか見る
昼と夜/季節で判定が変わる 外光が混じり S(λ) が変わっている 遮光して再現するか確認。暗幕で囲って比較
照明を交換したら合格率が変わった LED の分光ばらつき(同型番でもロット差がある) 新旧の照明で同じ標準板を撮り、チャネル比を比べる
画像を縮小・平均したら色が変わった ガンマ空間で演算した 線形に戻してから同じ処理をして比較
明るい部分だけ色相が回る 飽和(1 チャンネルでもクリップすると回る) チャネル最大値の分布を見る。飽和値に張り付いた画素を数える
視野の端だけ色が違う シェーディング未補正/周辺光量落ち(cos⁴) 白板を全面に撮り、平場を取ってから再判定
ΔE の数字が現場感覚と合わない 式の選択(CIE76 のまま)と kL ΔE94 / ΔE00 に替えて目視順位との相関を見る。閾値は自社の弁別実験で決め直す
Lab 値が他社と合わない 白色点と観測者が違う(D65/D50、2°/10°) 相手方に白色点と観測者を確認する。書いていなければ比較しない

出典