本指南仅有日文版(它是人写的散文,这里不做机械替换)。
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(出口)と同じ位置づけ。
物体色は物体だけでは決まらない。三刺激値は 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 になるよう正規化する
この式に無いものは色を決められない。 つまり:
• 光源が変われば色は変わる(同じ物体でも)。
• 観測者が変われば色は変わる —— CIE 1931 2° 標準観測者と CIE 1964 10° 標準観測者は
別物。検査の視野は広いので 10° を使う場面がある。**どちらで測ったか書いていない
Lab 値は比較できない。**
• カメラの RGB はこの式の出力ではない(§4)。
| 記号 | 実体 | 相関色温度 |
| --- | --- | --- |
| 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(λ) は出てこない。
分光放射計で実測するか、メーカーの分光データを使うのが唯一確実な道である。
分光反射率 R(λ) が違うのに、ある光源下では三刺激値が一致する組が存在する。
これをメタメリック・ペアと呼ぶ。
積分してから比べる以上、これは避けられない。3 つの数字(XYZ)に落とす時点で、
無限次元の R(λ) の情報は捨てられている。結果として:
• 昼と夜で判定が変わる(外光が混じる検査ブースで起きる)
• 目視 OK なのにカメラ NG(人の等色関数とカメラの感度が違う、§4)
• 照明を別ロットの LED に替えたら合格率が変わった(S(λ) が微妙に違う)
判別したいなら分光で測るしかない。 RGB でも XYZ でも足りない。
逆に言えば「色差で管理している」と言うとき、どの光源で・どの観測者でが
決まっていなければ、その管理は再現しない。
カメラの分光感度が等色関数の線形結合になっている(Luther–Ives 条件)ことは、
実機ではまず無い。したがって:
• RGB → XYZ / Lab の 3×3 行列は、その光源・その被写体群でだけ成り立つ近似である。
別の光源、別の材質群に持っていくと系統誤差が出る(カメラ内メタメリズム)。
• だからカラーチャートで校正する。X-Rite ColorChecker(24 パッチ)などを
同じ照明・同じ露光で撮り、パッチの既知 Lab に対して線形(あるいは多項式)回帰で
変換を推定する。校正なしの RGB から ΔE を出しても数字にしかならない。
1. 暗電流・オフセット減算
2. シェーディング(平場)補正 —— 照明ムラとレンズの cos⁴ を取る
3. ホワイトバランス —— von Kries 型の対角スケーリング、より正確には Bradford CAT
4. 線形空間で演算 —— ここが要点。sRGB のガンマを外さずに平均・リサイズ・補間すると
暗く濁る(非線形空間での平均は物理的に意味が無い)
5. 表示するときだけガンマを戻す
飽和した画素は色として無効。 1 チャンネルでもクリップすると色相が回る。
検査では飽和マスクを別に持ち、色差の計算から外す。
| 式 | 年 | 性質 |
| --- | --- | --- |
| **Δ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 が識別限界」は俗説として扱うこと。実際の弁別閾は色相・彩度・明度・
背景・観察条件で変わる。自社の対象で、自社の観察条件で、閾値を実測して決める。
| 要素 | 今あるもの | 足りないもの |
| --- | --- | --- |
| 光源 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(λ) 曲線、カラーフィルタの分光透過 |
| 色空間変換 | imgmetrics の rgb_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 に分けてある。
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_rgb(backends_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_pca と imgmetrics が同一の値を返すこと。
• 色を数字で管理するなら、光源・観測者・白色点を先に固定する。 これが決まっていない
ΔE は再現しない。
• RGB の差は色差ではない。 カラーチャートで校正して初めて色差になる。
• 分光が違うものを 3 数字で分けようとしない。 それがメタメリズムで、
照明を変えた瞬間に破綻する。分けたいなら分光で測る。
• 線形空間で計算する。 ガンマを外さない平均は物理量ではない。
| 症状 | まず疑う | 確かめ方 |
| --- | --- | --- |
| 目視 OK なのにカメラ NG | カメラの分光感度が人と違う(カメラ内メタメリズム) | 分光反射率を測る。無理なら校正チャートを同条件で撮り、その色の近傍で残差が大きいか見る |
| 昼と夜/季節で判定が変わる | 外光が混じり S(λ) が変わっている | 遮光して再現するか確認。暗幕で囲って比較 |
| 照明を交換したら合格率が変わった | LED の分光ばらつき(同型番でもロット差がある) | 新旧の照明で同じ標準板を撮り、チャネル比を比べる |
| 画像を縮小・平均したら色が変わった | ガンマ空間で演算した | 線形に戻してから同じ処理をして比較 |
| 明るい部分だけ色相が回る | 飽和(1 チャンネルでもクリップすると回る) | チャネル最大値の分布を見る。飽和値に張り付いた画素を数える |
| 視野の端だけ色が違う | シェーディング未補正/周辺光量落ち(cos⁴) | 白板を全面に撮り、平場を取ってから再判定 |
| ΔE の数字が現場感覚と合わない | 式の選択(CIE76 のまま)と kL | ΔE94 / ΔE00 に替えて目視順位との相関を見る。閾値は自社の弁別実験で決め直す |
| Lab 値が他社と合わない | 白色点と観測者が違う(D65/D50、2°/10°) | 相手方に白色点と観測者を確認する。書いていなければ比較しない |
• CIE Standard Illuminants(D 系列の定義経緯、D65 の相関色温度 約 6504 K、
c₂ 改定による名目値とのずれ、D 系は人工的にはほぼ再現できない) —
<https://www.rp-photonics.com/cie_standard_illuminants.html> /
<https://www.image-engineering.de/library/technotes/753-cie-standard-illuminants>
• G. Sharma, W. Wu, E. N. Dalal, *The CIEDE2000 color-difference formula:
Implementation notes, supplementary test data, and mathematical observations* —
<https://hajim.rochester.edu/ece/sites/gsharma/papers/CIEDE2000CRNAFeb05.pdf>
• CIEDE2000 と CIE94 の補正項の相対寄与、および CIE76 → CIE94 の改善が
CIE94 → CIEDE2000 の改善より大きいこと(比較研究) —
<https://www.researchgate.net/publication/8127013_Relative_significance_of_the_terms_in_the_CIEDE2000_and_CIE94_color-difference_formulas>
• kL の慣例値(グラフィックアート 1・繊維 2) — MATLAB imcolordiff —
<https://www.mathworks.com/help/images/ref/imcolordiff.html>