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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图% U3 G- O) s  M& g/ R
. n) q* I) j6 V

' X* k9 p; x( q- f3 m由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

6 O& o2 q3 P* G8 S
  1. <?php    . v5 Q$ E5 J1 K( m
  2. /**   & s/ j9 t1 l/ h# q: Q. F! k
  3. * 图片相似度比较   
    / j) x2 E& o8 r  D
  4. *   
    + i7 Y7 k6 I8 h; ~5 B# `
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    / C7 w4 D% O- W, A3 U
  6. * @author      jax.hu   
    4 ?! j& W8 G# u4 y, a5 r
  7. *   
    ' L( E% X) i( Y2 g6 K
  8. * <code>   
    1 b. ^5 r% n3 X4 m* {
  9. *  //Sample_1   $ ?4 \' H4 x' J' m
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    : j1 G0 y7 D5 W; s( O5 `) h- O
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    9 ?" ]) I0 L' b) u- T8 L
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    1 F. F7 o1 J- k& B+ I# A
  13. *   
    ; A6 j2 W8 C8 A/ {) G8 s, v
  14. *  //Sample_2   + C' L2 X& y& R/ H
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    1 V0 w9 f+ a1 D9 P7 ]* y
  16. * </code>   7 w* j7 g. h2 y2 u8 r. D
  17. */   
    9 H) U/ b7 w' p1 \. {
  18.       [0 R# `3 E$ r8 |% B
  19. class ImageHash {      ~- \5 x0 E, M+ m/ [
  20.    
    + s2 ~9 u! V2 p8 f' {6 G3 }
  21.    /**取样倍率 1~10   7 x  Q, c( \) G; @+ w
  22.     * @access public   
    9 N$ |# x) L" f$ {! r, e* b
  23.     * @staticvar int     _* a) F4 v& ?- B
  24.     * */   
      b5 F% x  Y9 `  A+ f
  25.    public static $rate = 2;      n4 B8 `3 I; t6 W
  26.    
    ' z+ @. l; u! h0 ?7 E- l$ Q4 c5 {4 }
  27.    /**相似度允许值 0~64   
    1 N# q5 R. V1 t2 Y, L
  28.     * @access public     U. F5 e/ Z! Z2 B8 d
  29.     * @staticvar int   . P) {& }1 Z% M" c) O
  30.     * */   
    , Y" M- a" J4 B) V9 z6 N
  31.    public static $similarity = 80;    9 y% L! y; O/ Z$ ?9 k, _7 I
  32.    
    6 v' |# p7 c8 t6 g6 I6 k
  33.    /**图片类型对应的开启函数   3 q5 t" A3 X7 K# H' F
  34.     * @access private   3 ~+ y: B8 e) N
  35.     * @staticvar string   2 X# s8 A0 o+ b
  36.     * */    5 @4 t  |- U9 Z# g3 X2 T
  37.    private static $_createFunc = array(   
    4 m) ?* [( V' q( M2 |" g& b6 k
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    * x3 b5 J1 I1 z! D, I* G3 Y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ! j8 ^. G9 W6 L
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ( D6 R5 D/ q2 P& D8 L4 v) m
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    * O& g: @! U7 d# G' X
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    7 ?6 t) v6 |% f7 S3 I
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    # D( N1 Q& m4 r
  44.    );   
    " |, Q# Q( p3 Y  _0 |$ [
  45.     5 [8 }7 I# O. }. o9 f# I
  46.    
    ) z: H' ]! z6 u' V  g! X& }
  47.    /**从文件建立图片   4 d) {+ U- o3 T. y& _
  48.     * @param string $filePath 文件地址路径   ' y5 s" i% l6 j2 z$ i
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   8 h( t& ?& d  J9 I/ N( P8 U. K% N
  50.     * */   
    ( }* Y1 P1 p0 b1 b; B  ?7 T0 [+ |
  51.    public static function createImage($filePath){   
      p- ]! T3 [; t' e! ?
  52.        if(!file_exists($filePath)){ return false; }    4 `  _$ G4 e! a
  53.     ! e$ [, Z/ \- C0 V+ h3 \
  54.        /*判断文件类型是否可以开启*/    , |7 U* o) G# g/ q
  55.        $type = exif_imagetype($filePath);   
    * x( C0 F/ q1 e5 u/ V
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ! l6 M! B  D) e% c2 h
  57.     - r0 q/ O- ~; E. k. {) A* @/ T* n
  58.        $func = self::$_createFunc[$type];   
    " @6 ?; u6 @! f& D  ?
  59.        if(!function_exists($func)){ return false; }    5 X9 b# u3 v4 o2 Y6 Y5 |  H8 {
  60.    
    4 L# U- }7 g4 u& \% F( ^. c+ `
  61.        return $func($filePath);   
    $ S9 u% l7 B- p; {
  62.    }    " T5 q! f# o( [; H/ T
  63.     # q8 N) ?1 P7 C
  64.     / B" }2 M: r& P3 s8 d
  65.    /**hash 图片   
    9 ]& ]  D* s& C+ a; Y9 V( U
  66.     * @param resource $src 图片 resource ID   0 T/ r  C5 y( ^# K7 a
  67.     * @return string 图片 hash 值,失败则是 false   
    5 H4 g( p+ Y0 S/ k' S% a
  68.     * */    ; `# n% G: R  ]$ i; y" F/ o
  69.    public static function hashImage($src){   
    * r" u) r8 Y4 m. s- T" A, B
  70.        if(!$src){ return false; }    , l, Q0 L; O4 S1 a. q& H0 d- w
  71.    
    8 Z% t* _3 v8 O2 V  y9 H  |  \7 v6 D
  72.        /*缩小图片尺寸*/   
    : k8 Q/ W) P. M- S" ~3 k
  73.        $delta = 8 * self::$rate;    ( ]' o. W! k% S, Y
  74.        $img = imageCreateTrueColor($delta,$delta);    % ?- @$ g' ?% G. S) [
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    1 V! h& E: Q' _
  76.     ( u. U9 D/ R& W" |  F2 V/ F# Y8 I
  77.        /*计算图片灰阶值*/    " g( ~8 ~& \) C; R1 i  h/ c2 ]0 F
  78.        $grayArray = array();   
    * i/ l8 ^+ e; C) ^. C1 L1 e
  79.        for ($y=0; $y<$delta; $y++){    ( s  H1 p- a( {8 `
  80.            for ($x=0; $x<$delta; $x++){    8 s1 R- [4 l1 n, f  S0 z2 e
  81.                $rgb = imagecolorat($img,$x,$y);   
    & H$ I' f- f" a; Q
  82.                $col = imagecolorsforindex($img, $rgb);    ) {# g* P: _% d: v7 \& f/ r+ |1 C
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    " U" `' q* I; ^
  84.    
    ! N# K( ]. U  e; T/ W& _
  85.                $grayArray[] = $gray;   
    " C) V; [8 d. O" E& G
  86.            }   
    7 z; T. U3 Q8 I! c8 |7 {% ~
  87.        }   
    ( H  \, ]; Y- e. x2 i5 ^
  88.        imagedestroy($img);    ( k0 w9 N2 s- t5 b  S7 b$ b2 V
  89.    
    ) k+ Y2 U& j# n# D0 g: Z
  90.        /*计算所有像素的灰阶平均值*/    - `& Q9 y* j# `' n6 {5 V! f
  91.        $average = array_sum($grayArray)/count($grayArray);    - x' Z! S4 i) [+ g: q2 ?' ~( N" m5 B
  92.     ; [8 O( ~6 Q+ j& ?( J4 n
  93.        /*计算 hash 值*/    # o- N  v! W! K2 z$ v6 C
  94.        $hashStr = '';   
    . d/ J1 ]: x8 Z. [" h5 @8 o  t
  95.        foreach ($grayArray as $gray){    1 k1 |. O2 a6 |+ r9 U
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    3 ~4 H7 P6 i) B6 X6 y1 o
  97.        }    - \4 x7 x4 p6 M3 G  }3 Q) ]
  98.     + V- x( H" d6 i( g( J$ z- v3 p
  99.        return $hashStr;    - i  d/ z* `* [8 o( V% \
  100.    }   
    : O3 A2 d# [, w( d' R) i8 o
  101.    
    ; {8 S" j$ S1 p# S8 u  `
  102.     9 B9 B" J8 Z% Z9 J
  103.    /**hash 图片文件   
    & d0 X6 `$ Z+ F0 L! z
  104.     * @param string $filePath 文件地址路径   
    ' Q7 F" G6 A) O1 i6 P$ C3 V4 m8 o2 n
  105.     * @return string 图片 hash 值,失败则是 false   
    2 U" f" v! P# c1 w  ?! J6 x3 P! H
  106.     * */   
    3 M! n7 Z) p9 |3 Y
  107.    public static function hashImageFile($filePath){    8 y( M( `* P* u  E3 d! o
  108.        $src = self::createImage($filePath);    : M7 ^2 Z3 |2 h, a% \
  109.        $hashStr = self::hashImage($src);    $ [8 H( \) X* X0 X; I0 N
  110.        imagedestroy($src);    * Q6 L! K, I# R
  111.     6 s( a* m7 a- V
  112.        return $hashStr;   
    ! {- J9 e9 j. @
  113.    }   
    3 y9 K) |$ K* V& m- R2 l* M
  114.     2 ?$ C5 H" I0 M, l! e, L; m
  115.     2 _; q9 V; @* b2 ?
  116.    /**比较两个 hash 值,是不是相似   
    / T0 f" }% L& c7 ]0 q2 j8 s# c8 q/ {
  117.     * @param string $aHash A图片的 hash 值   4 r% x- e" t9 d. B1 s/ q# q
  118.     * @param string $bHash B图片的 hash 值   
    ! d2 C6 Z8 X( `: a' M+ r
  119.     * @return bool 当图片相似则传递 true,否则是 false   , p8 D7 C) \& K5 q  G2 K
  120.     * */   
    " g7 R4 q! e" b9 l4 T) c0 P
  121.    public static function isHashSimilar($aHash, $bHash){   
    1 O, J- u" _8 l' T8 G& j
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    % _  k, o9 x* M. M% q! J  D
  123.        if ($aL !== $bL){ return false; }   
    & m4 k* P+ b" T/ g% {
  124.    
    1 \: G% v* V4 c6 S0 m' {+ A/ B0 x" H! [
  125.        /*计算容许落差的数量*/   
    % x* V" p9 Z& w6 J
  126.        $allowGap = $aL*(100-self::$similarity)/100;    6 T6 a2 b' X$ _+ e8 C7 A
  127.     9 |1 }: U. R0 ~' Y/ L" J( x0 Q. ]
  128.        /*计算两个 hash 值的汉明距离*/   
    . ~+ f$ r! a, }+ e! ]6 J: [$ ]
  129.        $distance = 0;   
    $ X1 E: Y, m0 i1 k6 m
  130.        for($i=0; $i<$aL; $i++){    ! R; }6 `7 N3 H1 h1 c; V
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    3 k" q. p( T5 x' m' V
  132.        }    ; G+ U$ X+ K5 ?# P2 L/ m
  133.     / ]  Y- _$ i* U9 |% V
  134.        return ($distance<=$allowGap) ? true : false;   
    & i8 \  @" p/ Q5 k9 E
  135.    }   
    ; u3 q6 J: U. U6 P
  136.    
    3 e* i+ |9 B7 v7 {
  137.     ' w: P8 N6 g- N
  138.    /**比较两个图片文件,是不是相似   
    7 @2 l. a5 H6 L- j
  139.     * @param string $aHash A图片的路径   
    & a( f! ~& j. q  }' ?! r5 ^' X
  140.     * @param string $bHash B图片的路径   3 h& }5 X$ O. _1 k- ^
  141.     * @return bool 当图片相似则传递 true,否则是 false   / R' _% A4 g% Y6 }# G" B$ h+ l
  142.     * */    , {# U( m/ m# S% z7 `/ a
  143.    public static function isImageFileSimilar($aPath, $bPath){    / U1 \  J7 \! P; G' v
  144.        $aHash = ImageHash::hashImageFile($aPath);    # M6 J; F+ Q5 v( n
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ; J, h, `8 ~: `3 @& i, ~
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    6 L% M3 J* @! m) `% [
  147.    }    ' Q2 {% U" a6 u
  148.    
    % {- x- I0 d  U; P
  149. }- g5 B6 X. F  ]# |
复制代码

  r+ L! }- b; b( G& W8 ~% j1 g+ l
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 05:21 , Processed in 0.065907 second(s), 20 queries .

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