旨辛チキンおいしい

よくある備忘録みたいな奴です。

Android で色差を簡単に求める

色差

色差とは、色の距離のことで、簡単にいうと2つの色がどれくらい近いかということを表します。 しかしこの「どれくらい近いか」というのは、何を基準に考えるかによって答えも変わってきます。

色の距離はある色空間上でのユークリッド距離として定義されることが多いようです1

Lab 色空間

コンピュータのディスプレイは色を表現するのに RGB 色空間を用いていますが、 RGB 色空間上でのユークリッド距離は人間の感じる色差とは大きく異なります。これは、 RGB 表色系が人間の目の視覚特性を考慮していないためです。

そこで人の知覚により合った色空間が必要となり、 国際照明委員会 (CIE) が策定したのが Lab 色空間です。 Lab 色空間は "知覚的均等性を重視しており、L成分値は人間の明度の知覚と極めて近い" とされています2

簡単に言えば、 Lab 色空間上での距離は RGB 色空間での距離よりも人間の視覚特性に一致しているということです。 色差を求めるには、 Lab 色空間上での距離を計算する必要がありそうです。

ColorUtils

Android で Lab 色空間上の距離を計算したかったのですが、軽く調べただけでは Java のライブラリも含め簡単に扱えるものがあまり見つかりませんでした。 Qiita のこちらの記事 はかなり詳しく紹介されていてサンプルコードも掲載されているのですが、ソースコードのライセンスなどが不明なので今回は利用しませんでした。

その後いろいろ調べているうちに、 Android のサポートライブラリに ColorUtils というクラスがあることを発見したのですが、なんと ColorUtils に distanceEuclidean() というメソッドがありました。 このメッソドはその名の通りユークリッド距離を求めるメソッドで、引数に2つの Lab 色空間で表された色を取ります。

また、 ColorUtils には色空間を変換するメソッドも多数用意されており、 ColorUtils.RGBtoLAB()ColorUtils.colorToLAB() メソッドで RGB 色空間で表される色を簡単に Lab 色空間に変換できます。

ColorUtils で色差を求める

ということで、2つの色から色差 (Lab 色空間上でのユークリッド距離) を求めるには次のようにします:

val labArray1 = DoubleArray(3).also {
  ColorUtils.RGBtoLAB(r1, g1, b1, it)
}
val labArray2 = DoubleArray(3).also {
  ColorUtils.RGBtoLAB(r2, g2, b2, it)
}
val distance = ColorUtils.distanceEuclidean(labArray1, labArray2)

または、 0xFF0088FF などの @ColorInt Int を用いて

val labArray1 = DoubleArray(3).also {
  ColorUtils.colorToLAB(colorInt1, it)
}
val labArray2 = DoubleArray(3).also {
  ColorUtils.colorToLAB(colorInt2, it)
}
val distance = ColorUtils.distanceEuclidean(labArray1, labArray2)

ちなみに、 Kotlin では 0xFF0088FFLong 型とみなされるので、明示的に 0xFF0088FF.toInt() のように Int 型に変換する必要があります3