色差(ΔE00)とガマット検証パイプライン
広色域(P3/AdobeRGB/HDR) 素材を 事故なく sRGB 配信 へ収束させるには “変換した” だけでは不十分です。変換結果を ΔE00 / ガマット外率 / 肌色個別指標 で継続監視し、閾値逸脱を CI で即座に検知する 色品質ガバナンス が必要です。
要点(TL;DR)
- sRGB固定 + ΔE監視 — “変換したか”でなく “劣化量は許容内か”。
- ゴールデン比較 — 品質議論の主観を外し再現性確保。
- 肌色/ブランド領域マスク — 全体平均では埋もれる局所差異を拾う。
- ΔE00指標セット — 平均/最大/95pct/ガマット外率で立体把握。
- CI逸脱ブロック — 閾値超過PRを早期に差し戻し回帰防止。
背景:色品質は“後戻りしがちな非機能”
圧縮や再生成のたびに彩度/局所コントラストが僅かに失われ、ローンチ直後と半年後で“なんとなくくすんだ”状態になることがあります。sRGB固定パイプライン や P3→sRGB肌色チューニング は単発施策。持続的には差分指標の継続記録が要件です。
また HDR / 10bit ソースは LDR 8bit 化でトーン圧縮が入るため、トーンマッピング 後の ΔE 分布監視が不可欠です。
設計:インベントリ → 変換 → 差分 → CI → 可視化 → レビュー
- インベントリ — ICC/色域/ビット深度/アルファ有無を機械抽出。
- 正規化 — ICC→sRGB, Orientation適用, メタ最小化。
- 差分計測 — ゴールデンと Lab 変換し ΔE00 分布算出。
- マスク特化 — 肌色/ブランド領域 ΔE 集計 (平均/最大)。
- CIゲート — 閾値逸脱で失敗。ログに上位Nピクセルを出力。
- ダッシュボード — 週次トレンド/閾値境界/最新逸脱一覧。
実装:Sharp × ΔE00 計測スクリプト
libvips(Sharp) は高速に sRGB 変換でき、raw() でピクセルへアクセス可能。そこで WASM ΔE 実装と組み合わせ高スループット比較を行います。
// libvips (sharp) を使った sRGB 正規化 + ΔE 計測準備 (Node.js)
import sharp from 'sharp';
import { readFileSync, writeFileSync } from 'node:fs';
const src = 'input-p3.png';
const ref = 'golden-srgb.png';
const out = 'out-srgb.png';
// 1) sRGB へ変換 (ICC 埋め込み→変換→ICCタグ最小化 or strip)
await sharp(src)
.withMetadata({})
.toColorspace('srgb')
.png({ compressionLevel: 9 })
.toFile(out);
// 2) ΔE00 計測 (簡略概念: 実際はWASMで高速化)
import { deltaE00 } from './lib/deltae-wasm';
const r1 = sharp(ref); const r2 = sharp(out);
const [i1, i2] = await Promise.all([r1.raw().ensureAlpha().toBuffer({ resolveWithObject:true }), r2.raw().ensureAlpha().toBuffer({ resolveWithObject:true })]);
if(i1.info.width!==i2.info.width||i1.info.height!==i2.info.height) throw new Error('size mismatch');
// RGB→Lab 変換 & ΔE00 集計 (擬似コード)
let sum=0, max=0; const arr=[];
for(let p=0; p<i1.data.length; p+=4){
const lab1 = rgbToLab(i1.data[p], i1.data[p+1], i1.data[p+2]);
const lab2 = rgbToLab(i2.data[p], i2.data[p+1], i2.data[p+2]);
const d = deltaE00(lab1, lab2); sum+=d; if(d>max) max=d; arr.push(d);
}
arr.sort((a,b)=>a-b);
const mean = sum / (arr.length);
const p95 = arr[Math.floor(arr.length*0.95)];
console.log({ mean: mean.toFixed(2), max: max.toFixed(2), p95: p95.toFixed(2) });
CI は “変換 → 色差計測 → 閾値判定” を直列に。閾値は初期広め→運用データで徐々に引き締める段階導入が安全です。
# GitHub Actions (抜粋) - ΔE00 閾値逸脱で失敗
jobs:
color-diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: node scripts/generate-images.js # 変換
- run: node scripts/deltae-check.mjs --threshold-mean 1.0 --threshold-max 2.5
肌色/ブランドカラーの局所ΔE監視
全画素平均 ΔE が 0.6 でも、肌色領域だけ 1.8 など局所劣化が潜むことがあります。マスクJSON(ポリゴン)を適用し独立指標を保持します。
// 肌色/ブランドカラー領域マスク JSON 例 (ポリゴン座標)
{
"skin": [ { "file": "model.png", "polygon": [[120,88],[180,90],[178,140],[118,138]] } ],
"brand": [ { "file": "hero.png", "polygon": [[40,40],[300,40],[300,140],[40,140]] } ]
}
このマスクは OGP や OGP安全域 のテンプレ生成時に併用し、ブランドカラー領域の不意なトリミングも検知可能です。
ガマット外率とクリッピング戦略
P3→sRGB 変換で彩度の高い赤/緑領域がクリッピングする場合、軽度なら ΔE 閾値に吸収されますが、ロゴ等で集中する場合は perceptual 変換や彩度圧縮前処理を検討します。
- ガマット外率 — 変換前 RGB を線形化→sRGB 範囲外成分割合。
- 圧縮前処理 — 彩度/輝度マッピングで集中領域を滑らかに。
- 再エンコード抑制 — ΔE 増加が許容内なら再処理を打ち切る。
閾値設定とガバナンス
初期は mean<1.5 / p95<2.5 / max<4.0
の緩め設定で誤検知を避け、履歴が安定したら 1.0 / 2.0 / 3.0
へ段階的に絞ります。肌色/ブランドは独自に mean<0.8 を目安。閾値逸脱 PR には ΔE 上位 N ピクセルの座標 (x,y,ΔE) をJSONで添付し、再現性を確保します。
関連ツール
- カラー差分ヒートマップ — ΔE/差分可視化で局所劣化を素早く把握。
- 画像比較ツール — スライダー/オンオフで主観確認を高速化。
- パレット抽出 — ブランドカラー/支配色の変化検知。
- カラーパレット可視化 — 圧縮前後の色分布変化を俯瞰。
- LQIP BlurHash — プレースホルダで色ストレスを低減し主観評価を安定。
NG/落とし穴
- ΔE指標の単一利用 — 平均のみでは局所劣化を見逃す。
- ゴールデン未固定 — 比較対象が更新され基準が漂流。
- HDR一括8bit化 — トーンマップ抜きで急激な彩度低下。
- 肌色マスク未整備 — 顔写真や人物UIで劣化を後追い検知。
- 過剰再エンコード — ΔE 改善量が閾値内でも無限微調整、工数浪費。
公開前チェックリスト
- sRGB化完了 — 全出力が sRGB / ICC 不要タグ strip。
- ΔE統計 — mean/p95/max が現行閾値内。
- 肌色/ブランド差分 — mean < 0.8 / max < 2.0。
- ガマット外率 — クリティカル画像で閾値内(例: <2%)。
- CIログ — 上位ΔEピクセル座標が保存され再解析可能。
まとめ
色品質を“属人ノウハウ”から外し、ΔE00 + ガマット外率 + マスク領域の 3層モニタリング で再現性を獲得します。これによりデザイン刷新・コーデック変更・圧縮再調整の各フェーズでブランド/肌色の破綻を早期検知し、品質ガバナンス の成熟度を高められます。
FAQ(よくある質問)
1肌色領域を分離する理由
全画素平均では隠れる“局所的彩度低下”を顕在化するため。ブランド/肌色は視認感度が高く ΔE=1.0 未満でも主観差異が拾われるケースがあります。
2HDRトーンマッピングで注意すべき点
ハイライト圧縮で局所コントラストが失われ ΔE が上がる。HDR→LDRトーンマッピング の手順を参照しガンマ再調整を挟む。
3既存の sRGB 変換記事との差
sRGB変換とICCプロファイル は“変換手順”中心。本稿はその後の“継続検証/閾値/通知”という運用レイヤに焦点。