PHP实现搜索相似图片

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

感知哈希算法

count < =5 匹配最相似

count > 10 两张不同的图片

var_dump(ImageHash::run(‘./1.png', ‘./psb.jpg'));

  1. <?php
  2. class ImageHash {
  3. const FILE_NOT_FOUND = '-1';
  4. const FILE_EXTNAME_ILLEGAL = '-2';
  5. private function __construct() {}
  6. public static function run($src1, $src2) {
  7. static $self;
  8. if(!$self) $self = new static;
  9. if(!is_file($src1) || !is_file($src2)) exit(self::FILE_NOT_FOUND);
  10. $hash1 = $self->getHashValue($src1);
  11. $hash2 = $self->getHashValue($src2);
  12. if(strlen($hash1) !== strlen($hash2)) return false;
  13. $count = 0;
  14. $len = strlen($hash1);
  15. for($i = 0; $i < $len; $i++) if($hash1[$i] !== $hash2[$i]) $count++;
  16. return $count <= 10 ? true : false;
  17. }
  18. public function getImage($file) {
  19. $extname = pathinfo($file, PATHINFO_EXTENSION);
  20. if(!in_array($extname, ['jpg','jpeg','png','gif'])) exit(self::FILE_EXTNAME_ILLEGAL);
  21. $img = call_user_func('imagecreatefrom'. ( $extname == 'jpg' ? 'jpeg' : $extname ) , $file);
  22. return $img;
  23. }
  24. public function getHashValue($file) {
  25. $w = 8;
  26. $h = 8;
  27. $img = imagecreatetruecolor($w, $h);
  28. list($src_w, $src_h) = getimagesize($file);
  29. $src = $this->getImage($file);
  30. imagecopyresampled($img, $src, 0, 0, 0, 0, $w, $h, $src_w, $src_h);
  31. imagedestroy($src);
  32. $total = 0;
  33. $array = array();
  34. for( $y = 0; $y < $h; $y++) {
  35. for ($x = 0; $x < $w; $x++) {
  36. $gray = (imagecolorat($img, $x, $y) >> 8) & 0xFF;
  37. if(!isset($array[$y])) $array[$y] = array();
  38. $array[$y][$x] = $gray;
  39. $total += $gray;
  40. }
  41. }
  42. imagedestroy($img);
  43. $average = intval($total / ($w * $h * 2));
  44. $hash = '';
  45. for($y = 0; $y < $h; $y++) {
  46. for($x = 0; $x < $w; $x++) {
  47. $hash .= ($array[$y][$x] >= $average) ? '1' : '0';
  48. }
  49. }
  50. var_dump($hash);
  51. return $hash;
  52. }
  53. }

var_dump(ImageHash::run('./1.png', './psb.jpg'));

方法二:

  1. hash($f);
  2. }
  3. return $isString ? $result[0] : $result;
  4. }
  5. public function checkIsSimilarImg($imgHash, $otherImgHash){
  6. if (file_exists($imgHash) && file_exists($otherImgHash)){
  7. $imgHash = $this->run($imgHash);
  8. $otherImgHash = $this->run($otherImgHash);
  9. }
  10. if (strlen($imgHash) !== strlen($otherImgHash)) return false;
  11. $count = 0;
  12. $len = strlen($imgHash);
  13. for($i=0;$i<$len;$i++){
  14. if ($imgHash{$i} !== $otherImgHash{$i}){
  15. $count++;
  16. }
  17. }
  18. return $count <= (5 * $rate * $rate) ? true : false;
  19. }
  20. public function hash($file){
  21. if (!file_exists($file)){
  22. return false;
  23. }
  24. $height = 8 * $this->rate;
  25. $width = 8 * $this->rate;
  26. $img = imagecreatetruecolor($width, $height);
  27. list($w, $h) = getimagesize($file);
  28. $source = $this->createImg($file);
  29. imagecopyresampled($img, $source, 0, 0, 0, 0, $width, $height, $w, $h);
  30. $value = $this->getHashValue($img);
  31. imagedestroy($img);
  32. return $value;
  33. }
  34. public function getHashValue($img){
  35. $width = imagesx($img);
  36. $height = imagesy($img);
  37. $total = 0;
  38. $array = array();
  39. for ($y=0;$y<$height;$y++){
  40. for ($x=0;$x<$width;$x++){
  41. $gray = ( imagecolorat($img, $x, $y) >> 8 ) & 0xFF;
  42. if (!is_array($array[$y])){
  43. $array[$y] = array();
  44. }
  45. $array[$y][$x] = $gray;
  46. $total += $gray;
  47. }
  48. }
  49. $average = intval($total / (64 * $this->rate * $this->rate));
  50. $result = '';
  51. for ($y=0;$y<$height;$y++){
  52. for ($x=0;$x<$width;$x++){
  53. if ($array[$y][$x] >= $average){
  54. $result .= '1';
  55. }else{
  56. $result .= '0';
  57. }
  58. }
  59. }
  60. return $result;
  61. }
  62. public function createImg($file){
  63. $ext = $this->getFileExt($file);
  64. if ($ext === 'jpeg') $ext = 'jpg';
  65. $img = null;
  66. switch ($ext){
  67. case 'png' : $img = imagecreatefrompng($file);break;
  68. case 'jpg' : $img = imagecreatefromjpeg($file);break;
  69. case 'gif' : $img = imagecreatefromgif($file);
  70. }
  71. return $img;
  72. }
  73. public function getFileExt($file){
  74. $infos = explode('.', $file);
  75. $ext = strtolower($infos[count($infos) - 1]);
  76. return $ext;
  77. }
  78. }

调用方式如下:

  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个图片相似,否则不相似。