利用php實現圖片相似度搜索的簡單原理

幾天看到阮一峯的博客裏寫到關於相似圖片搜索的原理, 裏面介紹了Google相似圖片搜索的大致原理,主要是從Neal Krawetz博士的LOOKS LIKE IT翻譯而來。文章詳細的介紹了相似圖片搜索處理的相關步驟,並且給出了一個python的實現,由於我對PHP比較熟,所以寫了個PHP的版本。
 
圖片相似搜索的簡單原理
 
根據文章裏的描述,其實原理比較簡單,大致有如下幾個步驟:
 
1、縮小尺寸。將圖片縮小到8×8的尺寸,總共64個像素。這一步的作用是去除圖片的細節,只保留結構、明暗等基本信息,摒棄不同尺寸、比例帶來的圖片差異。
 
2、簡化色彩。將縮小後的圖片,轉爲64級灰度。也就是說,所有像素點總共只有64種顏色。
 
3、計算平均值。計算所有64個像素的灰度平均值。
 
4、比較像素的灰度。將每個像素的灰度,與平均值進行比較。大於或等於平均值,記爲1;小於平均值,記爲0。
 
5、計算哈希值。將上一步的比較結果,組合在一起,就構成了一個64位的整數,這就是這張圖片的指紋。組合的次序並不重要,只要保證所有圖片都採用同樣次序就行了。得到指紋以後,就可以對比不同的圖片,看看64位中有多少位是不一樣的。
 
這種算法的優點是簡單快速,不受圖片大小縮放的影響,缺點是圖片的內容不能變更。實際應用中,往往採用更強大的pHash算法和SIFT算法,它們能夠識別圖片的變形。只要變形程度不超過25%,它們就能匹配原圖。
 
圖片相似搜索的PHP實現
 
原文中給出了一個python版本的實現,代碼只有53行。我寫了個對應的PHP版本,由於直接是用類寫的,所以代碼有100行,具體如下:
 
hash($f);
}
return $isString ? $result[0] : $result;
}
public function checkIsSimilarImg($imgHash, $otherImgHash){
if (file_exists($imgHash) && file_exists($otherImgHash)){
$imgHash = $this->run($imgHash);
$otherImgHash = $this->run($otherImgHash);
}
if (strlen($imgHash) !== strlen($otherImgHash)) return false;
$count = 0;
$len = strlen($imgHash);
for($i=0;$i<$len;$i++){
if ($imgHash{$i} !== $otherImgHash{$i}){
$count++;
}
}
return $count <= (5 * $rate * $rate) ? true : false;
}
public function hash($file){
if (!file_exists($file)){
return false;
}
$height = 8 * $this->rate;
$width = 8 * $this->rate;
$img = imagecreatetruecolor($width, $height);
list($w, $h) = getimagesize($file);
$source = $this->createImg($file);
imagecopyresampled($img, $source, 0, 0, 0, 0, $width, $height, $w, $h);
$value = $this->getHashValue($img);
imagedestroy($img);
return $value;
}
public function getHashValue($img){
$width = imagesx($img);
$height = imagesy($img);
$total = 0;
$array = array();
for ($y=0;$y<$height;$y++){
for ($x=0;$x<$width;$x++){
$gray = ( imagecolorat($img, $x, $y) >> 8 ) & 0xFF;
if (!is_array($array[$y])){
$array[$y] = array();
}
$array[$y][$x] = $gray;
$total += $gray;
}
}
$average = intval($total / (64 * $this->rate * $this->rate));
$result = '';
for ($y=0;$y<$height;$y++){
for ($x=0;$x<$width;$x++){
if ($array[$y][$x] >= $average){
$result .= '1';
}else{
$result .= '0';
}
}
}
return $result;
}
public function createImg($file){
$ext = $this->getFileExt($file);
if ($ext === 'jpeg') $ext = 'jpg';
$img = null;
switch ($ext){
case 'png' : $img = imagecreatefrompng($file);break;
case 'jpg' : $img = imagecreatefromjpeg($file);break;
case 'gif' : $img = imagecreatefromgif($file);
}
return $img;
}
public function getFileExt($file){
$infos = explode('.', $file);
$ext = strtolower($infos[count($infos) - 1]);
return $ext;
}
}
調用方式如下:
 
require_once "Imghash.class.php";
$instance = ImgHash::getInstance();
$result = $instance->checkIsSimilarImg('chenyin/IMG_3214.png', 'chenyin/IMG_3212.JPG');
如果$result值爲true, 則表明2個圖片相似,否則不相似。
 
 
 
其他
 
在實際的相似圖片搜索中,算圖片的指紋並不是難點,難點而是在怎麼從海量的圖片指紋裏找出與之相似的指紋。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章