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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
  ~7 m* j" B; [/ m: k! l0 u& G* E! c1 N, d- `

4 f, D+ u; z: T由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
2 R; f0 U/ f% y9 Q" s( G
  1. <?php   
    4 s+ f. ~4 w$ K7 m2 t$ \3 Y6 {, d7 P
  2. /**   & m1 x/ A; i& |" L+ H# P% ~  ?- W
  3. * 图片相似度比较   
    - _; _6 Z6 B$ F1 I/ g6 g4 I/ d
  4. *   
    ( b% D. \  k2 H6 z; c& T2 ]; m7 N) u
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    # J3 \$ V" n# |9 h" N
  6. * @author      jax.hu   % _( D1 t& U* |# M* v
  7. *   ( f7 Q* S0 A+ C* s
  8. * <code>   . T9 B7 P9 J1 Y9 X& L
  9. *  //Sample_1   7 f# r. M& V& X% G6 J" r
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    6 U4 E9 n" A: q" B  [/ N
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ; |& C5 N7 o, O- u! k9 d+ M7 A/ B, N+ X
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    : D  x: Q! s0 k' X
  13. *   
    9 D! r' C/ Q( d
  14. *  //Sample_2   
    : z: \' E( K# I
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ' a* h. F1 U  J- K" A; t4 G# h% \" ^
  16. * </code>   
    & k4 g* \5 D2 \/ \5 v1 O  A( h
  17. */   
    7 f3 s. o4 `* R: Q  B/ _
  18.    
    ! x& j% {& `. J* Y- A
  19. class ImageHash {   
    0 u  g  |: w( Q3 j$ g
  20.    
    , a5 t; d. P8 W2 B% @
  21.    /**取样倍率 1~10   
      e6 ?. ]& y# W$ C" N8 V: j* D
  22.     * @access public   
    ! N) `! O+ |7 n9 Q- ~3 s* ~; P, d
  23.     * @staticvar int   
    ! Y: Q; b& J( D6 q
  24.     * */   
    * G' w5 C9 R9 k4 s0 z
  25.    public static $rate = 2;    4 |5 _& _* r9 C
  26.     5 U: z4 @* ~, j( n, E
  27.    /**相似度允许值 0~64   / u; }& Z7 e# s% N. P# _
  28.     * @access public   
    + \) D; h# m: I( h$ r' l; F: n
  29.     * @staticvar int   
    ( i! W" L" T  _9 p) Y( {/ o
  30.     * */    * j. e0 V7 f* I/ y
  31.    public static $similarity = 80;   
    ' j4 o8 x/ t* O# d! s* L
  32.       b* S% W& F- Y
  33.    /**图片类型对应的开启函数   " B3 Q% }+ F) X7 X( }
  34.     * @access private   2 ^' k: K- [* s4 r
  35.     * @staticvar string   
    ; Q( @$ G/ o; s. G8 G/ R
  36.     * */    3 [+ m$ T* D3 @  N5 }8 T0 T
  37.    private static $_createFunc = array(    3 P, V+ L- Z% i* l& K1 N
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    # h* w) v/ S* ?8 Y" U- H5 N' g, i& Y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ( h. t' E5 F1 i* P  ]/ d! p
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    - W: Q) B, R+ I" Z+ \
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ) S6 [- e% K! F7 f: a' J
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    ; G# V0 P% K8 e! Q3 i& P
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    : I  u' e+ b. \+ ~$ e" X. T
  44.    );    2 t% t2 Z: W$ K0 K' n
  45.     : E8 |0 F: G0 d2 Q) s1 z
  46.    
    , ]- O) T1 [( P3 K( b
  47.    /**从文件建立图片   
    $ F4 `: s8 S! H7 ]8 a+ ]% z
  48.     * @param string $filePath 文件地址路径   
    ; L6 d% @. N$ j0 J
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    8 V1 ^* x8 ^! P, j
  50.     * */   
    0 ?! T% k! M" l0 v
  51.    public static function createImage($filePath){    , k* R$ H- p/ h# X0 k& ^
  52.        if(!file_exists($filePath)){ return false; }    4 W3 _6 `! j, t& w
  53.     , A8 K9 R  ~5 t( S7 E
  54.        /*判断文件类型是否可以开启*/   
    ; U1 B  c4 M4 _! B& ^1 U
  55.        $type = exif_imagetype($filePath);   
    - _' `% ~4 x, N1 L9 b, n+ M6 O
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ; @8 T% l6 J( F+ \. w5 @
  57.    
    . c0 z8 `+ M, K4 x. N) t
  58.        $func = self::$_createFunc[$type];   
    : M: _% h7 U) N7 I8 G/ y
  59.        if(!function_exists($func)){ return false; }    2 K  O+ m2 ~/ `
  60.    
    $ ~* A* Q  E6 M! B& y9 q) b6 }" Q
  61.        return $func($filePath);   
    : k5 o1 ^& E  E6 D
  62.    }    * G: z/ ?. E# {) v2 f! s  l' D$ r
  63.    
    1 ^6 E7 C% C3 ^+ m7 l  I5 I
  64.    
    - i, C; Q& l0 ]( Q
  65.    /**hash 图片   $ x6 E; e% j6 X9 P' `* D" o
  66.     * @param resource $src 图片 resource ID   4 d  i7 o9 |0 o( k# O
  67.     * @return string 图片 hash 值,失败则是 false   ) x- F6 I( {$ E- K. J3 R6 t
  68.     * */    % p1 r$ F6 S3 W
  69.    public static function hashImage($src){   
    0 \2 P( a- V7 A! i* P) I6 R
  70.        if(!$src){ return false; }    3 A$ J' ^& g8 y( t8 f3 Q  J
  71.    
    - e) r* L$ B( Z6 L9 C8 u# b# z, ]
  72.        /*缩小图片尺寸*/    ! `5 f% J- M/ u/ F
  73.        $delta = 8 * self::$rate;   
    , F! l: {9 w* `1 b8 T0 v% i
  74.        $img = imageCreateTrueColor($delta,$delta);    8 A/ P' {0 h$ C6 B3 |8 m* H
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    0 q; B7 c5 A- c! e
  76.     ) {: y$ O4 Q# S2 X( M
  77.        /*计算图片灰阶值*/   
    8 n) j$ H( ?8 B
  78.        $grayArray = array();    0 v* `  `' a$ ^' H* }
  79.        for ($y=0; $y<$delta; $y++){   
    . f4 i+ y& c% j; k) _! ^% u
  80.            for ($x=0; $x<$delta; $x++){    + N7 D  Q% J* I, O6 q0 w
  81.                $rgb = imagecolorat($img,$x,$y);   
    . ]# T! P/ l& l; c- t! |# W7 U" ~
  82.                $col = imagecolorsforindex($img, $rgb);    2 V8 ^: t8 A/ A/ C1 H6 t
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ! e' R, T% ~' r' \: G; j8 N3 w
  84.     , J7 R! V. N; Y
  85.                $grayArray[] = $gray;      s1 P5 ]$ v0 t9 u3 S* \2 B8 B9 ~
  86.            }    0 o5 z9 t7 T' P$ m2 z* N' C
  87.        }   
    ! K2 ~0 g: S0 ^
  88.        imagedestroy($img);   
    & q% A/ U( X- J1 f: _1 }
  89.    
      m  q1 ^- H9 I- n8 W
  90.        /*计算所有像素的灰阶平均值*/    ; y* a* `1 P; ^) p, ]! o
  91.        $average = array_sum($grayArray)/count($grayArray);    & ?8 V9 H* W& A' A+ i
  92.    
    ! s5 `5 \: T) u( j& S1 q* k
  93.        /*计算 hash 值*/   
    7 W* ]- t5 x. ]# U8 G
  94.        $hashStr = '';    . `. H4 l3 q: y- U
  95.        foreach ($grayArray as $gray){   
    $ S- k5 K% E2 o+ ?
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    / K: }6 |% B, c% Y; i
  97.        }   
    5 C7 r5 j: f' m1 y& g# P; k
  98.    
    $ Y" X2 i; m8 N$ @. l0 j
  99.        return $hashStr;   
    & i6 Q4 g) z- L9 w* x: ?
  100.    }   
    7 Z! n' v0 q- ~" j* R: v7 B" d: d, J
  101.     ) |* D# c: ?6 j/ Q/ |
  102.     1 P4 q% q4 p! X: q
  103.    /**hash 图片文件   
      |7 d9 G3 @) q4 ?
  104.     * @param string $filePath 文件地址路径   6 P6 g$ y0 k; c: a& \
  105.     * @return string 图片 hash 值,失败则是 false   5 M2 g! k7 }; n0 [" U9 I  T+ o' B: p
  106.     * */   
    - V) H' G0 V( r1 ~+ A3 i3 ^
  107.    public static function hashImageFile($filePath){   
    / v% q5 r- D* v5 w: J: E
  108.        $src = self::createImage($filePath);    $ v1 E. ?4 |, z
  109.        $hashStr = self::hashImage($src);   
    ) B6 f. K% a. h8 c
  110.        imagedestroy($src);    9 r; B! b3 T% T
  111.     2 m% t9 P) k+ Z6 Z/ r! }
  112.        return $hashStr;    ! _& J) k& `& ]5 F& S
  113.    }    2 I2 _$ m! U  d2 N- {
  114.     / V* z- L( x% F2 l% l3 g" U
  115.     ) \  M; X3 ~; U( O& y# t/ w$ Q1 }
  116.    /**比较两个 hash 值,是不是相似   ' P# C6 A2 e. `* W( v# s
  117.     * @param string $aHash A图片的 hash 值   - Z! M; Y7 m2 o& v1 W5 |  u
  118.     * @param string $bHash B图片的 hash 值   0 Q# b% \5 R- z1 T1 @
  119.     * @return bool 当图片相似则传递 true,否则是 false   
      o& f- Q: S- g/ c  p2 r
  120.     * */   
    & }+ Z* Y7 Z2 B# f; [
  121.    public static function isHashSimilar($aHash, $bHash){   
    + M8 ]* b* v' D1 M1 e4 W
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ; x8 y+ X( P( P0 `" g+ N% F  H$ I. l, V6 |
  123.        if ($aL !== $bL){ return false; }   
    ! ]4 K, d2 p8 m/ h5 O
  124.    
    + @- d' i4 [. Y9 C* z/ O# \
  125.        /*计算容许落差的数量*/   
    6 M% F+ l* Y. X9 l$ j% v& Q( j- m
  126.        $allowGap = $aL*(100-self::$similarity)/100;    & j& |9 X) y* ~1 B2 [! o, [
  127.    
    5 z  ~  Q: N6 `3 x, z! }
  128.        /*计算两个 hash 值的汉明距离*/   
    1 W7 J  I6 A% m8 f" B: H
  129.        $distance = 0;   
    3 R2 L* R8 O* S& g( c8 j$ s; J7 m
  130.        for($i=0; $i<$aL; $i++){   
    " V) L: P* y  K4 F% D0 ]* z
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    : R4 L, K) O1 f# v# c/ P! G: `
  132.        }    8 _. T3 N8 o# P* J! y" v$ ]
  133.    
    * H! O# l- ~6 l. J
  134.        return ($distance<=$allowGap) ? true : false;   
    1 K" t' k; R# m
  135.    }   
    1 C. S0 n4 A) a9 ~( L! Z7 d
  136.     . _& R1 v$ ~* r) v4 V
  137.     : e. ?$ h" _+ b- Y7 K- [
  138.    /**比较两个图片文件,是不是相似   # c0 O/ _/ {+ J8 b$ C9 r
  139.     * @param string $aHash A图片的路径   ' M! g. X+ F* [) W
  140.     * @param string $bHash B图片的路径   8 f1 F7 r6 K5 r- Z+ ?2 \# h' S
  141.     * @return bool 当图片相似则传递 true,否则是 false   1 w/ N* Y/ B, W5 N/ E, Z1 S
  142.     * */   
    ) g/ \& n! D6 `5 X/ @. u; I  r
  143.    public static function isImageFileSimilar($aPath, $bPath){    # m8 I' n% H; r% y
  144.        $aHash = ImageHash::hashImageFile($aPath);    : R4 |/ U) V" {+ T
  145.        $bHash = ImageHash::hashImageFile($bPath);    8 ~8 \5 Y5 [7 S, g
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    . A: s0 J3 I' J- r5 i
  147.    }    & J( y, T, [( N7 p9 V) C
  148.     : Q6 W7 U3 X* T- n4 U. G- v2 Q& i" r( ?
  149. }
    % g5 J9 f/ k4 C, X4 O/ B( j
复制代码
" ~9 w  w) ^- |
5 F: l7 H0 M" q$ k, T% f* j5 K* g- ?# p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-20 00:34 , Processed in 0.085124 second(s), 20 queries .

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