【PHP実践|実務向け】PHPとGDライブラリで実現する「平均色」ベースの画像比較ロジック

導入

Web開発において、ユーザーがアップロードした画像と既存の画像を比較し、似た色合いの画像を見つけ出したいというニーズは少なくありません。例えば、ECサイトでの商品レコメンドや、画像投稿サイトでの重複チェックなどが挙げられます。今回は、PHPの標準的な画像処理ライブラリ「GD」を用いて、画像の「平均色」を算出し、それをもとに類似画像を特定する手法を解説します。

基礎知識

画像の類似検索において最もシンプルなアプローチの一つが、画像全体の「平均RGB値」を算出することです。
RGB(Red, Green, Blue)は、光の三原色を数値化したもので、各0〜255の範囲で表現されます。画像全体の色情報を平均化することで、その画像が全体的に「赤っぽいのか」「青っぽいのか」という特徴量を数値化できます。GDライブラリのimagecopyresampledを使用すれば、画像を小さなサムネイルに縮小することで、計算コストを大幅に抑えつつ色分布を抽出することが可能です。

実装/解決策

画像比較のステップは以下の通りです。
1. 画像を読み込み、16×16ピクセル程度の極小サイズに縮小する。
2. 縮小した各ピクセルのRGB値を合計し、ピクセル数で割って平均値を算出する。
3. 比較対象となる全画像に対してこの処理を行い、基準画像との「色の距離」を算出する。
4. 距離が近い順にソートして結果を返す。

サンプルプログラム

  • 指定した画像の平均RGB値を算出する関数
  • /
    function getAverageColor($filepath) {
    $image = @imagecreatefromstring(file_get_contents($filepath));
    if (!$image) return null;

    $thumb = imagecreatetruecolor(16, 16);
    // 計算速度向上のため、16×16に縮小して色を平均化
    imagecopyresampled($thumb, $image, 0, 0, 0, 0, 16, 16, imagesx($image), imagesy($image));

    $red = $green = $blue = 0;
    for ($x = 0; $x < 16; $x++) { for ($y = 0; $y < 16; $y++) { $rgb = imagecolorat($thumb, $x, $y); $red += ($rgb >> 16) & 0xFF;
    $green += ($rgb >> 8) & 0xFF;
    $blue += $rgb & 0xFF;
    }
    }
    imagedestroy($image);
    imagedestroy($thumb);

    $pixelCount = 16 16;
    return [
    ‘r’ => $red / $pixelCount,
    ‘g’ => $green / $pixelCount,
    ‘b’ => $blue / $pixelCount
    ];
    }

    /

    • 二つのRGB値の距離(マンハッタン距離)を計算

    /
    function getColorDistance($c1, $c2) {
    return abs($c1[‘r’] – $c2[‘r’]) + abs($c1[‘g’] – $c2[‘g’]) + abs($c1[‘b’] – $c2[‘b’]);
    }

    // 実行例
    $baseColor = getAverageColor(‘target.jpg’);
    $candidates = [‘img1.jpg’, ‘img2.jpg’, ‘img3.jpg’];
    $results = [];

    foreach ($candidates as $file) {
    $color = getAverageColor($file);
    if ($color) {
    $results[$file] = getColorDistance($baseColor, $color);
    }
    }

    // 距離が小さい順(似ている順)にソート
    asort($results);
    print_r($results);
    ?>

    応用・注意点

    この手法は実装が容易である一方、現場レベルではいくつかの限界があります。
    1. 明暗の影響を受けやすい
    RGB平均では、黒っぽい画像と鮮やかな画像が同じ色相であっても「距離」が遠くなります。より高度な検索が必要な場合は、RGBを「HSV(色相・彩度・明度)」や「Lab色空間」に変換して比較することをおすすめします。これにより、明暗を除外した「色味そのものの比較」が可能になります。
    2. パフォーマンス
    大量の画像をリアルタイムでスキャンする場合、毎回画像を開いて計算するのは非効率です。あらかじめアップロード時に平均色を計算し、DBのカラムに格納しておく(インデックスを貼る)運用が、実務上の定石です。

    タイトルとURLをコピーしました