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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

2 P+ c8 ^7 R' L& O7 w( a5 H
2 ^- W0 P1 H, _+ U/ H% I
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
7 A& K# C4 e/ K9 t
  1. <?php   
    0 ^9 o* V  M: |
  2. /**   
    4 O, j8 d9 K1 e& m
  3. * 图片相似度比较   
      T$ h( ^% `7 W3 \
  4. *   0 C) G5 r: c/ A
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ' s) ]; h. Q5 }4 \
  6. * @author      jax.hu   8 l! B1 q. Y, \) Y4 Y' M
  7. *   
    5 u1 G% B1 i# h: }/ W4 \
  8. * <code>   
    5 [7 f% r- t  \0 G" r7 q- T2 K  b
  9. *  //Sample_1   
    1 S! n# S- H6 g. ^+ q- d
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    ) J3 k8 [* l& \) D( ^
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   2 i# O" A4 `, `! U. V
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ( |2 I! ?- v9 ?, }3 R  N8 b
  13. *   
    . z! P8 `0 U7 }5 R3 `; h/ y) Q% H3 t
  14. *  //Sample_2   % q7 I" d7 v+ ?9 [) ^& C# f
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    / k9 v+ {% [! D9 {
  16. * </code>   ' s% ?4 j" H: Q6 f! s: @
  17. */    3 L! Z' E( g/ {( B4 w( s
  18.     5 m: F  f8 l/ M. m8 @& ~- D6 Z
  19. class ImageHash {   
    : K- K) b; \* r2 u
  20.     1 `" r* z4 r) W) u& `
  21.    /**取样倍率 1~10   " K8 u! c  D# W  `6 o' m
  22.     * @access public   
    0 v4 x* p3 o; k" C  e
  23.     * @staticvar int   
    , V+ }3 o, ?9 Z( r/ _& q
  24.     * */   
    2 u1 U$ h0 P. s4 o5 b7 o
  25.    public static $rate = 2;    . o0 Q" g2 O, _4 v+ D# O& c
  26.     * n8 u) L: K) u) Y
  27.    /**相似度允许值 0~64   , H; f8 ?) B; K
  28.     * @access public   
    , i4 F) `- Q! A
  29.     * @staticvar int   ) e, ^5 _' K5 E3 Y
  30.     * */    , L' b% b, G% R; A! p, c
  31.    public static $similarity = 80;    $ F8 T6 S' r; a8 T* s
  32.     2 j0 }: m* _- L- @6 f$ c0 L/ ?
  33.    /**图片类型对应的开启函数   
    " u  v' p$ H1 R& n6 ?/ Q& a
  34.     * @access private   ' g. A% C+ j" Y" _3 q
  35.     * @staticvar string   
    3 L2 c" Y8 w; |& d- ~
  36.     * */    & y4 L1 t! g3 o5 M  g0 Z+ E
  37.    private static $_createFunc = array(    ' j" a2 X; D. P, t9 I0 z% C$ ^
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    * v$ S- I* }$ ^
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    $ s8 A8 w: Z1 s: K5 S! G
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    - U& d: X: l5 G
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    / l6 f' `# X! d  v* \
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    " S( A1 v  ]- _. R5 I& @
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    # H" C, ?( r2 C1 e3 z
  44.    );    3 `& z6 w7 l3 _2 |  b2 d
  45.    
      q) ]9 O5 n, ^, S1 P
  46.     6 k9 H& `) g1 o. D0 Y6 }6 Q
  47.    /**从文件建立图片   
    , h& Y! T* h; l1 e7 H3 [; i
  48.     * @param string $filePath 文件地址路径   
    : \+ z0 `) F, L: r5 i
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   6 ^% d: R$ B% [# h
  50.     * */   
    0 S- r1 o) r' @/ M+ w
  51.    public static function createImage($filePath){   
      {, b7 y; |5 P7 U+ S
  52.        if(!file_exists($filePath)){ return false; }   
    ' Y" @7 J$ ~! g9 H. j* t$ ?
  53.     6 |$ Y9 X" h1 \" W1 T) ?
  54.        /*判断文件类型是否可以开启*/   
    ! o% b. u+ K& X/ M" _
  55.        $type = exif_imagetype($filePath);    $ v! ?) r% p! t
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ; C8 P8 @' [6 y4 n( C: q
  57.    
    5 r9 y' u: E2 |# m5 z8 d* T8 _
  58.        $func = self::$_createFunc[$type];   
    & \5 Y9 C. G9 O1 n1 c, u4 n
  59.        if(!function_exists($func)){ return false; }   
    $ `" h* J2 N5 V
  60.     3 }; y; ~/ w. ~$ C
  61.        return $func($filePath);   
    ) i* V' `* s! t* c* m0 W5 e
  62.    }    4 `3 Y6 d" g) E! `
  63.    
    1 Q9 {. b4 |2 r" I0 I+ I
  64.     + z, _5 }3 E9 J5 ~* s
  65.    /**hash 图片   9 ~, x. M, }0 j  o/ {+ U7 }
  66.     * @param resource $src 图片 resource ID   
    ; ~4 p1 I$ W) t' y& q
  67.     * @return string 图片 hash 值,失败则是 false   7 M/ y4 S" I" q9 K. I. @- Z
  68.     * */   
    8 ^5 o( V/ n% L0 `  r" ~
  69.    public static function hashImage($src){   
    & X; j% o) n# A# K  a0 v
  70.        if(!$src){ return false; }    ) M9 w- ^7 n) R, X! R6 w
  71.    
    3 Q4 C; {/ C7 e/ w: M
  72.        /*缩小图片尺寸*/    # Q, F; E- K; `
  73.        $delta = 8 * self::$rate;    , @6 i) @- M/ o9 M
  74.        $img = imageCreateTrueColor($delta,$delta);    : c2 v" V: k& a; R
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ( ]3 m! M4 b3 r" k
  76.     2 E  @5 i6 _! t+ [" l
  77.        /*计算图片灰阶值*/   
    ' t5 P5 v0 I/ ?
  78.        $grayArray = array();   
    - V8 ?0 H! D6 x+ g5 W% C5 q" W% r% S
  79.        for ($y=0; $y<$delta; $y++){    . }; V0 ^3 E1 S+ \+ _# d: {
  80.            for ($x=0; $x<$delta; $x++){    , F) f7 `: Z9 O7 I/ W* [
  81.                $rgb = imagecolorat($img,$x,$y);    + m( I8 Q* D, ?) J
  82.                $col = imagecolorsforindex($img, $rgb);    ( a4 {) z; C4 H/ n& `' ?
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    - {7 L2 F( J+ O+ @" b9 |$ O
  84.     ( `4 Y* d1 P3 }+ @
  85.                $grayArray[] = $gray;   
    7 m3 l/ t3 Y" n: ?4 h* b: l
  86.            }   
    1 x/ z( E7 Q1 P
  87.        }   
    . M4 v9 |8 o" U% K
  88.        imagedestroy($img);    5 P' q! c/ [+ a
  89.    
    6 \7 S) |! s4 x: a1 ]+ q) h. M/ d
  90.        /*计算所有像素的灰阶平均值*/    0 j9 i% D/ X* |
  91.        $average = array_sum($grayArray)/count($grayArray);   
    8 V1 n& m* r8 j' A! L
  92.    
    3 L) Z; `* ?$ p$ j- p7 X* G- p
  93.        /*计算 hash 值*/   
    , P3 a; |! o* Y) z( d* I: ~
  94.        $hashStr = '';    $ Y4 y" o5 N4 y2 p8 }+ Y
  95.        foreach ($grayArray as $gray){   
    $ B1 {, U& u8 n7 A) @0 {
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    : s+ G0 ^1 i* w6 E" X
  97.        }   
    3 B1 `8 i5 L* p, }; C9 T
  98.    
    ( ]6 F/ q# m. O; D& I
  99.        return $hashStr;    4 T* E$ E6 Q% ]: d
  100.    }   
    & h3 a' |9 E! V+ Z
  101.    
    . c! P( E+ |4 n& p5 }  L
  102.    
    , B, ~, G( q" w/ F; Q
  103.    /**hash 图片文件   $ R! c% b% K% j8 s
  104.     * @param string $filePath 文件地址路径   
    ) o) u+ h2 S, g9 f$ k5 [
  105.     * @return string 图片 hash 值,失败则是 false   
    ( n1 F9 A9 m5 v
  106.     * */   
    / ]' Z7 W0 {3 o9 h* {$ t
  107.    public static function hashImageFile($filePath){   
    7 Z9 I4 j- V% V7 r
  108.        $src = self::createImage($filePath);   
    + V+ w2 h. `# V( b) W
  109.        $hashStr = self::hashImage($src);   
    + Z4 w4 s+ q" z& ?  T
  110.        imagedestroy($src);   
    & I2 u  ]7 N4 n# p8 u% r9 P
  111.     " z6 h9 O" ^! W3 k
  112.        return $hashStr;    7 z# T) J2 ^8 A( g& P, M% z2 D
  113.    }   
    & L' _4 U* F" G7 q) b
  114.     9 f! q. G( X% f
  115.     $ W+ u# f3 Q2 W( H  B( U
  116.    /**比较两个 hash 值,是不是相似   + y8 Y% D  Q2 ?+ t
  117.     * @param string $aHash A图片的 hash 值   " [0 I# G  k. q5 I7 B4 _
  118.     * @param string $bHash B图片的 hash 值   
    % U1 A& B8 z7 q5 j8 v- {# [1 m1 j% `
  119.     * @return bool 当图片相似则传递 true,否则是 false   ) i) N; x% e5 \4 R
  120.     * */    8 x- _  W$ }, F9 ?, S" D; a9 d
  121.    public static function isHashSimilar($aHash, $bHash){    9 |2 ?' [  d) k! R$ G, F
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    4 o! J" Z5 w$ C* J& C' O! j
  123.        if ($aL !== $bL){ return false; }    2 M! \4 z1 j7 H+ f
  124.     ! ^5 {4 T. M" P! i9 K
  125.        /*计算容许落差的数量*/    3 C  J/ J2 O" K+ F- D0 e
  126.        $allowGap = $aL*(100-self::$similarity)/100;    / m1 w- [! V4 K4 t: J
  127.     ! u7 J" V$ m9 y; @: x. q* i
  128.        /*计算两个 hash 值的汉明距离*/   
    & q1 d. W  ^" R$ L6 O+ `
  129.        $distance = 0;   
    4 s. R6 w  T# e3 i- c+ |/ J0 H
  130.        for($i=0; $i<$aL; $i++){   
    8 S+ I5 r% o( Q, |/ X
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    7 q  s" e. C* Q6 v( O& T
  132.        }    ( F) n. y0 y/ \$ ~$ V. A
  133.     ' m  t3 H! J% n3 S: T5 `3 e& U( ^
  134.        return ($distance<=$allowGap) ? true : false;   
    $ k' @; P; u# M# M" M2 z. \. h
  135.    }    * d9 x! v0 A0 p' x3 v! a, ~
  136.     " t  w. Q) H1 U% w  m( x4 o8 J/ I
  137.     4 ~* |1 O* ?) {- w" i/ x, F
  138.    /**比较两个图片文件,是不是相似   ( P" A( g: H3 @0 \( C& t8 w
  139.     * @param string $aHash A图片的路径   
    8 U9 t3 e  d4 B  t2 z- L
  140.     * @param string $bHash B图片的路径   ' q6 W) Q! h$ `0 U4 N5 d
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    # E1 X/ K/ j6 N8 K. d
  142.     * */   
    3 [9 I$ j% A8 E
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ' P. t! W6 f" `
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    6 e# c- c% J5 q
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    0 Q; e. b2 {) `) E3 T
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    * l$ k2 ?5 A* d1 u+ J# z
  147.    }   
      s9 u# ^! S" {& U
  148.    
      S6 j: H$ E0 Y- E# ]
  149. }
    , [4 q/ P) @! V5 g- c) ~
复制代码
( ~( D. _$ v/ T( E4 a

: W) `( f: r/ Z9 g7 M" n' r
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-6-18 07:14 , Processed in 0.134339 second(s), 19 queries .

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