PHP で画像比較

2つの画像がどの位違うのかを数値化するプログラムです。

ピクセル毎の色の違いを合計するだけの簡単な比較です。
一応、教科書の初めに出てくるような一般的な手法で、SSD (sum of squared difference) という名前が付いています。

  • 画像サイズがだいたい合ってないとダメ (縦、又は横が2倍違うとエラー)
    • エラーがマズイ人はエラーの代わりに適切な値を返すように変更して下さい。
  • 非対称な画像が回転してたり、部分的に一致してる場合とかは考慮していません。
    • あくまで殆ど同じ画像かどうかだけ。
  • 終結果はRGB色空間(0,0,0)-(255,255,255)の平均距離の2乗値です。
  • 画像フォーマットは、少なくとも PNG, GIF, JPEG の3種類に対応してます。(後は GD ライブラリ次第)
  • コードは見やすさ優先です。
    • 速さを追求したい人は while($x) { $x-- ;... とか自分で変えて下さい。

10分で作った割に、意外と使えそうなのでコードを晒します。

<?php

  /*
   * dissimilarity measure
   * sum of squared difference
   * 2011/10/13- yoya@awm.jp
   */

function usage() {
    echo "Usage: php bitmap_comp.php <file1> <file2>\n";
}

if (($argc != 3) || (! is_readable($argv[1])) || (! is_readable($argv[2]))) {
    usage();
    exit (1);
}

$data1 = file_get_contents($argv[1]);
$data2 = file_get_contents($argv[2]);
$im1 = imagecreatefromstring($data1);
$im2 = imagecreatefromstring($data2);

if ($im1 === false || $im2 === false) {
   echo "Error: image1 or image2 has broken.";
   exit (1);
}

$width1  = imagesx($im1); $height1 = imagesy($im1);
$width2  = imagesx($im2); $height2 = imagesy($im2);

$width_ratio  = $width2 / $width1;
$height_ratio = $height2 / $height1;

if ($width_ratio < 0.5 || 2.0 < $width_ratio ||
    $height_ratio < 0.5 || 2.0 < $height_ratio) {
    echo "Error: image1(".$width1."x".$height1.") image2(".$width2."x".$height2.")\n";
    exit (1);
}

$width = min($width1, $width2);
$height = min($height1, $height2);

$distance_square_sum = 0;

for ($y = 0 ; $y < $height ; $y++) {
    for ($x = 0 ; $x < $width ; $x++) {
        $i1 = imagecolorat($im1, $x, $y);
        $i2 = imagecolorat($im2, $x, $y);
        $rgb1 = imagecolorsforindex($im1, $i1);
        $rgb2 = imagecolorsforindex($im2, $i2);
        $red_diff   = $rgb1['red']   - $rgb2['red'];
        $green_diff = $rgb1['green'] - $rgb2['green'];
        $blue_diff  = $rgb1['blue']  - $rgb2['blue'];
        $distance_square_sum += $red_diff*$red_diff + $green_diff*$green_diff + $blue_diff*$blue_diff;
    }
}

echo $distance_square_sum / ($width * $height) . "\n";