您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15046|回复: 0
打印 上一主题 下一主题

[php学习资料] 分享一个PHP简易的图片相似度比较类

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图- y% W& b" W3 C
; q, E) ], G/ X2 c8 k: |
. |) L4 L! V1 e$ B
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
8 B5 T) {/ |8 B
  1. <?php   
    2 p# m6 N4 q- U1 b/ j
  2. /**   
    ) W7 x; M/ v% i0 ]
  3. * 图片相似度比较   
    $ T' o' B) k0 ?: r. m* `
  4. *   $ M5 e  Y7 C& c9 v+ x9 P
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  + M0 o9 {9 R; ?% ?4 W  e; ^
  6. * @author      jax.hu   
    & d; p: h3 \: q  L, s& B
  7. *   ( Q7 {9 C3 A( N" W6 x
  8. * <code>   
    0 _# x7 l3 w  }( l" e
  9. *  //Sample_1   2 q5 G; H0 o+ `% I
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   6 H3 Y3 r0 v( C* h9 a+ {
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ( s" m8 o$ J" @& j. ?0 z
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   7 I4 W' O; u/ Y4 f% p( b) Y
  13. *   
    . r/ y0 O1 i) L: Z0 o; w$ H
  14. *  //Sample_2   
    ' r3 F6 \; I" n" W- M, g
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ) ?- K- x- e7 @/ i8 u& Q
  16. * </code>   " [  l$ V" |" w9 u) [: d" X
  17. */    ! m5 t: d  c! E
  18.    
    & M/ P# ^3 R/ c6 p; @
  19. class ImageHash {    / h. @: s  ]/ j  I, |5 P3 B, ?
  20.     + u- [5 F2 H$ R+ `& e
  21.    /**取样倍率 1~10   $ w9 ^& q; d0 y. b# N; Y4 Y
  22.     * @access public   / F; D% }, H3 g# G
  23.     * @staticvar int   
    & V2 H6 `; m3 \+ C. B5 V
  24.     * */      \# q, e* T; ^# H7 H
  25.    public static $rate = 2;    ' `6 X) k, t* t5 V% Z" Q
  26.    
    1 n* u+ O3 H8 h
  27.    /**相似度允许值 0~64   
    : j+ w. I. l$ N: ^8 t
  28.     * @access public   , S% O1 v, _4 u; j9 T
  29.     * @staticvar int   % u5 w$ u. A2 A- M
  30.     * */    3 Q$ k% S& w- G2 x, {! |
  31.    public static $similarity = 80;    8 ]- h( k1 W' g9 t* C* J
  32.    
    6 D$ E3 D5 b/ v' Z
  33.    /**图片类型对应的开启函数   
    ( ?2 ~& Q- d! B
  34.     * @access private   * u) q+ c' N5 ]: i
  35.     * @staticvar string   7 }6 M3 U. U( H. M0 k: L
  36.     * */    . q2 ?9 o- P1 f& v/ w( Q
  37.    private static $_createFunc = array(   
    & ~% m1 ]: O" p
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    2 p' ^1 ?1 n  B( Y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    5 j7 I; Z4 J) {* w# X
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    2 T0 p2 v% m5 r
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    # t) J! S, w1 g/ R
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    $ c* ~) ~5 \7 I; \/ ]7 f- S$ b1 N
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
      L' Q# c1 z& n! T5 A  X
  44.    );   
    5 h4 F9 E) }9 n
  45.     * ~0 M4 {) C6 \( N! \" |
  46.     6 c( K0 W0 A4 Z$ V. v
  47.    /**从文件建立图片   ; ~. |5 B7 [3 }6 A7 d
  48.     * @param string $filePath 文件地址路径   
      Y+ y4 Z. L0 I" ]
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   0 d* z* C8 a8 p; r
  50.     * */   
    ' Q! k( Y2 v8 v' h" Z& Y
  51.    public static function createImage($filePath){    " N' g% o) Z7 R0 }' o
  52.        if(!file_exists($filePath)){ return false; }    6 D4 W' z  b5 u1 M5 |8 a
  53.    
    # d0 b$ n. R  k  F
  54.        /*判断文件类型是否可以开启*/    6 w" r" h! N" }8 Z
  55.        $type = exif_imagetype($filePath);   
    3 P; h9 y) e' o: ^/ [6 j3 R
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    9 F5 S$ c6 R) ?% P! }
  57.     4 `; l% ~0 q) e) @" J/ _4 P
  58.        $func = self::$_createFunc[$type];    3 w: s' M( L8 l0 ~! m& O$ T
  59.        if(!function_exists($func)){ return false; }    1 Q; `1 N# h0 B) P& D1 c, a' v
  60.    
    # L& r6 }  Q* Q; i- E4 H
  61.        return $func($filePath);   
    ; }# ~1 Y2 [0 z, d4 P
  62.    }    : l/ x1 u8 A9 x
  63.     ) L% n1 b) ^# J5 D0 }$ j
  64.    
    * \1 b% @+ R$ l( \
  65.    /**hash 图片   
    % e9 G5 ]1 I: z: `
  66.     * @param resource $src 图片 resource ID   , [$ q2 R6 J; Q5 p9 K% Y
  67.     * @return string 图片 hash 值,失败则是 false   , F6 B6 ^8 B' R& O8 ~# ~
  68.     * */   
    / a# }7 g0 h2 x) G' A4 h
  69.    public static function hashImage($src){   
    1 X8 d7 L; L" z
  70.        if(!$src){ return false; }    ; L8 J- o7 Z: f- J6 S" \8 g( N) l% b
  71.    
    7 {; x: M* T- H4 }, W4 v
  72.        /*缩小图片尺寸*/   
    9 T9 z. u/ W8 _: D- S5 D# }
  73.        $delta = 8 * self::$rate;    ; t3 L0 r. @7 T) z! F4 N% Q
  74.        $img = imageCreateTrueColor($delta,$delta);   
    6 \0 I5 {' O; s; `
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    # S7 ~" `) m* K0 ~" S
  76.     " r) M7 q: s: N, W
  77.        /*计算图片灰阶值*/   
    9 o0 J- h+ I3 n  ^2 t6 {0 s5 V
  78.        $grayArray = array();    2 S* v% g$ w7 m8 r! N8 k1 W" z9 K
  79.        for ($y=0; $y<$delta; $y++){   
    , Y; |2 N& p8 m3 O9 r( J- U
  80.            for ($x=0; $x<$delta; $x++){   
    8 ]0 b! n+ O* x
  81.                $rgb = imagecolorat($img,$x,$y);    8 r& ~3 z  ]" K( R" w
  82.                $col = imagecolorsforindex($img, $rgb);    7 j9 ^* g- H; y5 t( x$ |
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    + m- Y3 Y7 F$ c5 g* g  }
  84.    
    4 s6 C1 w" H. H" i0 u; s
  85.                $grayArray[] = $gray;   
    - a7 i9 {* d9 p" g& a# o
  86.            }   
    1 ~$ A7 S6 n) M0 `6 Z! ~8 h$ O( e
  87.        }   
    / b" e) s! @4 H1 o
  88.        imagedestroy($img);    ' s% E( k/ k" ?5 r* r* Q
  89.    
    . v* L6 ?) u0 x, Y: S8 R6 j, I$ G. I
  90.        /*计算所有像素的灰阶平均值*/    ; J( F7 {7 [7 e9 T
  91.        $average = array_sum($grayArray)/count($grayArray);   
    $ R, t. U- U5 m9 n( X
  92.    
    - K! r, ?/ ^0 F: n- Z
  93.        /*计算 hash 值*/    9 R& J2 c7 B$ B
  94.        $hashStr = '';    , Q* C: q+ Y5 |/ C" J# @; u) E
  95.        foreach ($grayArray as $gray){   
    ; @2 a7 B; ^+ j( c
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    % s& `# v# z3 v1 }$ J0 @
  97.        }    4 ~( u5 V2 d: \$ C" {" N# b8 }
  98.    
    2 P6 O( J* [( d
  99.        return $hashStr;   
    # p! P. v9 X1 r0 T0 _1 H
  100.    }   
    " ?2 J3 G2 I9 V( ]- y2 H' h
  101.    
    ; J8 d0 x; ~. O( Q1 Y2 p. F' R
  102.     9 j& }& r3 S0 S6 i5 o3 f
  103.    /**hash 图片文件   
    2 g3 f7 F( F( ]5 [0 h* [
  104.     * @param string $filePath 文件地址路径   
    , e/ V5 O- V6 J. y% S, V4 A* C
  105.     * @return string 图片 hash 值,失败则是 false   
    2 n  N7 L) h  F* Y0 }* c4 l
  106.     * */   
    - d* q  x9 |, \6 L
  107.    public static function hashImageFile($filePath){   
    0 S- C$ b* X3 Q' }7 L9 L$ t, S
  108.        $src = self::createImage($filePath);    4 x* P8 E1 j# c. ~& F" ?' X
  109.        $hashStr = self::hashImage($src);    ( q. d9 q: G+ b! J" ^
  110.        imagedestroy($src);   
    % A. P% o* z: P4 Q+ @
  111.    
    ! x3 ^2 B% |( n- X$ u3 Y2 x
  112.        return $hashStr;   
    ( G$ p- D( u, Q5 u8 O
  113.    }    . M; S7 W$ `+ n7 i
  114.    
    3 E( O$ _# R' Z( X- Q* M/ g& O+ ]* ]
  115.    
    $ k% L5 P3 ?( \- p/ P- H" V+ l  S
  116.    /**比较两个 hash 值,是不是相似   
    : B: A2 I  E1 v- R
  117.     * @param string $aHash A图片的 hash 值   
    - ^" I9 D' _7 o! X" u0 r2 E
  118.     * @param string $bHash B图片的 hash 值   
    ' }7 l- Z! P$ ?. a
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    : L- o9 ?# i( z
  120.     * */    % b: j: r( L# V) _) G8 c8 y
  121.    public static function isHashSimilar($aHash, $bHash){   
    5 V$ ~  k, A1 N. s
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    3 a# }; G8 i9 z/ j' p
  123.        if ($aL !== $bL){ return false; }    ' T0 G' ^' y8 C- f$ O
  124.     9 n# z- I- p$ A" ]; A) i+ [
  125.        /*计算容许落差的数量*/    5 z% a7 G- O! }5 e. \
  126.        $allowGap = $aL*(100-self::$similarity)/100;    $ h, z7 B# R) c5 B+ a: {
  127.     9 e8 F3 p* S- `6 X2 N) n
  128.        /*计算两个 hash 值的汉明距离*/   
    - k* x6 ]; v& @9 R3 F( z2 x" u  F
  129.        $distance = 0;    0 V/ t2 ~2 }$ M: k$ S3 ^* U
  130.        for($i=0; $i<$aL; $i++){   
    3 p& B' j2 s2 x, l$ S
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ! @' v1 F1 R( l, ~' ~1 }
  132.        }   
    7 E! b( w$ G: c  |7 I
  133.     5 M( m# x- \) y4 P; v7 F1 o
  134.        return ($distance<=$allowGap) ? true : false;   
    8 W2 n4 c- V6 ]& G
  135.    }    & p8 \7 V/ u& s+ n
  136.    
    5 G# [  P% ^/ Z2 r
  137.    
    ( ^5 `7 Z( V: V" d6 F
  138.    /**比较两个图片文件,是不是相似   9 n! P9 T3 D+ T. I, a0 p
  139.     * @param string $aHash A图片的路径   / D! t0 X+ c$ V
  140.     * @param string $bHash B图片的路径   
    ) [  \1 Z0 E0 X) d: v' I/ y
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    $ g: G6 t( a# }  z! A- v8 q# g
  142.     * */    , n4 r8 B8 I4 o& z2 U
  143.    public static function isImageFileSimilar($aPath, $bPath){    1 d) K3 D' ?; I3 w0 ]' m
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    . M7 q, _# C1 o7 `
  145.        $bHash = ImageHash::hashImageFile($bPath);    " T1 u1 }* X8 _5 t
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    . e5 ~' d7 I7 P
  147.    }    9 P9 K. _0 f; W4 c& V
  148.     % q; q# l& {0 u8 k
  149. }) R5 f: d/ ]. n
复制代码

: R( [6 r3 v0 j0 g  u. D. i3 ?; U- L/ |+ D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:51 , Processed in 0.048779 second(s), 19 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!