過去に類似画像を検索する方法はいくつか提示しましたが、おそらく今回の手法が一番多く使われているものです。
このプログラムでは、用意された画像をもとに、フォルダ内にある複数の画像の中から最も似た画像を探し、似ているものから順番に並べます。
原理はいたってシンプルで、比較元の画像と比較先の画像を小さな画像に変換し、1ピクセルずつ RGB 値を取得します。
あとは RGB を Lab 色空間上の座標に変換し、同じ座標同士の距離を比較し、近いものから順番にソートします。
RGB を Lab に変換するには一旦 xyz 表色系に変換し、それを Lab に変換する必要があります。
詳細については以前の記事を御覧下さい。
<?php //比較元となる画像 $filepath = "sample.jpg"; //比較対象用画像ディレクトリ $dir = "images/"; $sample = load_image($filepath); $sample_lab = image_lab($sample); imagedestroy($sample); $list = scandir($dir); $files = array(); foreach($list as $value){ if(is_file($dir . $value)){ $files[] = $dir . $value; } } $diff = array(); foreach($files as $file){ $image = load_image($file); $lab = image_lab($image); imagedestroy($image); $name = basename($file); $distance = 0; foreach($sample_lab as $key => $value){ $distance += lab_distance($value, $lab[$key]); } $diff[$name] = $distance; } asort($diff); $result = array_keys($diff); header("Content-type: text/html;charset=utf-8"); foreach($result as $img){ echo '<img src="' . $dir . $img . '" width="50" height="50" alt="" />'; } // 画像の読み込み function load_image($filepath){ $checkimg = getimagesize($filepath); if($checkimg['mime'] == "image/jpeg" || $checkimg['mime'] == "image/pjpeg"){ $extension = "jpg"; } else if ($checkimg['mime'] == "image/gif"){ $extension = "gif"; } else if ($checkimg['mime'] == "image/png" || $checkimg['mime'] == "image/x-png"){ $extension = "png"; } else { exit; } if($extension == 'jpg'){$image = ImageCreateFromJPEG($filepath);} if($extension == 'gif'){$image = ImageCreateFromGIF($filepath);} if($extension == 'png'){$image = ImageCreateFromPNG($filepath);} return $image; } // 画像をリサイズしピクセルごとのLab色空間上の座標を取得する function image_lab($image){ $width = imagesx($image); $height = imagesy($image); $thumb_width = 4; $thumb_height = 4; $thumb = imagecreatetruecolor($thumb_width, $thumb_height); imagecopyresampled($thumb, $image, 0, 0, 0, 0, $thumb_width, $thumb_height, $width, $height); $lab = array(); $red = 0; $green = 0; $blue = 0; for($x=0; $x < $thumb_width; $x++){ for($y=0; $y < $thumb_height; $y++){ $index = imagecolorat($thumb, $x, $y); $rgb = imagecolorsforindex($thumb, $index); $lab[] = rgb2lab( array($rgb['red'], $rgb['green'], $rgb['blue']) ); } } return $lab; } // xyz色空間上の座標をlab色空間上の座標に変換する function xyz2lab($xyz) { $threshold = 0.008856; //Chromatic Adaptation Matrices // D50 $ref_x = 0.96422; $ref_y = 1.0000; $ref_z = 0.82521; $var_x = $xyz[0] / ($ref_x * 100); $var_y = $xyz[1] / ($ref_y * 100); $var_z = $xyz[2] / ($ref_z * 100); $var_x = ($var_x > $threshold) ? $var_x = pow($var_x, 1/3 ) : (7.787 * $var_x) + (16 / 116); $var_y = ($var_y > $threshold) ? $var_y = pow($var_y, 1/3 ) : (7.787 * $var_y) + (16 / 116); $var_z = ($var_z > $threshold) ? $var_z = pow($var_z, 1/3 ) : (7.787 * $var_z) + (16 / 116); $l = ( 116 * $var_y ) - 16; $a = 500 * ( $var_x - $var_y ); $b = 200 * ( $var_y - $var_z ); $lab = array(); $lab = array($l, $a, $b); return $lab; } // rgb値をxyz色空間上の座標に変換する function rgb2xyz($rgb) { $r = $rgb[0] / 255; $g = $rgb[1] / 255; $b = $rgb[2] / 255; $r = ($r > 0.04045) ? pow(($r + 0.055) / 1.055, 2.4) : $r / 12.92; $g = ($g > 0.04045) ? pow(($g + 0.055) / 1.055, 2.4) : $g / 12.92; $b = ($b > 0.04045) ? pow(($b + 0.055) / 1.055, 2.4) : $b / 12.92; $r = $r * 100; $g = $g * 100; $b = $b * 100; $xyz = array(); //sRGB D50 $xyz[] = $r * 0.4360747 + $g * 0.3850649 + $b * 0.1430804; $xyz[] = $r * 0.2225045 + $g * 0.7168786 + $b * 0.0606169; $xyz[] = $r * 0.0139322 + $g * 0.0971045 + $b * 0.7141733; return $xyz; } // rgb値をlab色空間上の座標に変換する function rgb2lab($rgb) { $xyz = rgb2xyz($rgb); $lab = xyz2lab($xyz); return $lab; } // 2つの座標を比較し距離を返す function lab_distance($p1, $p2){ $dist = sqrt( pow($p2[0] - $p1[0], 2) + pow($p2[1] - $p1[1], 2) + pow($p2[2] - $p1[2], 2) ); return $dist; }
このサンプルでは画像のサイズ( $thumb_width, $thumb_height )を 4×4 に統一したものを比較しています。
より厳密な一致を求めるならこの数字を大きくします。ただし計算量が多くなるので気をつけて下さい。
Similar Posts:
- [PHP]HSV(HSB)色空間を比較して似た色合いの画像を検索する
- [PHP]似た色合いの画像をRGB値をもとに探す
- [PHP]複数の画像をランダムに敷き詰めて一枚の画像に合成
- [PHP]画像を上下反転、左右反転する(垂直・水平方向の鏡像)
- [PHP]画像ファイルのアップロードとGDを使ったリサイズ
- [PHP][HTML, CSS]画像を隙間なく並べて表示
- [PHP]多階層ディレクトリ内のファイル一覧を取得する
- [JS]画像ファイルアップロード前にプレビューを表示する