cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图) |) ^! N: T- a# k
+ h( Y) A' l! U5 R

7 I* J# @0 z  x: g% h% R! S由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
9 M2 s1 H3 s8 Q& g5 ~; K) {% J* Y
  1. <?php    4 R2 J/ N% C0 f
  2. /**   
    4 L: S- m1 }1 p) y+ g9 K6 l$ h
  3. * 图片相似度比较   
    6 Z5 S+ N' @& h# R1 Q
  4. *   
    3 d' A" B( t9 M
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    * [, o. @6 L- y( K7 F  ]. H) T7 L; C
  6. * @author      jax.hu   / A" v5 ?5 Q8 a; `2 {8 ^6 L
  7. *   
    ) X. p& l& W- m+ {; j
  8. * <code>   
      n( P6 Q& \$ U, Z4 j
  9. *  //Sample_1   
    / f1 {; `* o; z- i1 ]6 }1 l
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   - u' |5 ~) T( Y4 K: a1 c  V
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ; G. J; a7 x& @, `& j  R
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   9 `) B" b# S; A2 p8 H( J# |6 n4 G# p
  13. *   . Q$ I$ i  n4 h
  14. *  //Sample_2   0 U4 y6 l& W9 y! o
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   9 U! y% J* t4 p: k
  16. * </code>   4 j/ b4 c' C. m9 O3 G: k% d& `
  17. */   
    * Z: L1 l9 a: ^1 t$ H
  18.     ' F& ], m4 G( `8 j1 _$ D2 A
  19. class ImageHash {    % H2 H" q6 S" s8 k
  20.     ; `+ @% a2 ]! P. P0 t' @' b
  21.    /**取样倍率 1~10   
    0 \) D. w- Q/ m& }* Z: A' ]; k
  22.     * @access public   " m! }$ d# \* P" P4 d1 x3 l
  23.     * @staticvar int   2 G6 ]: k9 P# r) M! Q7 J
  24.     * */   
    8 s* p/ L) j1 h& V
  25.    public static $rate = 2;    5 X; S7 e2 z' y# x, P+ L5 d. N6 m
  26.     ' l: x% ?* w/ y& h6 d' W
  27.    /**相似度允许值 0~64   
    ( z/ b* E8 n1 u% ]
  28.     * @access public   7 {1 m( z* c" m, U( A7 ?6 ?$ M
  29.     * @staticvar int   
    ; S+ E5 m; r' c; T8 l0 d! a
  30.     * */    ' `( Z- E; g6 C- v& r2 ?5 r7 }$ {
  31.    public static $similarity = 80;    + p  R. E( G2 s2 G
  32.    
      Y0 y' s. m/ o  V5 k% G' ~
  33.    /**图片类型对应的开启函数   
    - c8 @/ R, N) u4 r4 D4 C' i& Q) _
  34.     * @access private   
    * u7 w5 ?0 J+ B% k5 V
  35.     * @staticvar string   0 }5 L- u8 I1 W$ b  t/ J
  36.     * */    # g0 r+ v9 p4 T
  37.    private static $_createFunc = array(    0 |$ r' c1 {% b2 r( L
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    / t0 F2 w, o: o$ w- o' }
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    * M% @" [: v' U: L3 v3 I# Y) U
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    5 m% L* s- o" a8 A" G3 A3 t& z
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    . L& U+ W6 ]  V5 X5 b
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    8 g% D6 ~' D0 t! d" X3 K$ D' @; o
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ' X! x6 l& h2 @, d
  44.    );    3 e' y% [$ I8 Z
  45.     ; `6 L, P1 k$ g
  46.    
    ) D" Z* Y3 f2 ?# ^6 C- w
  47.    /**从文件建立图片   $ s9 A0 L! `) D4 H) U( m5 ?
  48.     * @param string $filePath 文件地址路径   ' ]  Y0 J0 W2 M
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    : S: G3 p1 i* i
  50.     * */    8 B# O$ X1 g' H9 X- H9 N! P
  51.    public static function createImage($filePath){    0 s* ]; f0 ?& ]) Q3 T
  52.        if(!file_exists($filePath)){ return false; }    ) Q( c# ?+ j* b1 d0 |' i
  53.    
    5 V* @5 ?$ t* w0 z3 h2 \# u
  54.        /*判断文件类型是否可以开启*/   
    6 c3 S0 v7 ]: ]/ Z. J4 @3 F# n; {
  55.        $type = exif_imagetype($filePath);   
    0 w. I& b! B3 b0 A3 ~0 G/ V1 T
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }      A4 {( e* N4 e) B
  57.     6 u* A7 _4 E$ B* T  Q
  58.        $func = self::$_createFunc[$type];   
    : F( K! |" N* ^% z" V
  59.        if(!function_exists($func)){ return false; }   
    : S7 G. H4 m. ^% _5 ?. s) [
  60.     - O# g' T- n, t! C% g6 `( w
  61.        return $func($filePath);   
    * k; ^4 }. \& o2 _3 S9 b+ p" X
  62.    }   
    / B: [* `  V! O/ k  O
  63.    
    8 \" t$ r2 R8 l# ~: N/ r: G7 m) k
  64.     : p7 R3 J/ D+ r& U3 J- n
  65.    /**hash 图片   
    - z0 {7 A: D& l5 P# e
  66.     * @param resource $src 图片 resource ID   4 s  L. i, D0 G3 z: }% c
  67.     * @return string 图片 hash 值,失败则是 false   
    ) g- |# \+ w- \  {- P& g7 H
  68.     * */   
    - h, r! f' H7 v2 m8 n
  69.    public static function hashImage($src){   
    # A  d, X+ U, o/ ?/ f
  70.        if(!$src){ return false; }    7 r( c5 O7 v5 z1 |0 ?- ~+ d
  71.    
    # k8 Q3 u" x0 M9 P$ f
  72.        /*缩小图片尺寸*/   
    / i* ^+ @$ G) j6 A% L5 w
  73.        $delta = 8 * self::$rate;   
    " Y/ S# D: E5 n8 p1 T5 P1 h, H
  74.        $img = imageCreateTrueColor($delta,$delta);    $ j  J. W! U7 L- E
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ; q" G! |0 h$ B( I; o9 @
  76.    
    8 W6 @; ?9 R! c: d. {
  77.        /*计算图片灰阶值*/   
    4 K% g# U+ s! ^- `9 O4 w
  78.        $grayArray = array();    ! C4 b; J! K* g; |0 T
  79.        for ($y=0; $y<$delta; $y++){    8 J' L6 T7 y2 l9 f) [
  80.            for ($x=0; $x<$delta; $x++){    9 a! q1 y6 v. d* `* f# M) |. |
  81.                $rgb = imagecolorat($img,$x,$y);   
    : r: d  ]6 ^( A, \' [. p) |5 u
  82.                $col = imagecolorsforindex($img, $rgb);   
    / r- w4 ^4 `/ [& F- u  [
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    : n% y! |' c9 r) v; H* m
  84.       V8 f. o4 p$ O9 u) ?! ~" S
  85.                $grayArray[] = $gray;   
    ! V  Q: m) z3 V3 i- D" \* P
  86.            }    3 ]6 C, E0 `1 a! t
  87.        }   
    ! r/ v( T* _# \& u  \
  88.        imagedestroy($img);   
    + B. s4 V* x0 c* `/ z
  89.    
    9 X: c8 l1 d" t$ b' H9 F7 W, H
  90.        /*计算所有像素的灰阶平均值*/    5 E  r/ \* }3 o$ j. j8 m2 g2 f
  91.        $average = array_sum($grayArray)/count($grayArray);    . G* P& [( W6 {+ d
  92.    
    5 ]( @% U9 q, j8 F- D
  93.        /*计算 hash 值*/    6 ?& g/ \( p& J; O0 Q% Q
  94.        $hashStr = '';    % \% ]6 W; F+ k3 f
  95.        foreach ($grayArray as $gray){   
    6 N% r9 U* T( S& S2 D3 B0 N" X
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';      @9 C" a: m( F" u+ ]% I- C
  97.        }   
    1 t9 J6 ^  Q$ Y: G
  98.    
    $ ^4 \% q( r5 @3 A  N; x; W
  99.        return $hashStr;   
    2 G- p: g0 d5 f& `: `7 j, G7 W) o
  100.    }    8 ?5 }# s& X' b: Z5 T% O
  101.     0 a1 U; ^& i( [: E; K% w$ r
  102.     7 b2 q! Y0 Z' W- k6 B
  103.    /**hash 图片文件   0 j/ P' Q: R. {' [4 I6 @$ a6 }
  104.     * @param string $filePath 文件地址路径   
    7 q: K4 ]  B+ K8 h: L& S" }7 P
  105.     * @return string 图片 hash 值,失败则是 false   
    + \6 x7 X5 o/ l# E# e! j8 ]
  106.     * */   
    - d' E' b. f& ?( ~  U! Z9 Y4 r
  107.    public static function hashImageFile($filePath){    9 W) R: P1 e: E+ X
  108.        $src = self::createImage($filePath);    1 J; G! M% g& ^4 c. I5 R9 S! f
  109.        $hashStr = self::hashImage($src);    5 l+ {+ h  @4 x+ ^" O) v
  110.        imagedestroy($src);   
    3 n" W: A7 i, f  b- E8 L
  111.    
    ! j% `6 l; j7 q* Z
  112.        return $hashStr;    ) j/ F5 y  p. v  l
  113.    }      f2 `% J. Q7 i" p5 |5 J6 n
  114.    
    $ v: z+ r! q+ i! |4 u9 _6 W8 X
  115.     : l: ?* f; u1 b; Y. W
  116.    /**比较两个 hash 值,是不是相似   
    4 S6 e& S) ^  C3 Q- |6 m1 Z
  117.     * @param string $aHash A图片的 hash 值     p& f" M/ C& t3 X  ]8 o
  118.     * @param string $bHash B图片的 hash 值   
    * z+ D! v6 {6 A7 S; b: @2 N
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    9 [0 t* V6 S8 ?
  120.     * */    ' r( i' S' n3 U- Q/ L# _
  121.    public static function isHashSimilar($aHash, $bHash){   
    9 M5 L5 U' i! i3 C( S5 X, e0 r* ~
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    9 A# O0 g3 v* }7 u* V7 y
  123.        if ($aL !== $bL){ return false; }   
    # Z  m# c* u) V0 I3 \& |7 v+ L/ J9 E
  124.     9 T3 i2 {5 _8 V- [1 |' a! }
  125.        /*计算容许落差的数量*/   
    " n$ `8 g7 E" a) c
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    + G! S) w  d% i/ U
  127.     * p) G7 v: H. ]) f
  128.        /*计算两个 hash 值的汉明距离*/    $ Q/ t, z& ~+ a2 B* j
  129.        $distance = 0;    ' E/ `" u, M2 X- }/ ~! O
  130.        for($i=0; $i<$aL; $i++){   
    : T! b  ?) Z' G- M$ X; v
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    4 T: h8 r3 x' D' F2 [* |5 X
  132.        }    5 r* |3 f: L( i% {/ q- r" a
  133.    
    2 j% X, x& F) a2 J2 q: T, A& a
  134.        return ($distance<=$allowGap) ? true : false;    . K4 [! F# l- o. F+ g
  135.    }    : @( Z" k0 N" u
  136.     + L  y; Y6 }+ S2 e
  137.     + u& g) L  o8 w/ ]- M+ @9 w
  138.    /**比较两个图片文件,是不是相似   
    + P4 l5 g" z8 c
  139.     * @param string $aHash A图片的路径   % N3 |$ i. c" M" W% @% g7 H' ]
  140.     * @param string $bHash B图片的路径   ) w; s8 \# \+ v! j- I$ w
  141.     * @return bool 当图片相似则传递 true,否则是 false   ( ]  `( t- ?9 g* J; L+ E, h( u# w0 M
  142.     * */    ( n. Q4 _$ h. b, W6 N7 k5 ?
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    : |- q2 J5 j) X+ E1 W
  144.        $aHash = ImageHash::hashImageFile($aPath);    6 r3 F( Z5 T  K" T
  145.        $bHash = ImageHash::hashImageFile($bPath);    3 t  N: x$ Z: _$ C
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    - R  N" v/ I4 H/ k9 _/ L0 v
  147.    }    * t1 E& r! p2 D
  148.       j8 Z4 Q2 {1 ^% v( E, S
  149. }3 p( @/ K, N# ?/ K: Q. l- b2 S
复制代码
! O, e" t2 \$ i) f
% ~& W4 j& u+ H





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