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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

# Y. e$ a  n" L) w
# y; K& x4 Q* K2 Y6 k
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

6 ~1 b) c! e- x. i
  1. <?php   
    1 y$ J) _4 t- v
  2. /**   , g* [# J2 J6 J9 l: S7 p: A5 T
  3. * 图片相似度比较   1 u1 m. b" e7 `' a) @6 w' F  A
  4. *   8 k9 k/ Y0 v" x0 m# P/ E
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    - D+ Z7 ^, B: M3 C
  6. * @author      jax.hu   
    / ~  g% Q3 y0 U9 t, O* m& v% T
  7. *   1 b- y; Z/ F' t- g# x2 t) h5 K
  8. * <code>   8 n) J6 P7 R/ |0 I' L. q4 _
  9. *  //Sample_1   : M: g4 l4 V! \+ M- V0 }6 P* Q
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    & H' \. W. M- x9 m3 g# I( Z
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   7 j; m; t: ]3 F8 w/ y
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    # m# b$ y1 P9 z; S* @! P6 e- \1 g$ B8 d
  13. *   3 K6 s: t0 H/ E& a1 V* B0 \8 }& ]
  14. *  //Sample_2   
    . F. ]- O3 N* F! l, m2 a/ I1 T3 p& C
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ) T: [  ?4 [+ K0 m. W
  16. * </code>   
    9 _9 z0 Q3 z# b" u
  17. */    , f1 e, y3 ?+ s2 y, H7 d
  18.    
    7 B% Y* r3 r; b9 @; T; r# l( X
  19. class ImageHash {    7 O) x+ k! E! a9 W6 a# m1 A  g
  20.    
    & N$ [$ A  Y0 I' F# a' u
  21.    /**取样倍率 1~10   
    5 [# v9 U& N: e( t
  22.     * @access public   
    ; J. N) S/ o* m/ j
  23.     * @staticvar int   , r* H" b# z0 F. ~
  24.     * */    9 e% c% X. ?) w4 U" @6 a. [1 n
  25.    public static $rate = 2;    8 x- C1 Z" a: q+ e! F
  26.       u" E0 `* C& \8 F* j1 K. }
  27.    /**相似度允许值 0~64   
    % }, @6 F. O3 H7 Q, X$ s
  28.     * @access public   
      ?) l# O6 E+ E( i, x/ ^) ~
  29.     * @staticvar int   ( Z, H1 \7 J* k& i
  30.     * */   
    - r' x3 g0 E- y! A( f  X  U4 c
  31.    public static $similarity = 80;   
    9 Q0 I6 V6 r( H
  32.    
    " b, U) H" N  r% z
  33.    /**图片类型对应的开启函数   
    " X# Z, P: z/ a
  34.     * @access private   + [/ ?) E: n' ~* k' h0 d
  35.     * @staticvar string   
    2 S! S: ], y$ W
  36.     * */   
    ; z3 P9 V( q2 J: v( A0 R7 P. q
  37.    private static $_createFunc = array(    ) J5 `' q  s2 c) V& W+ A
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    3 F" j2 e, E* Q" `& O( u! s6 X. N5 u
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    + b! a$ c$ P# {. L* F- _& x
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ' h# [! i  B0 w# D3 y
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    9 j/ n8 W, d# {1 g. B
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    7 O  s+ N0 T9 c- ^
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    2 t" |) {6 v7 `# P+ V/ I" [
  44.    );    1 b- b* ~( @8 F; H- w' m+ r  V+ Y4 J, }
  45.     5 \' v% q$ S& {. y
  46.     9 C5 H) _2 m% o4 t& j
  47.    /**从文件建立图片   
    ( t2 {  U) x3 z: K6 Y& _3 _% x
  48.     * @param string $filePath 文件地址路径   
    ) @8 n+ q8 u9 j& z* r
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    8 d9 Q2 g) @2 _" s3 z- E0 Q; @8 ]
  50.     * */    7 c% J, ~4 A" l+ V$ f5 t- _7 L2 f3 d
  51.    public static function createImage($filePath){   
    8 ~) j9 H- p' T" T7 O, W& d/ \
  52.        if(!file_exists($filePath)){ return false; }    ) D' Y5 o+ p; ?: {
  53.    
    6 C+ f! i, d  v. J5 J
  54.        /*判断文件类型是否可以开启*/   
    & g+ K8 d2 }; `4 f% e2 r
  55.        $type = exif_imagetype($filePath);   
    7 x+ y; l, I$ _! }7 I
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ! ~3 u- k) ]8 Q# s7 L/ D
  57.     % w3 d3 e1 _5 e. {" {0 E1 o1 U
  58.        $func = self::$_createFunc[$type];   
    ; S9 `4 {! [" u" k; Y% _0 J
  59.        if(!function_exists($func)){ return false; }    . Y- ^* j9 E) D% Q
  60.     ) h% d" n7 u& s0 y' n3 A# y1 h; k
  61.        return $func($filePath);   
    8 \* N% \, G6 m8 |% k; J
  62.    }   
    6 `  D+ R0 Z, V. B/ E
  63.    
    - M3 z5 l; Z. C# x
  64.    
    7 ~8 z' `  S4 S' C6 O; V
  65.    /**hash 图片   + _( @5 a! [% X5 h' Z  {
  66.     * @param resource $src 图片 resource ID   
    ( N) G% l6 Z. W/ m2 l# a" u8 @
  67.     * @return string 图片 hash 值,失败则是 false   
    ! K+ [: ]8 l4 o6 {
  68.     * */    - ?( v+ Z% E, a( U, R
  69.    public static function hashImage($src){    - g8 M, a+ p# R  i
  70.        if(!$src){ return false; }   
    0 e) }7 @9 F! ?) `: i+ `
  71.    
    8 u) F% E0 e; ?" v% D. \+ A
  72.        /*缩小图片尺寸*/   
    , z8 @% Q% j! W" v0 g2 @( ]! s! r
  73.        $delta = 8 * self::$rate;    $ m5 F/ i2 |4 x9 _; ^
  74.        $img = imageCreateTrueColor($delta,$delta);    2 L8 X! O. R! c5 e
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    6 K8 [" v  `3 p$ X3 v( d
  76.     9 C8 s, e( ^5 _4 J$ Y
  77.        /*计算图片灰阶值*/   
    4 \+ r6 ^9 J: R$ a( z+ `
  78.        $grayArray = array();    4 v$ U% c1 _6 V: ~2 R
  79.        for ($y=0; $y<$delta; $y++){    5 x) ~0 _9 g$ |: S! Y* ^# B, p, E+ Y
  80.            for ($x=0; $x<$delta; $x++){   
      z* o- K6 s- v2 h/ }
  81.                $rgb = imagecolorat($img,$x,$y);    ( W' p0 f( s$ J* |; x0 B
  82.                $col = imagecolorsforindex($img, $rgb);   
    4 G8 O" L) j& S
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ! T6 Z5 K. }$ V, M5 }: D
  84.     , }6 Y8 C0 g9 z& N  E6 ?- X
  85.                $grayArray[] = $gray;   
    % J/ R: }( W8 _' X4 D2 Z4 b
  86.            }   
    ; ~+ w; m6 I& s- t& ^9 t$ s
  87.        }    & e) U$ o0 b7 Q" N2 L' ^" [
  88.        imagedestroy($img);    ( n6 S0 m, O% K  a; h
  89.     , I& m" n9 H/ p( i: q
  90.        /*计算所有像素的灰阶平均值*/   
    + H( m. `9 Z4 |9 L9 Z4 s8 L
  91.        $average = array_sum($grayArray)/count($grayArray);    4 {! x& N& q' x
  92.     ; I+ R# o8 B, g
  93.        /*计算 hash 值*/    7 Z3 L4 l" ]/ p  x0 ~" ?
  94.        $hashStr = '';    ' m" `8 k9 N# C) ~$ K( b0 I$ i
  95.        foreach ($grayArray as $gray){   
    ; Z0 j2 X" X: \0 q& H: [; b
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    + b; l1 j  q' K. q$ N# w" R
  97.        }   
    1 h0 v5 z* P, g
  98.    
    $ z& N/ N* b4 {; i" H
  99.        return $hashStr;   
    , D4 w7 W, A+ M; @  y4 o
  100.    }    $ `% F2 R5 s* P$ ?2 x
  101.    
    9 p% l) G# G) C5 B# C
  102.     , o' G! g  i! \% [+ K
  103.    /**hash 图片文件   + q. h7 q  v2 U; @! A' D$ V
  104.     * @param string $filePath 文件地址路径   
    , e+ O0 m9 `% @* x( J* _! W$ K5 T
  105.     * @return string 图片 hash 值,失败则是 false   
    - p# [, Q5 Y% b8 l
  106.     * */    6 C) F% |" o, B7 n% L
  107.    public static function hashImageFile($filePath){   
    / u2 l3 k5 J6 ^% f5 i& R/ T
  108.        $src = self::createImage($filePath);    4 E+ E7 R; I2 Z( R9 q* k. x
  109.        $hashStr = self::hashImage($src);   
    5 @2 C0 r4 Q% q4 `& B
  110.        imagedestroy($src);    . L) j% K! ?, S7 F& Q- X
  111.    
    ( W! F5 E! J  K3 Z. `, v" d! m
  112.        return $hashStr;    * j$ k6 d' r$ i$ n" l
  113.    }    2 d, n/ P7 D9 x. p2 d
  114.    
    ( u/ H8 E9 U! w! Z
  115.     + R( W$ C. t. O" e7 p
  116.    /**比较两个 hash 值,是不是相似   
    ! A# P. X6 S, T% |2 N
  117.     * @param string $aHash A图片的 hash 值   1 K: E1 r/ D4 b- \
  118.     * @param string $bHash B图片的 hash 值   
    & q* {  k# [' Z. e7 x' P/ O$ L- f  }
  119.     * @return bool 当图片相似则传递 true,否则是 false   5 I+ T2 ]2 ~! u! s
  120.     * */   
    # K$ F* n( a0 @$ F2 j, U+ B! T
  121.    public static function isHashSimilar($aHash, $bHash){   
    ' e' ]: O1 p  ~6 x* H0 Y
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    0 ?5 ~) E) e& q  A5 X" K: P
  123.        if ($aL !== $bL){ return false; }    2 ?7 R3 t" G; h: d4 |4 _' j
  124.    
    , m" r: l: b/ r+ B  T
  125.        /*计算容许落差的数量*/    & B+ D, h/ n0 T7 v9 }; s
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
      U+ ^  P$ k/ {4 `/ c! h" u- X
  127.    
    / C" O1 d- Q" H) e& L
  128.        /*计算两个 hash 值的汉明距离*/   
    ) y4 x! i+ B$ z1 V
  129.        $distance = 0;   
    ! B+ i0 l% C8 o  i; I
  130.        for($i=0; $i<$aL; $i++){      s! N* c, {: p; z1 X0 ~$ U
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    " C( K2 A& F/ P# n
  132.        }    5 e4 i, L# H* M! E+ M8 e6 O
  133.    
    ( {# @, \, b2 v2 |
  134.        return ($distance<=$allowGap) ? true : false;   
    , e: R& s9 Q5 c+ ?% w9 G& ~
  135.    }    $ W* m, Z  F' f  e5 |7 o2 v% A6 C
  136.     : e6 X7 P" r- N* e# P) L
  137.     # q! P( K6 X) n/ Z0 u2 M, c4 }
  138.    /**比较两个图片文件,是不是相似   
    . }. L" ]2 d- ?+ u( f
  139.     * @param string $aHash A图片的路径   ' P" C2 T* M7 F% P- m1 i" C
  140.     * @param string $bHash B图片的路径   
    7 p2 X0 E. j9 h8 s3 o
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    " i- u. ]; n. X3 W" W$ z' p' ^
  142.     * */   
    # F) ]$ I7 f/ K- j6 ?
  143.    public static function isImageFileSimilar($aPath, $bPath){    4 j8 f- E. E$ c9 B% g3 }
  144.        $aHash = ImageHash::hashImageFile($aPath);    ( I9 P  A1 L) z, k
  145.        $bHash = ImageHash::hashImageFile($bPath);    % B$ c, R1 N7 X7 B7 v+ g
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    6 }% b& q5 g6 V4 z3 y9 \
  147.    }   
    9 X8 p; R  g% w" V5 P! P; ?+ @- k
  148.    
    , T( [0 F, u1 j, k
  149. }/ d5 z. I: A8 p% s, q
复制代码

, C" {- Z: Q8 ?3 o+ A
2 V& A' c  y4 |) r
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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