導入
Webアプリケーションにおいて「似た画像を探す」機能は、商品検索やレコメンドエンジン、重複画像排除などの場面で非常に有用です。しかし、単純なバイナリ比較では画像のわずかな違いに対応できません。本記事では、PHPを用いて画像を低解像度にリサイズし、色空間の特性を活かして類似度を判定する実務的なアプローチを解説します。
基礎知識
類似画像検索の基本ステップは「特徴の抽出」と「比較」です。画像を3×3ピクセルといった小さなサイズに縮小することで、ノイズを排除しつつ全体的な色の特徴を抽出できます。ここで重要なのが「色空間」の選択です。
RGBはコンピュータには扱いやすいですが、人間の知覚とは乖離があります。HSV(色相・彩度・明度)は計算が高速で、ある程度の類似度判定には適していますが、極端な明度(白や黒に近い色)での判定精度に課題があります。より精緻な判定にはLab色空間を用い、ユークリッド距離で色の差を算出するのが定石です。
実装/解決策
実務では、検索速度を担保するために「事前計算(インデックス化)」が不可欠です。アップロード時に画像を9分割(または縮小)して色情報をDBに保存しておきます。検索時は、このインデックス値とクエリ画像の値を比較します。全件走査を避けるため、明度(V)でグループ化して候補を絞り込む手法が有効です。
サンプルプログラム
以下のコードは、GDライブラリを使用して画像を縮小し、各ピクセルのRGB情報を取得する基本的なロジックです。
/ $colors = []; // 使用例
function getAverageColors(string $imagePath): array {
// 画像を読み込み、3x3のサイズにリサイズ
$src = imagecreatefromjpeg($imagePath);
$small = imagecreatetruecolor(3, 3);
imagecopyresampled($small, $src, 0, 0, 0, 0, 3, 3, imagesx($src), imagesy($src));
for ($y = 0; $y < 3; $y++) {
for ($x = 0; $x < 3; $x++) {
$rgb = imagecolorat($small, $x, $y);
// RGB値を分解して配列に格納
$colors[] = [
'r' => ($rgb >> 16) & 0xFF,
'g' => ($rgb >> 8) & 0xFF,
'b' => $rgb & 0xFF
];
}
}
imagedestroy($src);
imagedestroy($small);
return $colors;
}
$imagePath = 'sample.jpg';
$pixelData = getAverageColors($imagePath);
print_r($pixelData); // 9つのブロックごとのRGB値が出力される
?>
応用・注意点
1. パフォーマンスの最適化:数万枚以上の画像がある場合、PHPで毎回計算するのは非効率です。特徴量を抽出する処理は、非同期タスク(LaravelのQueueやRabbitMQなど)として別プロセスで実行し、DBには計算済みの値を保存してください。
2. 精度の向上:HSV比較で精度が足りない場合は、Lab色空間への変換ライブラリの導入を検討してください。また、ユーザーのクリックログを収集し、ナイーブベイズ分類器等を用いて「ユーザーが好む類似性」を学習させると、検索精度が飛躍的に向上します。
3. バリデーション:画像フォーマットや破損ファイルによるエラーは頻発するため、`getimagesize()`や例外処理でのガードを徹底してください。