視認しにくいテキストを探す | その 1 chroma.js を使って色差を計算する

SEO が云々でも色被ってるの良くないよねっていうけど、いや普通にユーザビリティ悪いやん、適当に色選ぶと見にくいこと往々にしてあるやん、って思ったので、そういう何かがあるのかなあって思って調べたら、 Wikipedia 先生にそのまんまの項目が記載されていた。ので、これをまとめつつ、ライブラリがあったのでそれを使ってみる話。

数式、もといロジックをざっくり読んでみる編

前提として Wikipedia のものをガンガン鵜呑みにしていく。
数式とかなんでそうなの?みたいな理解はせず、そういうものがあるんだなーくらいに留める。

色差を計算するには?

Wikiepedia に色差というページがあって、もうこれ。英語版と微妙に内容が違うけど、それは後で触れる。

色差 - Wikipedia

色差を計算するには単純に距離を計算しては、人間の感覚とはだいぶずれてしまってだめ。どうやら CIEDE2000 というものを使うとよいらしい。 CIE は国際照明委員会のことで DE は Delta E だ。2000 は年代。1976 、 1994 と研究され数式が更新されている。で、この CIEDE2000 を計算するには Lab 色空間を使う必要がある。
ただ、ぼくらが普段生きている世界では RGB とか CMYK とか HSV とか HSL とかなので、そこから変換をしてあげないといけない。いや、デザイナーさんとかその手のグラフィック関連に詳しい人なら Lab の世界でも生きているのかもしれない。

(参考)
カラーネーム/RGB/HSL ウェブでのカラー指定いろいろ | アライドアーキテクツのクリエイターブログ

Lab 色空間に生きたい

Lab 色空間も Wikipedia 上にページがある。

Lab色空間 - Wikipedia

単に Lab というと Hunter と CIE の 2 種類があるが CIE の方を最近では指すらしいので、これを使ったらいいみたい。これまた国際照明委員会が決めたもので、明度( L )と、いい感じの色 a と b を使って示し、人間の目で見える全ての色を記述できて機器固有の基準として使えるようにしたものだそうだ。

RGB からどうやって Lab に変換するんだろうねっていうと、 RGB は機器固有の部分があるので、一発変換!とはできず、 RGB を XYZ 色空間 に変換する必要がある。

RGB の世界から XYZ の世界へ移動する

これまた Wikipedia 上にページがある。

CIE 1931 色空間 - Wikipedia

すげーざっくりの理解では「研究成果の結果、 RGB に対する人の感覚を重み付けしたもの」。

ここまでをまとめると?

RGB → XYZ → Lab → 色差が計算できる!

後に回した英語との差分って?

色差の英語版のページを見てみる。
Color difference - Wikipedia

すると「 CMC l:c (1984) 」という日本語にはない数式が出ている。なんか良いやつなんじゃないかな、きっと。色っぽい単語で調べてたらその手の調査したよって論文もでてきた。

DDCPにおける色域外特色近似再現のための色差式評価

優位性とか書いてあるので気になった時に読むとよさそうな気がする。

ライブラリの出番です chroma.js

こう研究された成果があるわけなので、まあきっと便利に使えるようにライブラリ作っている人とかいるんだろうなあ~~とか思っているとやっぱりある。

chroma.js api docs!

色関係の話題をいい感じに取り扱ってくれるライブラリだそうで、各種色空間の変換も任せろ、グラデーションも任せろ、な強いライブラリ。

chroma.js を使って色差を計算する

単純な距離、ユークリッド距離の計算をするには chroma.distance を使う。 mode パラメータで色空間の指定が出来るので、2つの色の間の位相をみたりなんかにもできそうだ。
色差を計算するには chroma.deltaE を使う。ご丁寧に deltaE という命名になっててわかりやすいぞ~。内部的には CMC を使っているらしい。 CIEDE じゃないんだ。

それを実際に試してみようってわけで、こんな HTML + JS を書いて様子を見てみる。

<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/1.3.6/chroma.min.js"></script>

<style>
.color-difference td {
    min-width: 15px;
    min-height: 15px;
    padding: 3px;
}
</style>

<table class="color-difference">
    <tr>
        <td></td>
        <td></td>
        <td>distance(RGB)</td>
        <td>deltaE</td>
    </tr>
</table>

<script>
let colors = [
    ['rgb(255,0,0)', 'rgb(0,255,0)'],
    ['rgb(255,0,0)', 'rgb(0,0,255)'],
    ['rgb(255,0,0)', 'rgb(255,255,0)'],
    ['rgb(255,0,0)', 'rgb(255,0,255)'],
    ['rgb(255,0,0)', 'rgb(0,255,255)'],
    ['rgb(255,0,0)', 'rgb(255,128,0)'],
    ['rgb(255,0,0)', 'rgb(255,0,128)'],
    ['rgb(255,0,0)', 'rgb(255,255,255)'],
    ['rgb(255,255,0)', 'rgb(255,0,255)'],
    ['rgb(255,255,0)', 'rgb(0,255,255)'],
    ['rgb(255,255,0)', 'rgb(255,255,255)'],
];

let table = document.querySelector('.color-difference');

colors.forEach((color) => {
    let tr = document.createElement('tr');
    tr.innerHTML = `
        <td style="background-color:${color[0]}"></td>
        <td style="background-color:${color[1]}"></td>
        <td>${chroma.distance(color[0], color[1], 'rgb')}</td>
        <td>${chroma.deltaE(color[0], color[1])}</td>
    `;
    table.appendChild(tr);
});
</script>

こんな出力が得られる。

  • 赤と緑、青よりは、黄ピンクのほうが気持ち近い。水色、距離は遠いんだけど色差はあまり変わらず
  • 赤とオレンジ、マゼンダな色はやっぱり色差が少ない
  • 赤と緑や青を比べるより、赤と白を比べたほうが色差がすくない(!)
  • 黄とマゼンダよりも、黄と水、黄と白のほうが色差がすくない(!)
  • 距離 = 色差 に直結せず、色によって微妙に重み付けがされているのを感じる

わりと見た感覚と近い気がするのと、数字として出るとさらに面白い。

その 2 を書いた。

https://gomiba.co.in/blog/archives/1841

前後の記事

Next:
Prev: