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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

3 @% G% w' o- {8 M; @) R5 [+ B

1 t3 Y* X9 c5 ]2 h" O* D' s) {- k' Z0 y由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
! ~$ b! B, \* ]7 P4 I
  1. <?php   
    ; ^, U* p! J6 F6 V6 p; L+ ~
  2. /**   8 B* E7 ^7 C6 j& {0 H+ S3 V
  3. * 图片相似度比较   6 q: l% w+ e& A! ?
  4. *   
    . P* [7 T' n: d+ A* _9 Y; L
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  % [5 H9 G; h1 Z: s
  6. * @author      jax.hu   
    4 ]3 c. u5 T1 ?  L& F% V
  7. *   : T" w3 ~3 n" b! _: Q+ m
  8. * <code>   
    * ~# ?: A: Z! {+ n, }
  9. *  //Sample_1   
    7 p" O8 f% ~+ G/ V( R
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   / m' h6 x5 `2 s- f5 Q, K0 i
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    " `0 {, t6 }/ z) {0 X: [
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    % t% n( b# s2 ]+ q& H7 r4 Q  o
  13. *   , w( j- h$ F" z1 u. e3 G& j
  14. *  //Sample_2   
    " W( ]. W, ^" l8 V
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   5 s2 f) [' |1 N. i) R
  16. * </code>   2 F/ B# s7 n: {; ^1 Q& X2 _& ]
  17. */   
    2 G/ H) n: a0 H
  18.     3 r" V/ f% `8 W6 ^1 C: u1 v
  19. class ImageHash {    3 x* f* X7 j8 R. u
  20.    
    , V8 N( g" d; U. c' y/ u% b
  21.    /**取样倍率 1~10   1 T' F. H4 f: D; U# _
  22.     * @access public   
    + Z2 G" L+ V2 @: f
  23.     * @staticvar int   4 d/ j* a6 l6 y4 c) s
  24.     * */    - T9 q- @' _! I3 l3 a7 e
  25.    public static $rate = 2;    7 p& ?& d* m4 t, V3 f. i1 A
  26.    
    9 b3 H7 G: y- N2 \3 o
  27.    /**相似度允许值 0~64   
    * d) M5 b, U; Q& N1 o/ Y
  28.     * @access public   ; ~* P8 k  L5 N! \# T8 z: ?
  29.     * @staticvar int   " U! O( n# a$ `) Z. L
  30.     * */    4 @* B0 [* K7 {3 r# F# D
  31.    public static $similarity = 80;      x" y; E& ^0 |3 k6 l2 `& t
  32.     * u' C+ ]. D1 ]& F2 Z
  33.    /**图片类型对应的开启函数   * h1 |# ?. ]) b7 \: F
  34.     * @access private   7 y  i) T; T. D2 u6 L# J7 x
  35.     * @staticvar string     X- D; w' ~$ x) \* M$ b7 n* M+ J& m
  36.     * */   
    ; Q2 ]! V1 j) Y3 g0 Y
  37.    private static $_createFunc = array(    4 W# i8 q7 p) O: w6 A; N
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    " M7 T: W  e/ M* \
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    3 f) C. u1 j2 i9 p  m% D3 k
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    / g* {  I+ G; R4 l7 P
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ( w" D2 P, C$ ^
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    * M; {+ i% K! W% q6 G9 B' u& [( X
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    # a4 L9 H3 O/ [5 p$ B* h( V
  44.    );    + n7 H6 `  o: t
  45.    
    1 b* O5 K% j: ?; a( r9 K, K
  46.     1 d! \( [  K$ q1 S
  47.    /**从文件建立图片   
    ! ]2 w, x# ~7 k" a, F
  48.     * @param string $filePath 文件地址路径   2 I; @4 }  V; Z5 U; O/ u' Y
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    / W) i- J3 y7 x, f4 Q( u
  50.     * */   
    : Z! v: R* B! X. i- {( g8 D/ ]
  51.    public static function createImage($filePath){   
    3 q* k& ~5 e$ |( F) ~" c! c
  52.        if(!file_exists($filePath)){ return false; }    - _6 Q3 j& U' r: H8 V7 d; R: X
  53.    
    * \9 [8 C' g2 E, x: |# ~8 G  }! E
  54.        /*判断文件类型是否可以开启*/    : M+ W7 p7 q( j, P) Q
  55.        $type = exif_imagetype($filePath);   
    6 j; p# G& v) X; w& J, J
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    5 F5 `% I2 e8 s( C5 B
  57.     $ L  U  F+ _3 [  ]/ I0 T
  58.        $func = self::$_createFunc[$type];    . G" n. a! i5 {9 A& x  \
  59.        if(!function_exists($func)){ return false; }    # I* @5 ^# j( Q7 T; q/ t
  60.    
    % p  E- k1 K6 E. |/ \
  61.        return $func($filePath);    9 d: ^1 @$ r( z4 x. ^# x
  62.    }   
    1 u" D7 J$ t1 X( W* p& ?2 i
  63.    
    3 f1 q' H: t  e
  64.     , g% Q8 @& s! J( Q
  65.    /**hash 图片   
    8 w7 }1 ~* a5 t/ D! i
  66.     * @param resource $src 图片 resource ID   
    + M( |+ d6 t* }7 M/ d
  67.     * @return string 图片 hash 值,失败则是 false   2 Y0 q; F% U" T( `6 i  n5 P  M
  68.     * */    1 u5 K+ F9 p9 O5 m
  69.    public static function hashImage($src){    - z2 D  v' _4 X/ U" k  T
  70.        if(!$src){ return false; }    8 g: g& i) z4 k! n
  71.     2 F/ o8 z% ?- P8 u
  72.        /*缩小图片尺寸*/   
    8 D$ c9 R% e8 E5 `" I9 a
  73.        $delta = 8 * self::$rate;    ( p" s$ S& ?1 s% G$ D( L, l
  74.        $img = imageCreateTrueColor($delta,$delta);   
    ' P8 n" t2 v: s6 r& q
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ( J0 x  V" U0 T# N! N! t% V
  76.     6 k% Q0 e( c2 I; b' M* Q$ X
  77.        /*计算图片灰阶值*/    % g" y% \3 D( |% {
  78.        $grayArray = array();    : N; e& A8 s: R$ x/ b, A) b1 B
  79.        for ($y=0; $y<$delta; $y++){    * x: q" H. o7 k! Y% ^
  80.            for ($x=0; $x<$delta; $x++){   
    ! ^7 x5 u- g3 Z# y  s# W! ^
  81.                $rgb = imagecolorat($img,$x,$y);   
    ) j8 X" R, I2 E8 h
  82.                $col = imagecolorsforindex($img, $rgb);   
    ) ^  Q5 a0 J$ t8 S& e
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    9 }: X8 i/ w$ @$ q& c9 \
  84.    
    # Q0 F1 s( ~0 r4 d+ K. W4 }6 v
  85.                $grayArray[] = $gray;    4 `4 E+ ?7 L1 `( A/ y3 V+ j2 V2 c
  86.            }   
    / ^+ T. W1 P  S/ [
  87.        }   
    6 g; Y" B& J; d# K& Y' O+ G# a
  88.        imagedestroy($img);   
    ; q2 F& X8 m8 A: N
  89.    
    " S* `& ~" g0 ]; h
  90.        /*计算所有像素的灰阶平均值*/    * w3 u- J/ h/ A- r
  91.        $average = array_sum($grayArray)/count($grayArray);   
    + i$ _* y" j; }. w. C1 ?! e
  92.     $ {1 C$ k) F* A( ?" u  W
  93.        /*计算 hash 值*/    2 @' i* X" B' G- ?, Q: Y
  94.        $hashStr = '';   
    1 f/ d" N( X8 w8 c4 }' b* a' L! W( B' P
  95.        foreach ($grayArray as $gray){    - y- U) `; @4 t2 P& Q2 _$ ^+ p2 v
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    + p& \0 I) w' W! a- R8 f+ N
  97.        }   
    $ F% f# {5 r" F5 L: L
  98.     1 t& ~/ v, a: H) ?# N2 M' M
  99.        return $hashStr;    " |4 g% y% Y9 R' [2 P2 R, E
  100.    }      \" F, x) k2 r, k
  101.     # Q( J- T7 N/ x1 A
  102.    
    6 c8 e. h! q  n1 X
  103.    /**hash 图片文件   
    2 ^( S! \4 S5 H& z& V
  104.     * @param string $filePath 文件地址路径   2 b$ ]9 U7 r+ L. j2 {+ e
  105.     * @return string 图片 hash 值,失败则是 false   4 X  `' m2 g2 q5 R3 |( k
  106.     * */   
    + r# L4 _/ z! Z& p- S; k$ X
  107.    public static function hashImageFile($filePath){   
    1 @# R0 T0 x& O$ _
  108.        $src = self::createImage($filePath);    5 L* y/ N% H9 R; W7 o5 {6 v
  109.        $hashStr = self::hashImage($src);   
    $ Y$ N7 [( B. j: {
  110.        imagedestroy($src);    5 ]5 Y3 V5 w! S
  111.     3 N8 U; k  G% [: `6 I0 l
  112.        return $hashStr;    + v( ~' x( b% E0 S" j, a: v! l* s
  113.    }    " A; A% h( v9 ]; {; D2 X9 [
  114.    
    . _( r5 H) w6 ?
  115.       S- S; \6 d- z4 r) X; I
  116.    /**比较两个 hash 值,是不是相似   - x+ t3 L. j) v
  117.     * @param string $aHash A图片的 hash 值   
      N; s7 }, r, x: i* q
  118.     * @param string $bHash B图片的 hash 值   ; w' O  u1 z- e6 ]& }
  119.     * @return bool 当图片相似则传递 true,否则是 false   6 j. F7 M/ h- ^& ?! y
  120.     * */   
    6 E5 {* ?) O8 b% h
  121.    public static function isHashSimilar($aHash, $bHash){   
    % p3 R( E! p: R
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    3 a2 O4 T2 `6 l
  123.        if ($aL !== $bL){ return false; }   
    ! _+ X- e( z# X7 @* O' c
  124.     7 F0 Q: D8 f: V, c# j! L6 z
  125.        /*计算容许落差的数量*/    - Z: b- v) a1 @  k
  126.        $allowGap = $aL*(100-self::$similarity)/100;    ) @4 T' U: Q! H& W2 N) X$ y7 S
  127.    
    7 B9 c; b% E- ]0 R. o
  128.        /*计算两个 hash 值的汉明距离*/      Q' a$ }4 @  {+ R, L
  129.        $distance = 0;   
    ( @) t3 P, j4 O. w5 m  U- H2 a# j
  130.        for($i=0; $i<$aL; $i++){   
    9 d/ M+ ?$ S7 b: H( L5 @/ |+ V; P
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    . J+ ?8 e' m' v" \% \. Z/ M- ]
  132.        }    ' C; E8 {( R2 @3 \) X7 `$ X6 g) B' O% A
  133.    
    % g  T) S" }3 S7 j" n  P
  134.        return ($distance<=$allowGap) ? true : false;   
    ! k* H- b: O" T; n
  135.    }   
    * J7 L8 D0 e" f# r! f4 f% I
  136.    
    - s. R, W( n" l8 S. _9 K8 K1 m
  137.     # |/ d& S* D, A6 x+ K; A, b
  138.    /**比较两个图片文件,是不是相似   
    ) C3 i& g- a1 _7 r# b
  139.     * @param string $aHash A图片的路径   / F; R4 i- ?- W* w4 }
  140.     * @param string $bHash B图片的路径   
    7 q4 p) \( V0 f' N
  141.     * @return bool 当图片相似则传递 true,否则是 false   " M) U0 U6 x3 X: w9 ^
  142.     * */   
    & d. T; ]9 G5 G2 A9 g. g
  143.    public static function isImageFileSimilar($aPath, $bPath){    # W4 \9 i" q$ e% a
  144.        $aHash = ImageHash::hashImageFile($aPath);    * z& }; P- ~! j0 M: @
  145.        $bHash = ImageHash::hashImageFile($bPath);    0 z1 M& H& B( L4 D, y1 `  p3 c
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    ! j' W  e/ J4 R2 P
  147.    }      V( ~4 P. I8 G& f  j
  148.    
    % L5 i. b' M" z4 O2 G* Q% ?
  149. }
    9 B1 C; W5 c2 ]/ \. w- m7 x1 b) f
复制代码

. ]! d. k. \9 h  d* @- k, `
- x* x* s, ]! z. q. H
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-1 00:29 , Processed in 0.055484 second(s), 21 queries .

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