画像カラーパレット抽出ツール

写真をアップロードすると、このツールはヒストグラムベースの色量子化を使って支配的な色を自動的に抽出します——16進コード付きのすぐに使えるスウォッチパレットを、完全にブラウザ内で計算し、サーバーには何もアップロードしません。

250回閲覧

写真をアップロードすると主要な色を抽出します — すべての処理はブラウザ内で行われます。

なぜピクセルを数えるだけでは不十分なのか

写真の支配的な色を見つける最も直感的な方法は単純に思えます。各ピクセルの正確な色ごとの出現回数を数え、最も頻繁に現れる色を残せばよいというものです。しかし実際にはこれはほとんど即座に破綻します。たとえば青空の写真は、単一のフラットな青ではありません。センサーノイズ、自然光のグラデーション、JPEG圧縮のアーティファクトによって、ピクセルごとにわずかに異なる何千もの青が存在しています。隣接する2つの空のピクセルはrgb(91, 148, 214)とrgb(92, 149, 213)かもしれません。見た目にはまったく同じでも、数値としては別物です。正確な値として数えると、どちらも「最も一般的な色」にはなりません。それぞれがせいぜい1回か2回しか出現せず、ほとんど同一だが技術的には異なる何千もの青の中に埋もれてしまいます。この素朴なアプローチが返すのはパレットではなくノイズです。

解決策は、正確なピクセル値を数えるのをやめ、似た色のバケット(区分)を数えることです。このツールは、通常0から255までの範囲を持つ赤・緑・青の各チャンネルを、それぞれ32刻みの8つの等しい帯に分割します。各チャンネルに対してMath.floor(value / 32) * 32を適用します。これにより、1,670万通り考えられるRGBの組み合わせが、8 × 8 × 8 = 512個のバケットからなる扱いやすいグリッドに変換されます。リサイズされた画像内の各ピクセルは、その赤・緑・青の値がどの帯に該当するかに基づいて、ちょうど1つのバケットに割り当てられます。そして、単純なオブジェクトをハッシュマップとして使い、各バケットに何個のピクセルが入ったか、およびその実際の赤・緑・青の値の合計を随時集計していきます。

バケットからパレットへ

すべてのピクセルを数え終えたら、バケットを含まれるピクセル数の多い順に並べ替え、最も多い6〜8個を残します。ただし、各バケットに表示される色は、単純にバケットの数値的な境界(たとえば「赤224〜255、緑128〜159、青0〜31」)ではありません。それは32×32×32の立方体の中の、ある程度恣意的な一角にすぎないからです。代わりに、このツールはそのバケットに実際に入った各ピクセルの赤・緑・青の真の平均値を計算します。これは、人間の目がその画像領域を代表する色として知覚するものにはるかに近いものです。

このヒストグラムビニングの手法は、意図的にシンプルにした色量子化(color quantization)の一種です——大きな色の集合を、それを代表する小さな集合へと縮小する処理です。より洗練された古典的な代替手法として、Paul Heckbertが1980年にMITの修士論文で定義したメディアンカット(median-cut)があります。これは固定サイズのボックスを使う代わりに、色空間を最も幅の広い次元に沿って再帰的に分割する手法で、GIF画像が256色のパレットに縮小される際の仕組みとして今も使われています。メディアンカットは複雑な画像に対して一般的により知覚的に正確なパレットを生成しますが、その分実装の複雑さが増します。ここで使われている固定グリッドのヒストグラムビニングは、より理解しやすく、ブラウザ内で即座に実行できるほど高速です。これがこのツールが選んだトレードオフです。

カウントを始める前に、アップロードされた画像はまずHTML5のcanvas APIを使って、幅が200ピクセルを超えないように縮小されます。この処理により、読み取ってバケットに割り当てる必要のあるピクセル数が大幅に削減される一方、結果として得られるパレットにはほとんど影響しません。色のバケットは細部ではなく、色相の大まかな領域を追跡するものだからです。画像の描画、リサイズ、getImageData()によるピクセルデータの読み取り、バケット平均の計算まで、このプロセス全体はブラウザのメモリ内でローカルに実行されます。写真がサーバーにアップロードされることは一切ありません。

よくある質問

このツールはなぜ単純に最も一般的な色を1つだけ見つけないのですか?

実際の写真では、まったく同じRGB値を共有するピクセルのペアはほとんど存在しないからです。自然光、センサーノイズ、圧縮によって、目には同じに見える色でも数値上はわずかに異なります。そのため、意味を持つほど頻繁に繰り返される正確な値は存在しません。近い色を先にバケットへグループ化することで、この集計が初めて意味を持つようになります。

パレットはいくつの色を表示しますか?

最大8色です。このツールはすべてのピクセルを512個の可能な色バケット(赤・緑・青それぞれ8段階)にグループ化し、その中で最もピクセル数の多い6〜8個のバケットを表示します。非常にシンプルでほぼ単色に近い画像では、埋まっているバケットが少数しかない場合、表示される色も少なくなることがあります。

これはGIF画像の作成に使われているのと同じ技術ですか?

完全に同じではありませんが、近い関係にあります。GIFは通常、固定グリッドではなく色空間を再帰的に分割する、1980年に登場したより高度な量子化アルゴリズムであるメディアンカットを使って256色に縮小されます。このツールは、計算が速く理解しやすい、よりシンプルな固定サイズのヒストグラムビニングを使用しており、その分、複雑な画像における知覚的な精度は多少犠牲になります。

ここで写真をアップロードすると、サーバーに送信されますか?

いいえ——画像はブラウザ内で完結してcanvas要素にデコード・描画され、すべてのピクセルはcanvasのgetImageData() APIを使ってローカルで読み取り・解析されます。写真に関する情報がどこかへ送信されることは一切ありません。

なぜ分析の前に画像がリサイズされるのですか?

純粋に処理速度のためです。フル解像度の写真のすべてのピクセルを読み取ってバケットに割り当てると、数千万個もの値を処理することになりかねません。あらかじめ画像の幅を最大200pxに縮小しておくことで、この処理量を大幅に削減できる一方、結果はほとんど変わりません。支配的な色は細部ではなく、大きな領域によって決まるからです。

コメント

まだコメントはありません — 最初のコメントを書いてみましょう!

関連ツール