cncml手绘网

标题: 分享一个PHP简易的图片相似度比较类 [打印本页]

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
( M8 @2 t+ }5 F4 N  A/ {5 m% W) A* c) j# k7 s* Y

' f: E% I. V' x: Z. t由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

" o- [$ k7 B' `$ Y) b
  1. <?php   
    : A  t4 W/ {  @' W
  2. /**   : z9 @2 Y. P( V" b
  3. * 图片相似度比较   " c% C0 L' w0 i0 U
  4. *   
    & P+ p; C, H  Y" O" o& U5 G* [3 m4 w
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    + b  d1 A9 O3 J2 \9 Q  P3 i* }# N; J
  6. * @author      jax.hu   
    + W. j; K: K. x% m2 l, j# ~: q; T
  7. *   2 Q+ m3 r! ]- c" ?3 Q
  8. * <code>   ( c2 [8 R% {" L
  9. *  //Sample_1   
    5 b$ N- V! D. j; K+ F+ H
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    % K5 ?6 n0 c. Y1 Y  q1 t
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   5 ?% ~4 T6 w: r
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ; ?8 l: l# \, d. t4 s
  13. *   
    8 i" ?7 e  L0 |. q# |, w
  14. *  //Sample_2   / Z. L; p1 Z' t
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   . X9 F% I( X1 L  `: }) M, X" m
  16. * </code>   ' a% Q7 E  I& }( W3 Z9 }; d
  17. */      U6 N/ z* u. t$ d$ ~
  18.     , u. B8 v0 q/ Q6 X1 n
  19. class ImageHash {   
    1 z" h3 K3 A  E! P" X
  20.     1 F. z2 t9 K* H# f) F
  21.    /**取样倍率 1~10   ! O! K3 }6 t& M# X
  22.     * @access public   
    : Z7 m, U2 }) O. ]9 V" w/ u; X
  23.     * @staticvar int   
    ' g/ J6 J7 f8 U" A' y2 W
  24.     * */    # p5 f. b8 ~$ I9 s# t  N7 H; X. R7 X& Z# j
  25.    public static $rate = 2;    , z2 X( o. A4 ~, y
  26.    
    4 @8 ?" K7 v# o( `; `( s. v$ L) w1 k
  27.    /**相似度允许值 0~64   " g; L  l1 B8 k, `5 g
  28.     * @access public   
    5 t' c$ v4 x6 V- I) A
  29.     * @staticvar int   8 v/ C) f( v. b' {- s
  30.     * */   
    5 {1 y. \* w) z* K
  31.    public static $similarity = 80;    " Y) q; Z6 ^2 a& i8 P6 w
  32.     ) x" ^2 b6 M1 Z* g$ w  z& ]$ g+ R
  33.    /**图片类型对应的开启函数   
    , z1 K& |, j9 r  H; U! h, p, _
  34.     * @access private   . O' ^7 p; ^% R9 ~: W8 v
  35.     * @staticvar string   ' |- o! a0 s% @0 d
  36.     * */   
    , h) {- T, L, v; Y8 N- ~/ \
  37.    private static $_createFunc = array(   
    " Q0 R* o0 J; t8 j
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    % s* X/ |* N2 Z2 d
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    * p) z7 i' o5 N! B$ `) x9 t& Y% I
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    # F% b0 d' G- t1 |0 S
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ( j" l  {7 I. K$ s9 q/ E0 N$ i
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    $ w1 l' P8 o9 _0 z
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    * n0 U! o% b+ ]& G0 o+ e) u; v0 A
  44.    );   
    : N% ?: o  M6 y& ?3 s) |
  45.     & E* N7 P% Y1 `# e( U2 N
  46.    
    3 {* W6 V0 n9 `# T( C- J- g
  47.    /**从文件建立图片   
    # S1 y6 l% H+ R
  48.     * @param string $filePath 文件地址路径   
    ( H. i: E- Q7 s5 |; I
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ' W- g2 b4 D; G; B: H- I! ]& t
  50.     * */   
    - n& @7 O* L) L. Y" Q
  51.    public static function createImage($filePath){   
    , W2 J3 a$ Y" S! ?7 C* A4 P8 a
  52.        if(!file_exists($filePath)){ return false; }    9 E5 A6 H) C9 P$ J: o! B) ^
  53.    
    2 Q; B# k! C, T& m
  54.        /*判断文件类型是否可以开启*/   
    : B0 Y) \: l9 t9 F, j& Y
  55.        $type = exif_imagetype($filePath);   
    % v- S0 a9 @/ k1 l$ @0 b
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    : O8 o: g! l) o7 L! b4 s7 v
  57.    
    2 @" d- z3 J" ^1 {0 J0 E
  58.        $func = self::$_createFunc[$type];   
    . d' |' y1 O% g1 l& {/ B: ?5 {4 a
  59.        if(!function_exists($func)){ return false; }   
    6 d) S( C: \2 b+ N1 O" \6 j
  60.     , Z3 `3 f8 h) v0 _/ P. x
  61.        return $func($filePath);   
    8 c1 c5 y7 n# p" j
  62.    }   
    5 [( x2 P& y  ]( h5 g
  63.     * C- t0 t* C9 Z2 u
  64.     ! f; ?8 l/ Z' g3 Z0 x
  65.    /**hash 图片   4 u1 T0 C9 v# G8 W& n6 x$ T( n* T/ `
  66.     * @param resource $src 图片 resource ID   
    7 H5 V& ?0 B2 w8 A1 J
  67.     * @return string 图片 hash 值,失败则是 false   
    ! v0 M0 ^$ v" g* k7 Z: k( C4 S1 q) w7 k
  68.     * */    # w8 p2 |- g0 N1 p$ D3 @8 S
  69.    public static function hashImage($src){   
    " }6 U; o5 B( g( w+ d* y
  70.        if(!$src){ return false; }   
    7 N4 J& Q7 f  b, E
  71.    
    1 ^, j, d* ~" F) x1 j* s
  72.        /*缩小图片尺寸*/   
    ! H8 V5 d& A  _4 N" _  c
  73.        $delta = 8 * self::$rate;   
    5 {$ J# I+ M3 `+ b  f
  74.        $img = imageCreateTrueColor($delta,$delta);   
    $ ~1 z% x: j' u+ _+ i
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    / |3 f; k9 X2 [0 `0 `$ S3 Z  H/ F& Q
  76.     0 j7 X% c7 k$ Z! \
  77.        /*计算图片灰阶值*/   
    7 W. t6 n6 K8 J2 o
  78.        $grayArray = array();    6 ~4 x. }1 l  V) i3 ]
  79.        for ($y=0; $y<$delta; $y++){   
    " i6 M9 p5 a1 B5 u
  80.            for ($x=0; $x<$delta; $x++){   
    " e+ t6 }* ~9 \
  81.                $rgb = imagecolorat($img,$x,$y);   
    % x% V( q' {+ u7 }/ C2 q! y
  82.                $col = imagecolorsforindex($img, $rgb);    0 {2 O# O- ~- P" @' D
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    + `3 c8 t, `7 F$ n8 w4 }3 G6 |
  84.    
    6 l: c) ]: z! S) X: g
  85.                $grayArray[] = $gray;    2 k& c; K$ z2 h0 a5 k- f2 `5 }
  86.            }    9 ^* i* b# C: z% p1 @; A, f$ H$ X
  87.        }   
    9 u1 f- F  y. n; Y
  88.        imagedestroy($img);   
    / X" @* g4 x, ]7 q) I5 q
  89.    
    ! [" z& Z2 ^5 h9 K" f2 J- h% v
  90.        /*计算所有像素的灰阶平均值*/    : l, m4 ?9 h3 y7 V9 f+ Y) Y7 C
  91.        $average = array_sum($grayArray)/count($grayArray);    . l! Q! C+ T2 M* x$ V9 i
  92.    
    & w* `9 R! U- @# Y3 Z# \" R  k6 v
  93.        /*计算 hash 值*/   
    ) C6 `! V- x+ D! P% N* B
  94.        $hashStr = '';   
    . [: p1 s8 j" E
  95.        foreach ($grayArray as $gray){    * A5 ]5 {$ q% ]9 }- Y4 x) d. G
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    0 S+ f* w8 Y9 U% V! S
  97.        }    ) V" D, M0 T9 m# S, P" r3 \
  98.     . y- O- |& j$ u" l! z
  99.        return $hashStr;   
    % F3 v$ P  Z8 A1 J) y
  100.    }   
    % @2 j. u5 o# I, C
  101.    
    ) @4 G; s/ O( ?2 A6 l/ r1 b/ t
  102.    
    2 K  m0 p( F& d: t9 P6 \
  103.    /**hash 图片文件   6 _( c" {# R/ L
  104.     * @param string $filePath 文件地址路径   * J% w4 X5 g( l* h! G, |) x
  105.     * @return string 图片 hash 值,失败则是 false   
    , j4 D& B7 z; i- A( A( o
  106.     * */   
    ; y* G- h  Y5 C4 I1 p8 c: G9 q8 k
  107.    public static function hashImageFile($filePath){   
    * O) W/ ?7 x' y# ?  p- C$ E8 X
  108.        $src = self::createImage($filePath);   
    ( J7 v3 k( g# O% I& `, N* |, A+ J
  109.        $hashStr = self::hashImage($src);   
    ! l7 j% j5 j3 ]5 R- t# s' Q1 b
  110.        imagedestroy($src);   
    * _0 T4 D3 x) x1 i
  111.     ) i; L+ V) T6 Q9 {: i6 M
  112.        return $hashStr;    ) k5 K: K+ ]$ Q4 C) s$ r
  113.    }   
    6 {, c# O3 l; g1 l8 e% u
  114.    
    - m: a) q1 D: X8 A9 x/ M! V
  115.    
    % \3 p$ p  E- l5 ^) B( x
  116.    /**比较两个 hash 值,是不是相似   + [; e3 l3 [" c, I8 }7 g$ v
  117.     * @param string $aHash A图片的 hash 值   
    ; q0 C* y  y% f2 ]3 m
  118.     * @param string $bHash B图片的 hash 值   $ `- P8 b+ P& s7 K2 H' B7 ^
  119.     * @return bool 当图片相似则传递 true,否则是 false   6 F/ o- G, Y' Q1 ]
  120.     * */    . C3 K7 G, W" A5 S3 G9 O- S# Q1 h
  121.    public static function isHashSimilar($aHash, $bHash){   
    $ ?; i1 K- [" H8 G" H# b2 o6 g, h
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    , U% c4 v, N9 ^7 q) C& L" f# F
  123.        if ($aL !== $bL){ return false; }    + }8 E  `# `4 d; Z2 P  g
  124.     ; ~# g: q. q4 Y/ a, [4 a( f
  125.        /*计算容许落差的数量*/    4 p. q' P' ~. E+ G  u+ P
  126.        $allowGap = $aL*(100-self::$similarity)/100;    $ R& P9 y- k; T, \) n
  127.     - H0 A$ x+ t' A# e' x8 S1 W$ C
  128.        /*计算两个 hash 值的汉明距离*/   
    9 ^, [% x/ s$ X+ f7 c
  129.        $distance = 0;   
    # e1 Z. W" ^4 Z$ f
  130.        for($i=0; $i<$aL; $i++){    ) c; m5 ~5 U& H0 D3 h
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    7 `$ e) W: r( B+ ^# I0 B
  132.        }    9 I" ?! H. y  e- j+ `3 u/ ]1 Y( M4 t/ r
  133.     4 N# P. `! c3 g9 D5 H
  134.        return ($distance<=$allowGap) ? true : false;   
    7 e% ?9 Y+ E" r$ o
  135.    }   
    ( D. }# Q. ?3 [4 B0 E4 P& m' _
  136.     ! k6 Z/ w1 U4 f8 @+ o2 O
  137.    
    3 x! M) R" e/ w, }& o. a' v$ M7 T
  138.    /**比较两个图片文件,是不是相似   
    $ c( L+ O/ Y, T6 q6 H- ~
  139.     * @param string $aHash A图片的路径   . ~2 A: v" A8 a6 K+ u, X% s1 ^
  140.     * @param string $bHash B图片的路径   
    : v# L/ _1 `# M8 ]
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ! {8 B2 K; T& s3 u; R  j, f3 S  ]
  142.     * */    ! y- v+ `" a3 \2 U) [& D& u7 Y
  143.    public static function isImageFileSimilar($aPath, $bPath){    # o" D; q6 x( r3 ^) k# M
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    : F( v. v4 u% y
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ; J' I0 u* T, H- Y2 W: \, @6 u6 ~( d
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    # o+ G: v) Y/ O! F" H
  147.    }   
    : ?7 Z% P+ ~7 ^; \
  148.    
    & `/ Q1 B) S; L4 o& @( e
  149. }
    2 P& c3 ?7 q2 k! |! @
复制代码
" x5 H5 z: I8 a! u6 y/ n1 `

$ a- e9 w# Q8 n  }( W  m; M




欢迎光临 cncml手绘网 (http://bbs.cncml.com/) Powered by Discuz! X3.2