Imghash:相似图片搜索的php实现

图片相似搜索的简单原理

根据文章里的描述,其实原理比较简单,大致有如下几个步骤:

1、缩小尺寸。将图片缩小到8×8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

2、简化色彩。将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

3、计算平均值。计算所有64个像素的灰度平均值。

4、比较像素的灰度。将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

5、计算哈希值。将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。

这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。

 

图片相似搜索的PHP实现

PHP代码
  1. /** 
  2.  *  
  3.  * 相似图片搜索hash的php实现 
  4.  * @author welefen 
  5.  * 
  6.  */  
  7. class Imghash{  
  8.       
  9.     private static $_instance = null;  
  10.       
  11.     public $rate = 2;  
  12.       
  13.     public static function getInstance(){  
  14.         if (self::$_instance === null){  
  15.             self::$_instance = new self();  
  16.         }  
  17.         return self::$_instance;  
  18.     }  
  19.     public function run($file){  
  20.         if (!function_exists('imagecreatetruecolor')){  
  21.             throw new Exception('must load gd lib', 1);  
  22.         }  
  23.         $isString = false;  
  24.         if (is_string($file)){  
  25.             $file = array($file);  
  26.             $isString = true;  
  27.         }  
  28.         $result = array();  
  29.         foreach ($file as $f){  
  30.             $result[] = $this->hash($f);  
  31.         }  
  32.         return $isString ? $result[0] : $result;  
  33.     }  
  34.     public function checkIsSimilarImg($imgHash$otherImgHash){  
  35.         if (file_exists($imgHash) && file_exists($otherImgHash)){  
  36.             $imgHash = $this->run($imgHash);  
  37.             $otherImgHash = $this->run($otherImgHash);  
  38.         }  
  39.         if (strlen($imgHash) !== strlen($otherImgHash)) return false;  
  40.         $count = 0;  
  41.         $len = strlen($imgHash);  
  42.         for($i=0;$i<$len;$i++){  
  43.             if ($imgHash{$i} !== $otherImgHash{$i}){  
  44.                 $count++;  
  45.             }  
  46.         }  
  47.         return $count <= (5 * $rate * $rate) ? true : false;  
  48.     }  
  49.     public function hash($file){  
  50.         if (!file_exists($file)){  
  51.             return false;  
  52.         }  
  53.         $height = 8 * $this->rate;  
  54.         $width = 8 * $this->rate;  
  55.         $img = imagecreatetruecolor($width$height);  
  56.         list($w$h) = getimagesize($file);  
  57.         $source = $this->createImg($file);  
  58.         imagecopyresampled($img$source, 0, 0, 0, 0, $width$height$w$h);  
  59.         $value = $this->getHashValue($img);  
  60.         imagedestroy($img);  
  61.         return $value;  
  62.     }  
  63.     public function getHashValue($img){  
  64.         $width = imagesx($img);  
  65.         $height = imagesy($img);  
  66.         $total = 0;  
  67.         $array = array();  
  68.         for ($y=0;$y<$height;$y++){  
  69.             for ($x=0;$x<$width;$x++){  
  70.                 $gray = ( imagecolorat($img$x$y) >> 8 ) & 0xFF;  
  71.                 if (!is_array($array[$y])){  
  72.                     $array[$y] = array();  
  73.                 }  
  74.                 $array[$y][$x] = $gray;  
  75.                 $total += $gray;  
  76.             }  
  77.         }  
  78.         $average = intval($total / (64 * $this->rate * $this->rate));  
  79.         $result = '';  
  80.         for ($y=0;$y<$height;$y++){  
  81.             for ($x=0;$x<$width;$x++){  
  82.                 if ($array[$y][$x] >= $average){  
  83.                     $result .= '1';  
  84.                 }else{  
  85.                     $result .= '0';  
  86.                 }  
  87.             }  
  88.         }  
  89.         return $result;  
  90.     }  
  91.     public function createImg($file){  
  92.         $ext = $this->getFileExt($file);  
  93.         if ($ext === 'jpeg'$ext = 'jpg';  
  94.         $img = null;  
  95.         switch ($ext){  
  96.             case 'png' : $img = imagecreatefrompng($file);break;  
  97.             case 'jpg' : $img = imagecreatefromjpeg($file);break;  
  98.             case 'gif' : $img = imagecreatefromgif($file);  
  99.         }  
  100.         return $img;  
  101.     }  
  102.     public function getFileExt($file){  
  103.         $infos = explode('.'$file);  
  104.         $ext = strtolower($infos[count($infos) - 1]);  
  105.         return $ext;  
  106.     }  
  107. }  

 

调用方式如下:

PHP代码
  1. require_once "Imghash.class.php";  
  2. $instance = ImgHash::getInstance();  
  3. $result = $instance->checkIsSimilarImg('chenyin/IMG_3214.png''chenyin/IMG_3212.JPG');  
 

如果$result值为true, 则表明2个图片相似,否则不相似。

 

 

其他

 

在实际的相似图片搜索中,算图片的指纹并不是难点,难点而是在怎么从海量的图片指纹里找出与之相似的指纹。

原文链接:http://www.welefen.com/similar-image-search-in-php.html

 



上一篇: php addslashes及其他清除空格的方法是不安全的
下一篇: VB实现Asp中的server.urlencode功能
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: php
相关日志:
评论: 1 | 引用: 0 | 查看次数: 6101
anitee[2013-05-20 05:06 PM | | Mail To:anitee0208@gmail.com | 114.92.129.51 | del | 回复回复]
沙发
话说,俺测试了下,只有两张图片一模一样的时候才返回true,其余再怎么相似都是false,不知道博主测试过没有?
发表评论
昵 称:
密 码: 游客发言不需要密码.
邮 箱: 邮件地址支持Gravatar头像,邮箱地址不会公开.
网 址: 输入网址便于回访.
内 容:
验证码:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭

 广告位

↑返回顶部↑