ChromaLens は、 画像 を 1型 (P型・赤) / 2型 (D型・緑) / 3型 (T型・青) の 色覚特性 で の 見え方 に 変換 して 並べ、 さらに 「区別 しやすく」 補正 する ブラウザ ツール。 変換 は 3×3 の 行列 演算 だけ で 済む ので、 機械学習 モデル も サーバー も 使わ ず、 画像 は 端末 の 中 から 出ません。
#🎯 「見えない」 ではなく 「区別 が つかない」
作り 始める 前 に 一番 誤解 して いた の が ここ でした。 色覚特性 は 「色 が 見えない」 のでは なく、 特定 の 組み合わせ の 区別 が つき にくい。 日本人男性 の 約 5% (20 人 に 1 人) が 該当 する と 言われ、 赤緑 型 が 大半 を 占め ます。
つまり 検証 したい の は 「この 画像 は 何色 に 見える か」 では なく、 「グラフ の 赤い線 と 緑の線 が 別物 だ と 分かる か」。 それ が 分かる 形 に 出力 を 設計 しました。
- 元画像 と 1型 / 2型 / 3型 を 横 に 並べて 同時 に 見せる (切り替え 式 に する と 差分 が 分から ない)
- 「区別 しやすく 補正 した 画像」 も 同じ 並び に 置く
- サンプル に 原色 ブロック を 入れて、 赤 と 緑 が どこ まで 寄る か を 一目 で 分かる ように する
#🏗️ 3×3 行列 を かける だけ
色覚 シミュレーション は、 RGB の 各 ピクセル に 行列 を かける 線形変換 で 近似 でき ます。 広く 使われて いる 係数 (HCIRN / Wickline 系) を sRGB に 直接 当てる 方式 を 採り ました。
const SIM: Record<Vision, number[]> = {
protan: [0.567, 0.433, 0.0, 0.558, 0.442, 0.0, 0.0, 0.242, 0.758],
deutan: [0.625, 0.375, 0.0, 0.700, 0.300, 0.0, 0.0, 0.300, 0.700],
tritan: [0.950, 0.050, 0.0, 0.0, 0.433, 0.567, 0.0, 0.475, 0.525],
}1型 の 行 を 見る と、 R と G の 係数 が どちら の 行 でも ほぼ 同じ 比率 に なって います。 これ が 「赤 と 緑 が 同じ 値 に 潰れる」 の 正体 で、 コード に する と 現象 が そのまま 数字 で 見え ます。
ImageData を 1 ピクセル ずつ 舐めて 掛ける だけ な ので、 依存 ライブラリ は ゼロ。 1200×800 程度 なら 体感 で 一瞬 です。
#🔑 ダルトナイズ ── 失われる 差 を 別 の 色 に 逃がす
見え方 を 再現 する だけ なら 上 の 行列 で 終わり です が、 実用 上 欲しい の は 「じゃあ どう 直せば いい か」。 そこ で ダルトナイズ (daltonize) を 実装 しました。
考え方 は 素直 で、
- 元 の 色 と、 シミュレート した 色 の 差分 を 取る (= その 特性 で 失われる 情報)
- その 差分 を、 まだ 感じ 取れる チャンネル へ 足し 込む
const [sr, sg, sb] = applyMatrix(r, g, b, m)
const er = r - sr // 失われた 赤成分
const eg = g - sg
const eb = b - sb
// 赤 の 損失 を 緑 と 青 に 7 割 ずつ 逃がす
d[i + 1] = clamp(g + 0.7 * er + eg)
d[i + 2] = clamp(b + 0.7 * er + eb)赤 の 損失 er を 緑 と 青 に 配分 する の が 肝 です。 補正後 の 画像 は 一般 色覚 の 人 に は 「少し 色 が ずれた 絵」 に 見え ます が、 赤緑 の 区別 が つき にくい 人 に は 元 は 潰れて いた 差 が 明度 と 青み の 差 として 立ち上がり ます。
#😓 苦労した ところ
補正 の 強さ を どこ に 置く か。 係数 を 上げる ほど 区別 は つき やすく なり ます が、 写真 が 一気 に 不自然 に なり ます。 0.7 は 「資料 の 配色 チェック に 使える 程度 に 区別 が 出て、 写真 が まだ 写真 に 見える」 境目 として 選び ました。 正解 が ある 数字 では ない ので、 ここ は 断言 せず 「一般的 な モデル に よる 近似」 と 画面 にも 明記 して います。
サンプル 画像 を 何 に する か。 風景写真 だ と 差 が 分かり にくく、 最初 は 「変換 されて いる の か どうか」 すら 伝わり ません でした。 最終的 に 原色 ブロック (純赤 / 緑 / 青 / 黄 / 橙 / 茶 / マゼンタ / シアン) を 敷き詰めた サンプル を 用意 し、 1型 で 赤 と 茶 が 同じ 色 に なる の が 一目 で 分かる ように しました。
個人差 を 言い切ら ない こと。 色覚特性 は 型 の 中 でも 程度 が 大きく 違い ます。 「あなた に は こう 見えます」 と 言い切る の は 誠実 では ない ので、 表記 は 一貫 して 「この 特性 で の 見え方 の 近似」 に 統一 しました。
#🔭 今後 の 拡張
- 弱度 (protanomaly / deuteranomaly) の 段階 指定 — 現状 は 二色型 の 全欠損 近似 のみ
- 画像 内 の 「区別 が つか ない 色 ペア」 を 自動 検出 して 印 を 付ける
- 配色 コード (
#rrggbb) を 直接 入力 して、 その 組み合わせ が 安全 か 判定 する モード - WebGL 化 (現状 は CPU ループ、 4000px 級 だ と 待ち が 出る)
#💡 この サービス から 言える こと
画像処理 は 端末 の 中 で 完結 する なら、 それ 自体 が 価値 に なり ます。 資料 や 社内 の グラフ を 検証 したい 場面 で、 画像 を どこか に アップ ロード しなくて いい こと は 「便利」 では なく 「使える か どうか」 の 分かれ目 です。
そして、 3×3 の 行列 を かける だけ の 処理 でも、 出力 の 見せ方 を 設計 すれば 実用 ツール に なり ます。 重い モデル を 動かす こと と、 役 に 立つ こと は 別 の 話 でした。
[ ./next_action ]
読んだら、 ChromaLens を実際に動かす。
この開発ログは ChromaLens をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。