【PHP実践|実務向け】PHPで実現する画像類似度検索 – Lab色空間を活用した実装手法

導入

Webアプリケーション開発において、「類似画像の検索」や「重複画像の検知」は非常に需要の高い機能です。しかし、ピクセル単位で完全に一致する画像を探すのは簡単ですが、リサイズや圧縮形式の変更などによって微妙に異なる画像同士を判定するのは困難です。本記事では、Lab色空間を用いた、視覚的な色味に基づいた画像比較手法について解説します。この手法を導入することで、ユーザーがアップロードした画像とデータベース内の既存画像との類似度をロジックで判定することが可能になります。

基礎知識

画像の類似度を比較する場合、単にRGB値をそのまま比較するだけでは、人間の目に見える「色の近さ」を正しく表現できません。そこで利用されるのがLab色空間です。
Lab色空間は、L(明度)、a(赤-緑成分)、b(黄-青成分)の3つの軸で色を定義します。この空間は「知覚的に均等」であるという特徴があり、空間上の2点間のユークリッド距離を計算することで、人間が感じる色の差に近い値を算出できます。PHPでこの色空間を扱うには、RGBからXYZ表色系を経由してLabに変換する数学的な計算が必要となります。

実装/解決策

実装の手順は以下の通りです。
1. 比較する画像を共通の小さなサイズ(例: 4×4ピクセル)にリサイズします。これにより、微細なノイズを無視しつつ色味の特徴を抽出します。
2. リサイズした画像の各ピクセルのRGB値を取得します。
3. RGB値をLab色空間の座標に変換します。
4. 比較元画像と対象画像のLab座標同士の距離を算出し、その合計が小さいものほど「似ている」と判断します。

サンプルプログラム

以下のコードは、指定ディレクトリ内の画像群から、基準画像に最も近いものを判定する一例です。

  • 簡易的な画像類似度比較スクリプト
  • /

    // 比較対象の画像ディレクトリと基準画像
    $target_dir = “images/”;
    $sample_file = “sample.jpg”;

    // 画像をロードしてLab色空間の配列を生成
    $sample_lab = get_image_lab_data($sample_file);

    $results = [];
    foreach (glob($target_dir . “.{jpg,png,gif}”, GLOB_BRACE) as $file) {
    $current_lab = get_image_lab_data($file);

    // 各ピクセルのLab距離を合計する
    $total_distance = 0;
    foreach ($sample_lab as $index => $lab) {
    $total_distance += calculate_lab_distance($lab, $current_lab[$index]);
    }
    $results[basename($file)] = $total_distance;
    }

    // 距離が小さい順(類似度が高い順)にソート
    asort($results);

    // 結果の表示
    foreach ($results as $filename => $distance) {
    echo “ファイル名: $filename, 距離: $distance
    “;
    }

    // 画像を4×4に縮小してLab値の配列を返す関数
    function get_image_lab_data($filepath) {
    $img = imagecreatefromjpeg($filepath); // 実際には拡張子に応じた関数を使用してください
    $thumb = imagecreatetruecolor(4, 4);
    imagecopyresampled($thumb, $img, 0, 0, 0, 0, 4, 4, imagesx($img), imagesy($img));

    $lab_data = [];
    for ($x = 0; $x < 4; $x++) { for ($y = 0; $y < 4; $y++) { $rgb = imagecolorsforindex($thumb, imagecolorat($thumb, $x, $y)); $lab_data[] = rgb2lab([$rgb['red'], $rgb['green'], $rgb['blue']]); } } imagedestroy($img); imagedestroy($thumb); return $lab_data; } // Lab距離計算(ユークリッド距離) function calculate_lab_distance($p1, $p2) { return sqrt(pow($p2[0] - $p1[0], 2) + pow($p2[1] - $p1[1], 2) + pow($p2[2] - $p1[2], 2)); } // ※rgb2lab関数等は、前述の変換公式を組み込んで実装してください。 ?>

    応用・注意点

    1. パフォーマンスの考慮: 画像の枚数が数千件を超える場合、毎回計算を行うとサーバー負荷が非常に高くなります。実務では、事前にサムネイルのLab値を抽出し、データベースへ保存しておくことを強く推奨します。
    2. 解像度のトレードオフ: サンプルでは4×4ピクセルにしていますが、精度を上げようとしてサイズを大きくしすぎると、計算量が指数関数的に増大します。用途に合わせて16×16程度までで調整するのが現実的です。
    3. 透明色の扱い: PNGなどの透過画像を扱う場合、透明部分が黒として計算されることがあります。必要に応じて背景を白で塗りつぶす等の前処理を行ってください。

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