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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" y" h/ j! ?9 e. }6 L) ?; x由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
* f7 w. n8 E( G  a) L
  1. <?php    9 f) N4 v% T1 I3 M6 x- \8 ?
  2. /**   
    ; C& X5 A2 @1 Q% E5 I- E
  3. * 图片相似度比较   
    ! q+ j' o) p/ p0 @3 W
  4. *   
    8 p( _, o( D( F. e- H1 a& ~
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    . L. t0 R0 c: \% q
  6. * @author      jax.hu   
    0 b  z* L4 I& k: }+ |+ @0 [/ H
  7. *   
    ! u" v) F( R- s7 }  k3 |* }4 y
  8. * <code>   
    ( L& s2 k( w8 w- x6 f* N+ S
  9. *  //Sample_1   
    7 g0 ^4 i' ~! f7 ~5 h7 e" L$ R9 F
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   1 s5 I! S3 P, w; n  e: F
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   2 s" }: T6 l3 T4 O8 P
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   8 V. v; C- A# `9 m
  13. *   $ C5 v2 ?; U1 {: O$ D3 ?
  14. *  //Sample_2   , m% K" o: W& y3 j, E) f
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ! ?* j5 R' X2 g, w# d( t8 o
  16. * </code>   
    . `5 H* y! Z" A; q, P# d) O- j2 c! o3 j
  17. */    9 t* G9 U. Z9 f
  18.    
    ; I; G" g" E! z- ?7 a7 x
  19. class ImageHash {   
    " ]1 L) W' U/ T& v) D
  20.     + @  y& o) ~+ M' s9 Q
  21.    /**取样倍率 1~10   2 S  C9 S2 r* S( Z
  22.     * @access public   
    # f' q; ^$ l8 `6 [% d& c( h) J  G2 I
  23.     * @staticvar int   
    3 N5 Y! E* W7 x0 p( f
  24.     * */    ( J& G1 @) J( y; n; _
  25.    public static $rate = 2;    $ c% o! \8 M# s. Y3 @
  26.     $ e; m( f, g6 P) k, U. o
  27.    /**相似度允许值 0~64   # m& |: k) O7 j9 }' i6 b
  28.     * @access public   
    : ~8 J  \5 ~% |. V$ k+ @* j- \* R
  29.     * @staticvar int   ' Z, s: J$ o+ s
  30.     * */    $ z; C. _4 j2 U; W( R5 E" `' r
  31.    public static $similarity = 80;   
    + i" C' y! I% |  f$ @# Q7 c. ^
  32.    
    / g, D. e7 {! ~" G4 Y$ `- f
  33.    /**图片类型对应的开启函数   
    ; J& L% J1 `1 v# z3 Y
  34.     * @access private   
    1 S+ Y" x0 B# n" U* h7 |8 u
  35.     * @staticvar string   * c, s' {6 r/ c: {" @3 T
  36.     * */   
    % p# z  b: b' S& |
  37.    private static $_createFunc = array(   
    " K8 K& n, w  H* ?! y; ], Y6 n
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    7 {4 n/ D+ \% e3 ?# c4 F5 i
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    6 M; Z3 L9 B2 i9 a
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    0 S  n0 }# H5 `
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    9 R6 X& W' X* U! p  t5 r- p. Y7 b
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    " Z4 V" V$ k8 H1 o0 a4 |) ^
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    . K% Z, P8 V7 J+ f2 P+ j- f$ _7 h" a
  44.    );    + t  ?' e0 n0 D, |7 W, G8 J, `
  45.     3 q% E) Z1 A) |& P
  46.    
    " U; l2 ~9 H/ b6 E
  47.    /**从文件建立图片   
    , h& E2 A, L" A7 C0 ]
  48.     * @param string $filePath 文件地址路径   
    8 m3 |. s& L4 z, M& S4 r% R2 ?
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    , f! h2 V- x  d% a* f! a
  50.     * */   
    1 l" f, \; q4 [4 x
  51.    public static function createImage($filePath){    9 k$ X! J2 l" s' w
  52.        if(!file_exists($filePath)){ return false; }   
    8 k5 W" @1 ^" L& ]  ^+ C
  53.    
    0 O; S0 t5 c8 H# S& a4 q- x, \
  54.        /*判断文件类型是否可以开启*/    1 r9 z  K3 \; m' ?- N
  55.        $type = exif_imagetype($filePath);    & O+ i4 n# a3 ~+ i9 E- u
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    % W- d0 x* ^; Y" ?8 ~* A5 r4 x
  57.     * [7 O5 `; C; V3 L8 ~. u
  58.        $func = self::$_createFunc[$type];   
    " y9 O' s# g8 d% d2 ^8 j
  59.        if(!function_exists($func)){ return false; }      N! o1 s$ ^, r. G2 F6 [
  60.     ! f: l) }2 D; F2 E2 R8 F
  61.        return $func($filePath);    - D0 n1 H7 `. U% i( i, g
  62.    }   
    : Y; q; f* C3 K  D, K8 R1 Z
  63.     - w9 p; r* k, h3 h9 W% T$ G
  64.    
    : [1 \) b: i; u9 f
  65.    /**hash 图片   $ o% A  Q8 r. @0 X$ q. O5 ^* t
  66.     * @param resource $src 图片 resource ID   * S$ z7 F  q: }/ P4 p6 ]8 g
  67.     * @return string 图片 hash 值,失败则是 false   6 U4 I5 v* O9 ~3 X$ W% ?" T8 U
  68.     * */   
    5 Y& H) f2 E" t* y/ B
  69.    public static function hashImage($src){    ! v% |1 V& i6 ~$ V
  70.        if(!$src){ return false; }    8 A% N4 u: p; y% ?( d+ H/ S7 x6 s
  71.    
    * X+ }! j0 A* I
  72.        /*缩小图片尺寸*/   
    8 @8 p! y( X1 D2 L, Y
  73.        $delta = 8 * self::$rate;   
    + @0 A( ~$ \+ \
  74.        $img = imageCreateTrueColor($delta,$delta);    : _" B0 e! u$ G& V$ @8 }
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ' b* B0 D# A1 T, v1 W0 j
  76.     $ o7 f: b% _, X: R0 ^2 o& Y8 R8 m
  77.        /*计算图片灰阶值*/   
    & B+ ~- \5 H, t! F! j# m- H
  78.        $grayArray = array();    ' E+ E2 z& h' c' }! J+ M( v3 `
  79.        for ($y=0; $y<$delta; $y++){    ) ^; E5 H+ h. w5 ^
  80.            for ($x=0; $x<$delta; $x++){   
    , C. ~, i9 f$ {3 T& A' E; i
  81.                $rgb = imagecolorat($img,$x,$y);   
    8 N& H& p6 X5 r
  82.                $col = imagecolorsforindex($img, $rgb);    0 ~. z4 @' i' E1 [  V' v* c
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    6 h  D0 A( h, v9 w$ L
  84.    
    1 h; V. M! J0 ?. z' b( o. F
  85.                $grayArray[] = $gray;    0 U, B- S7 \9 A' U& V* ~
  86.            }    # }  g# L2 f% M2 C+ [3 f% M
  87.        }   
    6 X2 g; v- r  Y- D' U1 U5 P$ X
  88.        imagedestroy($img);    - w/ i9 a6 ~8 Y& c* S8 u+ P
  89.    
    ; A3 P/ I! [9 [4 `4 v) }" P
  90.        /*计算所有像素的灰阶平均值*/      I+ Y9 [# Q9 J$ C8 L' v& B
  91.        $average = array_sum($grayArray)/count($grayArray);    / M0 C$ m1 U, m) A/ q
  92.     : l4 ^* P+ t" I
  93.        /*计算 hash 值*/    1 V, W9 e0 E+ t. P. H
  94.        $hashStr = '';   
    7 ^% |# O/ w" d" J9 W7 |5 X
  95.        foreach ($grayArray as $gray){   
    # E' T! V" u9 [: B4 g: X
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    ! x3 ^' ]4 |/ y
  97.        }   
    $ _  D% E8 n- R7 C! q5 u7 ]# a
  98.     * o9 X+ R0 ^) Z+ f* X9 q7 w2 J: Y
  99.        return $hashStr;    + y1 M( p; _5 s
  100.    }    ! I- r- Z' p3 i. r5 m# `# Y
  101.     4 r* b5 V, ?3 T6 D
  102.     4 B+ E4 ?, |2 ~$ H8 u9 v# T3 C. P
  103.    /**hash 图片文件   
    # {- V7 G, v* U& F! J5 n
  104.     * @param string $filePath 文件地址路径   
    % S- T0 d, M" Z
  105.     * @return string 图片 hash 值,失败则是 false   
    8 m% x, l, ~% M* b  X. S
  106.     * */      j2 e8 y+ s4 u
  107.    public static function hashImageFile($filePath){    , o& e, H9 @& S$ E& Z
  108.        $src = self::createImage($filePath);    , `& s2 p# N9 b, V
  109.        $hashStr = self::hashImage($src);   
    ! _+ {1 l; H3 L* Z! n# l: s
  110.        imagedestroy($src);    3 w% a, S. ?% J. |: I! O, W; ^
  111.    
    2 L6 A2 p, N8 P2 v; i
  112.        return $hashStr;   
    $ q: A& u) B% _# @3 ?
  113.    }    0 L; J4 S! y  o% ^1 m. [7 l
  114.     " H2 A: [1 _, |9 J1 k+ d5 S
  115.     . F; p: U* o1 ^- l6 o, V
  116.    /**比较两个 hash 值,是不是相似   
    ; m$ T( O3 r% E7 [3 Z; Z1 F
  117.     * @param string $aHash A图片的 hash 值   
    5 Q2 q6 s- W& N7 W$ k
  118.     * @param string $bHash B图片的 hash 值   
    ; @( E8 V* }3 S3 h: o, g6 I0 c
  119.     * @return bool 当图片相似则传递 true,否则是 false   % Y- I0 b+ y' \$ C/ o% V2 ^  {
  120.     * */    2 S. v) }6 U  Q, E, n5 r
  121.    public static function isHashSimilar($aHash, $bHash){    7 G" b1 r6 e3 O8 ^7 V8 Q9 k
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    0 i6 [$ n/ z  r( [( p- _& c9 M. F8 p
  123.        if ($aL !== $bL){ return false; }    # m' E( U9 Y* K$ L0 j
  124.    
    + n8 ]  t9 J7 E7 P8 h) g. g
  125.        /*计算容许落差的数量*/    8 M' L2 ^( h5 ~
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ; ]& k1 q' g0 C! W- N0 }
  127.    
    4 a* C7 _- K4 H1 J* \' F
  128.        /*计算两个 hash 值的汉明距离*/    0 [: L  O, k2 A1 G
  129.        $distance = 0;   
    - e: [9 N- C2 C$ h. }" w8 J
  130.        for($i=0; $i<$aL; $i++){   
    ) b. a8 |% n- U6 k% U! ]7 J
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    0 E. S0 b1 j, \+ f* _+ e, A
  132.        }    9 a. B+ t7 i7 }2 [( K
  133.     # w4 h2 E( [# S$ t( c
  134.        return ($distance<=$allowGap) ? true : false;   
    9 \. q$ a) e5 {$ t1 a
  135.    }    6 G7 z2 k4 q+ R' l( a; `* |' J
  136.     2 y% \+ n! j5 a0 H  l9 R
  137.    
    1 D/ X2 W; {$ `7 w
  138.    /**比较两个图片文件,是不是相似   
    7 `5 X/ I8 b) l1 E9 R
  139.     * @param string $aHash A图片的路径   2 Z8 u7 E5 Y8 h. Z: i; C; g' ~
  140.     * @param string $bHash B图片的路径   % t7 J* F6 U5 m2 f. G( G2 H, D, Z% m
  141.     * @return bool 当图片相似则传递 true,否则是 false   . p$ M* Z+ @6 p" v2 n; ^
  142.     * */   
    6 F( H8 Z& ^6 Y% }  {# |
  143.    public static function isImageFileSimilar($aPath, $bPath){    " ^% M% g/ y; V# @% e$ ~  W2 i
  144.        $aHash = ImageHash::hashImageFile($aPath);    . v! a% s2 e, t3 N8 e; E* c1 G
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    . S# k1 R% K9 S. d, I5 _
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    ) ~! a; a, f' N) y2 F3 j
  147.    }   
    3 W4 Q% V& `3 |& _4 Z
  148.     8 T0 O' I, U5 R" y. c
  149. }
    ; M" Y2 f, i# J. {& w; Z
复制代码
# d8 {9 A4 d! a0 W) P' L5 l4 k* }
" Q( a% ]  d( u: \2 G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:08 , Processed in 0.116928 second(s), 19 queries .

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