2013-05-20 22:41

[PHP] aHash, pHash, dHash 實做

  1. <?php 
  2. /** 
  3. * 圖片特徵 Hash 計算 
  4. * 
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax $ 
  6. * @author      jax.hu 
  7. * 
  8. * <code> 
  9. *  //Sample_1 
  10. *  $hashA = ImageHash::pHash('001.jpg'); 
  11. *  $hashB = ImageHash::pHash('002.jpg'); 
  12. *  if(ImageHash::isSimilar($hashA, $hashB)){ 
  13. * 
  14. *  } 
  15. * 
  16. * </code> 
  17. */ 
  18.  
  19. class ImageHash { 
  20.  
  21.    /**讀取圖片至指定大小*/ 
  22.    public static function readImageTo($imagePath, $width, $height){ 
  23.        if(!$imagePath || !file_exists($imagePath)){ return null; } 
  24.  
  25.        if(class_exists('Imagick')){ 
  26.            $image = new Imagick($imagePath); 
  27.            $image->thumbnailImage($width, $height); 
  28.            $img = imagecreatefromstring($image->getImageBlob()); 
  29.            $image->destroy(); $image = null; 
  30.  
  31.        }else{ 
  32.            $createFunc = array( 
  33.                IMAGETYPE_GIF   =>'imageCreateFromGIF', 
  34.                IMAGETYPE_JPEG  =>'imageCreateFromJPEG', 
  35.                IMAGETYPE_PNG   =>'imageCreateFromPNG', 
  36.                IMAGETYPE_BMP   =>'imageCreateFromBMP', 
  37.                IMAGETYPE_WBMP  =>'imageCreateFromWBMP', 
  38.                IMAGETYPE_XBM   =>'imageCreateFromXBM', 
  39.            ); 
  40.  
  41.            $type = exif_imagetype($imagePath); 
  42.            if(!array_key_exists($type, $createFunc)){ return null; } 
  43.  
  44.            $func = $createFunc[$type]; 
  45.            if(!function_exists($func)){ return null; } 
  46.  
  47.            $src = $func($imagePath); 
  48.            $img = imageCreateTrueColor($width, $height); 
  49.            imageCopyResized( 
  50.                $img, $src,  
  51.                0,0,0,0,  
  52.                $width, $height, imagesX($src),imagesY($src) 
  53.            ); 
  54.            imagedestroy($src); 
  55.        } 
  56.  
  57.        return $img; 
  58.    } 
  59.  
  60.  
  61.  
  62.    /**取得灰階數值*/ 
  63.    public static function getGray($img,$x,$y){ 
  64.        $col = imagecolorsforindex($img, imagecolorat($img,$x,$y)); 
  65.        return intval($col['red']*0.3 + $col['green']*0.59 + $col['blue']*0.11); 
  66.    } 
  67.  
  68.  
  69.  
  70.    /**取得 DCT 常數*/ 
  71.    private static $_dctConst = null; 
  72.    public static function getDctConst(){ 
  73.        if(self::$_dctConst){ return self::$_dctConst;} 
  74.  
  75.        self::$_dctConst = array(); 
  76.        for ($dctP=0; $dctP<8; $dctP++) { 
  77.            for ($p=0;$p<32;$p++) { 
  78.                self::$_dctConst[$dctP][$p] =  
  79.                    cos( ((2*$p + 1)/64) * $dctP * pi() ); 
  80.            } 
  81.        } 
  82.  
  83.        return self::$_dctConst; 
  84.    } 
  85.  
  86.  
  87.  
  88.    /**圖片檔案 aHash 
  89.     * @param string $filePath 檔案位址路徑 
  90.     * @return string 圖片 hash 值,失敗則是 null 
  91.     * */ 
  92.    public static function aHash($imagePath){ 
  93.        $img = self::readImageTo($imagePath, 8, 8); 
  94.        if(!$img){ return null; } 
  95.  
  96.        $graySum = 0; 
  97.        $grays = array(); 
  98.        for ($y=0; $y<8; $y++){ 
  99.            for ($x=0; $x<8; $x++){ 
  100.                $gray = self::getGray($img,$x,$y); 
  101.                $grays[] = $gray; 
  102.                $graySum +=  $gray; 
  103.            } 
  104.        } 
  105.        imagedestroy($img); 
  106.  
  107.        /*計算所有像素的灰階平均值*/ 
  108.        $average = $graySum/64; 
  109.  
  110.        /*計算 hash 值*/ 
  111.        foreach ($grays as $i => $gray){ 
  112.            $grays[$i] = ($gray>=$average) ? '1' : '0'; 
  113.        } 
  114.  
  115.        return join('',$grays); 
  116.    } 
  117.  
  118.  
  119.  
  120.  
  121.    /**圖片檔案 pHash 
  122.     * @param string $filePath 檔案位址路徑 
  123.     * @return string 圖片 hash 值,失敗則是 null 
  124.     * */ 
  125.    public static function pHash($imagePath){ 
  126.        $img = self::readImageTo($imagePath, 32, 32); 
  127.        if(!$img){ return null; } 
  128.  
  129.        /*取得灰階數值 32*32*/ 
  130.        $grays = array(); 
  131.        for ($y=0; $y<32; $y++){ 
  132.            for ($x=0; $x<32; $x++){ 
  133.                $grays[$y][$x] = self::getGray($img,$x,$y); 
  134.            } 
  135.        } 
  136.        imagedestroy($img); 
  137.  
  138.  
  139.        /*計算 DCT 8*8*/ 
  140.        $dctConst = self::getDctConst(); 
  141.        $dctSum = 0; 
  142.        $dcts = array(); 
  143.        for ($dctY=0; $dctY<8; $dctY++) { 
  144.            for ($dctX=0; $dctX<8; $dctX++) { 
  145.  
  146.                $sum = 1; 
  147.                for ($y=0;$y<32;$y++) { 
  148.                    for ($x=0;$x<32;$x++) { 
  149.                        $sum +=  
  150.                            $dctConst[$dctY][$y] *  
  151.                            $dctConst[$dctX][$x] *  
  152.                            $grays[$y][$x]; 
  153.                    } 
  154.                } 
  155.  
  156.                /*apply coefficients*/ 
  157.                $sum *= .25; 
  158.                if ($dctY == 0 || $dctX == 0) { 
  159.                    $sum *= 1/sqrt(2); 
  160.                } 
  161.  
  162.                $dcts[] = $sum; 
  163.                $dctSum +=  $sum; 
  164.            } 
  165.        } 
  166.  
  167.        /*計算所有像素的灰階平均值*/ 
  168.        $average = $dctSum/64; 
  169.  
  170.        /*計算 hash 值*/ 
  171.        foreach ($dcts as $i => $dct){ 
  172.            $dcts[$i] = ($dct>=$average) ? '1' : '0'; 
  173.        } 
  174.  
  175.        return join('',$dcts); 
  176.    } 
  177.  
  178.  
  179.  
  180.    /**圖片檔案 dHash 
  181.     * @param string $filePath 檔案位址路徑 
  182.     * @return string 圖片 hash 值,失敗則是 null 
  183.     * */ 
  184.    public static function dHash($imagePath){ 
  185.        $img = self::readImageTo($imagePath, 9, 8); 
  186.        if(!$img){ return null; } 
  187.  
  188.        $grays = array(); 
  189.        for ($y=0; $y<8; $y++){ 
  190.            for ($x=0; $x<9; $x++){ 
  191.                $grays[$y][$x] = $gray = self::getGray($img,$x,$y); 
  192.            } 
  193.        } 
  194.        imagedestroy($img); 
  195.  
  196.        $bitStr = array(); 
  197.        for ($y=0; $y<8; $y++){ 
  198.            for ($x=0; $x<8; $x++){ 
  199.                $bitStr[] = ($grays[$y][$x] < $grays[$y][$x+1]) ? '1' : '0'; 
  200.            } 
  201.        } 
  202.  
  203.        return join('',$bitStr); 
  204.    } 
  205.  
  206.  
  207.  
  208.   /**比較兩個 hash 值,是不是相似 
  209.    * @param string $aHash A圖片的 hash 值 
  210.    * @param string $bHash B圖片的 hash 值 
  211.    * @return bool 當圖片相似則回傳 true,否則是 false 
  212.    * */ 
  213.   public static function isSimilar($hashStrA, $hashStrB){ 
  214.       $aL = strlen($hashStrA); $bL = strlen($hashStrB); 
  215.       if ($aL !== $bL){ return false; } 
  216.  
  217.       /*計算兩個 hash 值的漢明距離*/ 
  218.       $distance = 0; 
  219.       for($i=0; $i<$aL; $i++){ 
  220.           if ($hashStrA{$i} !== $hashStrB{$i}){ $distance++; } 
  221.       } 
  222.  
  223.       return ($distance <= 10) ? true : false; 
  224.   } 
  225.  
  226. } 

3 回應:

Lucien 提到...

厲害的人...我是路過的,也是本行資訊人,您的文章很不錯,我會加RSS的

Jax Hu 提到...

感謝支持!

匿名 提到...

博主,您好,这些hash可以做在另一个图像中包含给定的图像吗