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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

$ C2 r; a7 N' v1 s

/ C5 P% q8 E. ~- E# ^8 J, _由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

" X& W: u7 G! ]" r! F
  1. <?php    3 h# \( ^7 U# j
  2. /**   
    7 E; N! U: a7 P
  3. * 图片相似度比较   
    # j6 \# ?6 y- ]* P. _( a
  4. *   . U) p' O7 Q' @
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  : e9 i5 c& _* l
  6. * @author      jax.hu   
    ; K* R% u- {' L& S5 }
  7. *   
      m' G/ H- U( |6 s5 f5 @
  8. * <code>   
    ! c; ^  o4 t6 _4 U( J+ ~4 T- T) [
  9. *  //Sample_1   - u' K# i+ M2 Y
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   0 B/ l3 k; C4 v7 d( V& w, L5 R  r
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    # O# q7 h4 c; y6 Z  s* o0 z, Z
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    4 [9 T/ O; @3 [
  13. *   3 ~9 O+ E. ^& e( b" i( c0 `
  14. *  //Sample_2   ! k* _$ L0 L0 X5 i1 i$ u  [
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    " m, P# {+ r5 N, V4 }3 ]
  16. * </code>   
    ; L2 {. J( Q# m8 T# J. A5 }
  17. */   
    7 j( _. {* r0 b% ~, V9 F9 z$ r0 k: d
  18.     . @- Z( J3 S6 R  E
  19. class ImageHash {    5 s5 V! ^" ^+ g! j
  20.    
    ! |; q1 X- c7 m3 D. N
  21.    /**取样倍率 1~10   
    " b; q/ z) N1 F$ _# S8 Y, J* }
  22.     * @access public   
    " I7 [- _1 e7 [& P- _1 S# V; a
  23.     * @staticvar int   
    ' r7 H3 T- d1 U+ |
  24.     * */    . B% ~2 T1 ~/ H" g; H
  25.    public static $rate = 2;   
    . o2 F6 `; W% x8 x7 a' W9 Q) ^# m
  26.    
    3 i/ Y2 i& ?! S' a( {3 P, G
  27.    /**相似度允许值 0~64   8 ?" l& {4 A" s; Q
  28.     * @access public   
    5 I% P& m0 a+ W) [0 Y4 r
  29.     * @staticvar int   % i1 ]# t6 M2 a" R' Q0 N' t
  30.     * */   
    * h8 n# N# b: V
  31.    public static $similarity = 80;   
    7 ^" [; Z* L9 ]. \
  32.     - }9 z9 @! u9 U
  33.    /**图片类型对应的开启函数     u  E9 s. i$ Y6 _
  34.     * @access private   ) F5 s! H" H" z% u" w8 F6 Q! U- l
  35.     * @staticvar string   
    " W; D5 q+ k. U! y7 y/ B# X! B# P9 U- W
  36.     * */   
    2 r& q; x/ B+ x4 p$ V
  37.    private static $_createFunc = array(   
      L9 `0 J- J/ A, t3 Y
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    1 }* r2 W0 B7 R$ n9 m7 F
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    # F' m7 t+ h; L. k7 l6 g  e0 \
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    & O3 Y' D2 M2 Z* x
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    * I4 ?! M' s7 ~; O% V7 c+ k% U
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    $ x. ?5 N/ Z, x/ \0 A0 ?
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ) Y$ q' X% L8 S3 ?) J+ e
  44.    );    - n, R% P+ q$ @) m1 b: P% g9 G  u
  45.     / b& B: @+ h$ j$ c4 v2 _7 e: l9 }6 V
  46.    
    4 y; Q( Z, R3 I$ V+ a; e
  47.    /**从文件建立图片     w1 r' k; V$ g( _# d! n! u6 l+ U* m
  48.     * @param string $filePath 文件地址路径   , Z. k1 @/ n- a, Q. o
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    3 z" k: L  H+ g1 ^$ z
  50.     * */    ; }: d& A- M7 V9 H0 s" v1 W
  51.    public static function createImage($filePath){    $ q; H; y2 L# @+ K) S
  52.        if(!file_exists($filePath)){ return false; }   
      S) Q* V5 N  F! W$ |
  53.    
      f" e) T! h7 N9 Z$ W) P! L
  54.        /*判断文件类型是否可以开启*/    / L, F+ |: G8 s: c) f& T
  55.        $type = exif_imagetype($filePath);    : {7 f7 e  ?8 c- ^4 S
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    - N7 h1 Z$ C& n/ V& V7 P. d5 f
  57.    
    - o. L1 L  x! U. x. o0 P. T
  58.        $func = self::$_createFunc[$type];   
    ' \$ }5 a$ ?% G7 S
  59.        if(!function_exists($func)){ return false; }    ) B9 ?! Q6 I; Z: T! J+ O
  60.     ; X' U7 \: [  H0 L7 \# Q  n& u1 J- s
  61.        return $func($filePath);   
    5 ~# K- g+ z. ~1 Q- t- Y
  62.    }   
    7 v4 A* U0 g+ U
  63.     * ^+ u9 y$ Z' O3 o: U( E2 ]
  64.     & n( a, w8 a% N$ ^. R
  65.    /**hash 图片     Q: x4 M9 l& o  `0 Z
  66.     * @param resource $src 图片 resource ID   ) `* u( B9 g  c; c/ R6 Z* V; H
  67.     * @return string 图片 hash 值,失败则是 false   
    " a4 @6 T8 d# E6 v
  68.     * */    5 K; T! D- e- o% v( @+ s  Q
  69.    public static function hashImage($src){    7 @9 ]% n& N. b7 K+ d
  70.        if(!$src){ return false; }    ) X+ a0 N  a' X- O" x2 u- Q5 V
  71.    
    $ {0 o- r# Z7 n
  72.        /*缩小图片尺寸*/   
    $ G$ X$ e' N5 U# r9 ]% \
  73.        $delta = 8 * self::$rate;    $ H. h9 l  F/ q7 s  v. ^' [/ X
  74.        $img = imageCreateTrueColor($delta,$delta);    $ m& c  d: z7 k8 I5 B
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    6 b: ^1 U* n0 V3 @- A
  76.     3 T4 T3 d, S2 H+ G7 Y' C
  77.        /*计算图片灰阶值*/    7 @+ z+ ~2 h% I- K
  78.        $grayArray = array();   
    ! t7 v; Q* e2 b8 N8 G. O. z
  79.        for ($y=0; $y<$delta; $y++){   
    , m& {- R4 T- `" g: T
  80.            for ($x=0; $x<$delta; $x++){   
    : {5 e0 _6 _4 K5 |4 N& I$ e
  81.                $rgb = imagecolorat($img,$x,$y);    3 q* [  m( |2 Z3 ]; p
  82.                $col = imagecolorsforindex($img, $rgb);    5 P8 F5 P, i7 z5 p
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    9 Z: {' b5 R. {- g3 a
  84.     & \  k. \+ o. m$ B8 S
  85.                $grayArray[] = $gray;    1 a6 ?8 m; Q5 p  B! M
  86.            }   
    8 N, A" T/ w! E, n. b* C' P% C
  87.        }    7 |1 U/ ^& \) L' d" B+ |
  88.        imagedestroy($img);   
      J1 y2 E/ T' @7 e* ^1 y3 {
  89.     0 S& E: f* i% S) t5 {$ U8 S
  90.        /*计算所有像素的灰阶平均值*/   
    . Q: M( y& k, G3 R; g, D; x
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ' m/ T" }4 Q$ V( {
  92.    
    8 B' _9 F" `/ e. v
  93.        /*计算 hash 值*/   
    , o3 u, q# E7 O( {, f
  94.        $hashStr = '';    " p' D# v" [- {' W
  95.        foreach ($grayArray as $gray){   
    - a7 l! k/ f3 n0 M' N
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ( L% |2 H6 @% l; L5 N! m
  97.        }    ! h% n; @& x' \% k# r/ f
  98.    
    ) j+ w! u3 w$ A* _" z2 k0 _
  99.        return $hashStr;   
    & b4 K2 i  @# {0 A5 c8 l+ Y. ?3 q3 r$ z, @
  100.    }   
    + L# W, S6 q1 S
  101.    
    7 @$ h% s! q9 I, C: i
  102.     . {; l$ v, q) w) [" B$ Y
  103.    /**hash 图片文件   
    ; i; O7 d7 x  b5 U$ U3 s
  104.     * @param string $filePath 文件地址路径   ; G, @* M: z+ H0 s# b& c/ N0 O
  105.     * @return string 图片 hash 值,失败则是 false   
      k+ w% o- j& B- P6 Q
  106.     * */    . e- v2 Q8 u9 t
  107.    public static function hashImageFile($filePath){    ' ?3 H3 W8 J. c+ O9 j5 ?- T$ a
  108.        $src = self::createImage($filePath);   
    . Z3 b9 h. x" A' k' {; H
  109.        $hashStr = self::hashImage($src);    8 [; E. F7 T* M
  110.        imagedestroy($src);    , ?- K8 m  C2 u% m, J" B  {
  111.     0 I; E; m' O, U8 H
  112.        return $hashStr;    ( X" Y' N7 M5 a$ ^. {. }
  113.    }      C' k- _7 A% ^! f: j
  114.     ( w/ f4 b3 j5 l" Z2 i+ e, ~0 g
  115.     , U: R, N& j& g, G
  116.    /**比较两个 hash 值,是不是相似   / J: d: B- `0 S0 A' Q
  117.     * @param string $aHash A图片的 hash 值   . N; g% w0 t# L  P8 ~
  118.     * @param string $bHash B图片的 hash 值   - U% j" ?) v' e$ c, C
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    5 \( _, O/ d  i$ |7 \+ N$ ]* m
  120.     * */   
    ) K+ l- G6 P1 d1 j' G
  121.    public static function isHashSimilar($aHash, $bHash){    & g; |" @: R# X; n5 L
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    1 D( j: C7 ]3 I) l" B/ |
  123.        if ($aL !== $bL){ return false; }    4 Q* J: y, j& v2 V
  124.    
    7 ^" m' g0 v: y* @
  125.        /*计算容许落差的数量*/   
    % q2 V  T3 [, P
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ; @" t( ^' Y9 w, J6 ]2 n
  127.    
    ; A+ @9 }% a( G  D
  128.        /*计算两个 hash 值的汉明距离*/    & x9 G9 S% H& K" [
  129.        $distance = 0;   
    " I+ J& N2 _& t7 X
  130.        for($i=0; $i<$aL; $i++){   
    3 L2 w/ c. j3 h  N7 k
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    & J$ S/ _$ @9 s: J; K
  132.        }   
    $ s& L' o3 o4 e$ j
  133.    
    $ n, v2 _) r+ e$ M) T. H
  134.        return ($distance<=$allowGap) ? true : false;    * Z' S( G! I& j( }
  135.    }    ( Z6 N+ a2 a2 g5 N. p% v
  136.     + @  H* K: M% X. p9 Q/ ^7 K+ u
  137.     7 N9 H! l+ W5 ?; p
  138.    /**比较两个图片文件,是不是相似   
    # w! \! e% D# G1 ~
  139.     * @param string $aHash A图片的路径   
    - K# W1 q' E( W& s% _! \
  140.     * @param string $bHash B图片的路径   6 ]" W# R8 }& t: `
  141.     * @return bool 当图片相似则传递 true,否则是 false   " C2 s1 k  Z7 S
  142.     * */   
    % E' M- B' X8 C* m% n' n
  143.    public static function isImageFileSimilar($aPath, $bPath){    5 G5 b6 l9 O& ?% b  H1 q- `
  144.        $aHash = ImageHash::hashImageFile($aPath);    / T  \9 q+ w6 p. ?3 h1 m
  145.        $bHash = ImageHash::hashImageFile($bPath);    + _% c, z! K: G( h. J# _+ s
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    - ^8 q0 K+ W1 ~& g9 R8 w% ]4 v
  147.    }    * B! G: r  N* {: J5 h0 y% V8 \; _
  148.    
    5 _7 B) z9 q# b" c( m4 s3 S& s
  149. }
    - L) N) M5 H) }3 V+ D5 N7 t# t1 w
复制代码
: v& j# k  g3 v# L! P
2 z. \! E, \3 K: j9 x6 s7 I  s; ?0 q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 01:09 , Processed in 0.115894 second(s), 19 queries .

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