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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

! u( J- c! N4 b由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
2 Z& q8 }$ z/ T% H8 T; |
  1. <?php    ; |& j) m2 d1 L+ U+ G- X
  2. /**   
    , y6 R2 I3 f" h* G. @3 s
  3. * 图片相似度比较   
    7 ~( W) F7 S+ ]3 U1 X) c
  4. *   
    # r, z: i3 b- F
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ; u2 g/ `& G" g3 c& \) P9 z
  6. * @author      jax.hu   + |5 M* g" T; x; A
  7. *   
    ! R6 s& i2 W: r6 h& x
  8. * <code>   4 d+ U5 s0 I) [3 W4 n
  9. *  //Sample_1   7 z. `6 K" C+ w% Z' h
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   3 d- G1 v5 Y8 y; U
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   / ]. ~5 F/ m% b1 ?6 ]3 r/ i, G& A
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    # d2 g9 g1 f8 U
  13. *     a, @. p: B/ y( L
  14. *  //Sample_2   - w( F% U8 `# Q, n9 v! O
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    9 P+ O$ @5 G+ n
  16. * </code>   6 L( v, Q: g& r8 F/ B, p1 p
  17. */   
    2 \$ [" ^, Q2 r9 }' z+ R: l9 ]; ?
  18.    
    4 P- S2 Q% Y: @' |( w
  19. class ImageHash {   
    9 A0 x3 V$ ?* l# i- k
  20.     ; K& h$ w4 f5 k" T' W
  21.    /**取样倍率 1~10   3 S! p3 W" V; ~, T, i
  22.     * @access public   
    2 `. b3 r1 u# o# x, M4 C9 r! K" a  ?
  23.     * @staticvar int   ' |% w+ S$ n2 R: u; |2 m; A
  24.     * */   
    + E0 s/ y; v/ j$ u; ?7 g% D
  25.    public static $rate = 2;   
    - e9 j8 y" S& D
  26.    
    " L. V6 `, R3 D# F% m
  27.    /**相似度允许值 0~64   9 t2 X2 t( I9 h: w6 w5 w
  28.     * @access public   1 N8 n( G5 y  b! u7 y+ n- i
  29.     * @staticvar int   3 s9 D5 ^( w1 ]) j
  30.     * */   
    ! N+ b+ R  A* l+ T
  31.    public static $similarity = 80;   
    # E$ q5 B" l! ~; P: D
  32.     & O1 M/ l0 m3 r9 c) c
  33.    /**图片类型对应的开启函数   . A2 |6 R9 R' A( \1 K
  34.     * @access private   
    3 ^+ E2 u; N4 R$ ~. J
  35.     * @staticvar string   # D3 o2 v% W& p2 l: a- j+ W
  36.     * */    ' O; G. Q: I* e5 O
  37.    private static $_createFunc = array(    2 b, P  V2 E$ ?; r
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    " n5 E6 j3 x& q
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    4 I) h/ ~( j9 ^  x" [8 r
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    9 C' C4 {' J" H, k7 O6 ~
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    1 g2 u. V8 ~0 ~$ [  o
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    * {/ b' N; |8 W' D4 [
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    " P& P9 C* N4 L$ J" b9 q
  44.    );   
    1 A$ l; j& R! q: Y, M2 m0 u
  45.     / g% g. k& |3 }9 n. s5 ?: n
  46.     & A' m: ^/ `+ |6 h& e( B
  47.    /**从文件建立图片   
    2 V2 h( F6 |) H* U2 ~- C
  48.     * @param string $filePath 文件地址路径   
    $ s7 s; g$ t0 x2 t2 P0 m2 @
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    # c# v. S2 G% M
  50.     * */    8 K) l4 I4 j2 c( Q2 l
  51.    public static function createImage($filePath){    6 W& K- B9 b" M9 H. N2 J! r* i4 e- |
  52.        if(!file_exists($filePath)){ return false; }   
      N( A# [4 L( w7 Z# T2 ~% B9 Y$ _
  53.    
    " ?5 e3 X0 O: b& I3 c( ]. k
  54.        /*判断文件类型是否可以开启*/    3 ?0 O9 d5 m$ h7 B& P% `, G/ ]
  55.        $type = exif_imagetype($filePath);    8 Z& T( E1 o' r$ r# [
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    ) q" `7 t% z# Q$ r* t
  57.     9 @( D$ ]* b' R
  58.        $func = self::$_createFunc[$type];    9 m' ]6 E5 F! V! n7 ^, Y4 k
  59.        if(!function_exists($func)){ return false; }   
    4 j% O# c; a" e0 r
  60.     # X% O! O5 i* ~3 A
  61.        return $func($filePath);   
    " j" `& S% _9 N, p6 @) t
  62.    }   
    7 G& n5 @2 {& ]
  63.     % ~7 @3 h2 [) A4 k. t, G3 N
  64.     3 S9 |* w# A; k: B
  65.    /**hash 图片   
    / t; \( M7 M7 @1 a/ C9 x
  66.     * @param resource $src 图片 resource ID   4 T* G2 y8 h) v+ z( S2 ?% H( M2 b
  67.     * @return string 图片 hash 值,失败则是 false   
    . e+ b+ k6 c% Z# X4 }" n4 p0 C
  68.     * */    + C0 p% Z8 ~5 m3 H, g1 M" e2 Q
  69.    public static function hashImage($src){    $ z$ c6 Y2 @8 V
  70.        if(!$src){ return false; }   
    1 r% L6 J0 e1 M2 ^
  71.     $ `" @8 K& t9 M! P: Q# q
  72.        /*缩小图片尺寸*/    2 m# E2 ^4 v3 V1 K9 c
  73.        $delta = 8 * self::$rate;      h0 \; C+ f/ I3 K# E$ B$ r5 g8 J
  74.        $img = imageCreateTrueColor($delta,$delta);    7 d5 l+ n" |6 |0 Q+ Z
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    1 p4 G5 R. B2 I' w
  76.     & O% @/ t& T  V8 o4 V
  77.        /*计算图片灰阶值*/    ) d! y$ A. U. L* o! r
  78.        $grayArray = array();   
    - H+ m2 ?% ?* C: E$ o8 v# ]( j
  79.        for ($y=0; $y<$delta; $y++){   
    4 \' _5 i# H6 j7 Q, B
  80.            for ($x=0; $x<$delta; $x++){   
    3 B& h8 H9 H1 C% Q9 H
  81.                $rgb = imagecolorat($img,$x,$y);    / g, T# ]- w% |. L# W4 O: d2 d9 m& d
  82.                $col = imagecolorsforindex($img, $rgb);   
    2 R7 r& c8 D$ G3 u/ i2 Q! F+ d
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    6 o9 B  \/ j- ^) [3 ?2 y) m6 R6 }
  84.    
    ' w( E4 t- ?1 d8 y) u* F- R
  85.                $grayArray[] = $gray;   
      v+ o6 T/ u( ]6 x1 I
  86.            }   
    ( S3 J6 x4 e; Z' F% t1 Y% g
  87.        }    3 p$ j- s( A- M% t$ G. Z# T
  88.        imagedestroy($img);   
    " `% |  z3 ]4 n
  89.     " ~. Q0 f1 Z/ E! B0 S
  90.        /*计算所有像素的灰阶平均值*/   
    9 C$ s6 }. N. J* g0 q. {: C
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ( h! B. ?0 f+ b0 Q
  92.     - ]: S# D; n9 c! O+ \! T$ j# Z
  93.        /*计算 hash 值*/    6 f+ y, I" w. |
  94.        $hashStr = '';   
    * k" g! Y: w6 X+ ]' N
  95.        foreach ($grayArray as $gray){    ) J# T) [7 B! F3 l0 S
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
      ]4 q) h: ?. @! l+ F" o; s: k
  97.        }   
    ' T- W) H9 J8 p, @5 l
  98.     " D( s9 [1 t' J. q
  99.        return $hashStr;    " x2 ?2 y$ C, y! p" ~' O& J) l
  100.    }    - a4 F  q' n" B. z/ x1 v
  101.    
    5 x: ~; {# p: ^" X
  102.     7 d2 P: o0 ^, Z. c/ ]
  103.    /**hash 图片文件   1 b$ `8 e1 E) m& z2 L
  104.     * @param string $filePath 文件地址路径   
    4 \/ L5 c7 e  v' ]9 |7 a3 q8 a* T
  105.     * @return string 图片 hash 值,失败则是 false   
    * @8 X7 H# x8 r9 \. M7 z% z3 n
  106.     * */   
    $ p- @1 s. d. S6 `% G: S- I/ M8 U
  107.    public static function hashImageFile($filePath){   
    1 A1 S0 y5 J% L: n8 {
  108.        $src = self::createImage($filePath);    0 q+ v6 b: f8 a4 s; q5 X' ?) C
  109.        $hashStr = self::hashImage($src);    6 ]/ @0 F9 C% l2 ~+ K0 e. `0 z
  110.        imagedestroy($src);   
    ! `) O2 w; N9 @0 w2 V7 X
  111.     $ Q9 ~( [. {+ I( ?& N: M6 _
  112.        return $hashStr;    8 Z! c% t2 @& }' T. _
  113.    }    ( t; @( [( n' X3 U
  114.     # ~9 h* e( n" y! r' }
  115.    
    8 Z( ]: v8 N) X# X( Y$ M
  116.    /**比较两个 hash 值,是不是相似   : ^9 }3 c; Z: [3 Z& b. k
  117.     * @param string $aHash A图片的 hash 值   
    0 e4 M1 @3 T1 p- t1 W3 M
  118.     * @param string $bHash B图片的 hash 值     c& `7 e0 e1 V! n7 @) I
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    5 d. v, r) v% g6 S4 M
  120.     * */    . ^9 X  e) y! t/ e' S  F: D. k" {5 {  E' Y
  121.    public static function isHashSimilar($aHash, $bHash){   
    . k$ n. i! d3 S, w; ]
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    2 j  Y% G' e, _: }. Z
  123.        if ($aL !== $bL){ return false; }    2 f6 p. D* g6 u; |
  124.    
    * D/ O# E' y; c
  125.        /*计算容许落差的数量*/    - r8 U: d+ j6 V4 `  p4 C$ p
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ) N: Q/ W# S. [& w/ f' Z4 o
  127.     9 L% e7 [- {# W( k  `
  128.        /*计算两个 hash 值的汉明距离*/   
    + o+ X# n8 G5 e: q' I
  129.        $distance = 0;   
    ' i) ?8 j$ O+ L5 k) p  @, _$ p
  130.        for($i=0; $i<$aL; $i++){   
    / S1 k* U! K9 ^# l. |4 o# c7 Z
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    : J; ^2 k" k4 R6 K: d
  132.        }    8 N$ c5 t- T9 y
  133.     5 W+ k+ M' d; y& n8 F) V+ I' n
  134.        return ($distance<=$allowGap) ? true : false;    ; o9 F. t8 ~, n( f
  135.    }   
    7 A0 d, U" V5 _, U' A
  136.    
    1 I( D3 T1 y; t# A
  137.     , j; ^" L0 d- \0 m+ `4 J) Y$ v' B
  138.    /**比较两个图片文件,是不是相似   # ?0 y3 \3 L2 Z0 J
  139.     * @param string $aHash A图片的路径   
    4 o2 n7 o- N# {- r. x( L0 H9 ~  q
  140.     * @param string $bHash B图片的路径   ' ^! ~* m% @) U$ F
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ' Q! m7 E- Y+ j6 J1 O6 @
  142.     * */    : p' W# Y! V  C
  143.    public static function isImageFileSimilar($aPath, $bPath){    $ E7 Y# Z$ p0 e! M4 U& c9 R: \0 F
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    , r$ g/ u: n" c* ~- R5 y" E
  145.        $bHash = ImageHash::hashImageFile($bPath);    2 ^6 y; y! [0 ^5 V- ^6 X2 }
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    # p; A! ?5 W- l7 Y# b: c' X7 k. U, W
  147.    }    $ ^, [* ^- ^# E- T' r  a  K
  148.     0 @7 U7 W" g* |+ u0 |$ F/ t
  149. }
    - F0 I( G$ f+ F' f! a
复制代码
" W. s& I7 l  E6 ^' p

# k* i% r+ O/ y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:25 , Processed in 0.144959 second(s), 22 queries .

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