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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

$ P9 ?3 s& S/ b- ?1 V- u5 Q

3 y/ ]/ i6 _' ?5 v/ X由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

* s# k) z% @6 G% L" Z7 B
  1. <?php    7 A2 Z9 p9 y& ^: \
  2. /**   
    ; \& G1 b( ^! `
  3. * 图片相似度比较   9 c( u& C; ~( H, R
  4. *   / P& I5 q' e7 j# C, y7 D# P* K
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    , z8 Q! B- ^6 c
  6. * @author      jax.hu   
    / d) E  ^7 W9 A$ m5 W
  7. *   
    ( s& U1 P6 R* G% m: F
  8. * <code>   ; x) v+ d! h2 |- Y; w
  9. *  //Sample_1   
    ( L" `2 b* w5 }; T( U
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    4 U! m4 a' z: R& p- x) h7 n9 f
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    6 _( G7 K1 m: Y& q- P5 T( R
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    " ]9 w7 p+ W" c* P* x1 T
  13. *   & |2 z) M. A5 y$ C  Q  B  c, k* S
  14. *  //Sample_2   . K  g( i9 E0 V* T
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ) }9 f5 S! {+ m. m( n) f
  16. * </code>   
    6 f$ i0 B% x3 l" Y
  17. */   
    % j4 D% y% p! R9 J& X5 o- ]
  18.    
    ) I! y: `- N: q4 Y. j9 K( g0 }
  19. class ImageHash {   
    % c- {3 D# m1 D- ]
  20.     % T8 V. H" J$ k8 p/ m3 k$ ]
  21.    /**取样倍率 1~10   4 Z$ ~( W& k3 ~! c# u6 O
  22.     * @access public   / p1 O% {/ z. o% M- O) W
  23.     * @staticvar int   0 C; ]( K1 ?* K4 l' K
  24.     * */    2 ^2 T4 ^( n; f# q0 k
  25.    public static $rate = 2;   
    # O* h, n* y' M8 w# o! a1 m6 v. w9 U
  26.    
    ( j+ s0 p) U0 r9 D2 B7 R
  27.    /**相似度允许值 0~64   
    " A; Z( d# D7 S+ J4 p
  28.     * @access public   
      _# Y! M5 T9 M* {% J. W$ x  j
  29.     * @staticvar int   2 o* w: l. P0 w6 ]- l+ L. g. D, f
  30.     * */    / [+ b* T  k) G
  31.    public static $similarity = 80;    7 E  T& V7 T( a1 Z
  32.     1 ], Q6 I% {1 d1 J  \- {' O
  33.    /**图片类型对应的开启函数   / t/ A: {- @) U8 }8 B; M
  34.     * @access private   4 ~; A8 k& o1 S2 R4 }) d+ v
  35.     * @staticvar string   8 g. e# n/ j$ @! b4 U5 T
  36.     * */    6 R9 j" A" b! z% z0 D
  37.    private static $_createFunc = array(   
    ( H5 n+ R3 i# A. n
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',      H$ j: l/ \& Z( [. O* ^5 M5 z
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    $ ]" ~/ f& Y/ X  U
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    : y  A# `+ p8 O5 }
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    - ], ?# o* G* G$ H2 }* J, @9 m- E
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    1 Y" y" b9 y3 f) F. _
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    3 ?' ?' ~& L# }5 y* q% k
  44.    );   
    0 ?7 `2 e3 n* n! i+ x  s" j! K
  45.    
    7 ]" _+ c/ x# N
  46.    
    * C8 i/ |: ]; I4 W) G
  47.    /**从文件建立图片   + ^& q; t2 [. {8 Y8 Q# X
  48.     * @param string $filePath 文件地址路径   
    + J0 Y. y4 P! k5 s8 S+ u
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    3 K5 w- [6 n7 i  T/ z1 t
  50.     * */    ( o9 p5 V' ^. K
  51.    public static function createImage($filePath){    ' Y& L: w( q3 f. W  F" s' S' U0 w
  52.        if(!file_exists($filePath)){ return false; }    ' d9 u3 i- p- R% ]# S
  53.     . I0 _; p( ^+ d; U
  54.        /*判断文件类型是否可以开启*/    , r: y5 y1 i. T" V
  55.        $type = exif_imagetype($filePath);    . G5 O5 x! T' X" A6 R/ d6 g1 p
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    9 a+ |9 n2 E$ E5 A) M' W
  57.    
    ! `9 V% M% R  q5 ^% A
  58.        $func = self::$_createFunc[$type];   
    / w8 D/ V, o( T8 T
  59.        if(!function_exists($func)){ return false; }    8 a. Z8 i4 O: @$ ^3 }3 [% q
  60.    
    & ^0 o! G, i: \$ g
  61.        return $func($filePath);    # f" d% c+ A; ]# l, N
  62.    }    / ?: \$ m0 Z8 P( t
  63.     , g4 M3 n/ |! _& ~4 v( h; W
  64.     - F9 O3 s! f1 ?6 j0 q6 ]
  65.    /**hash 图片   ; i! v  X0 v0 |' |7 ~
  66.     * @param resource $src 图片 resource ID   
    2 Y) c) n0 {2 E* ]& r$ m2 [5 V
  67.     * @return string 图片 hash 值,失败则是 false   6 K- J, G' l% l+ A
  68.     * */    : a* f( {- G5 \
  69.    public static function hashImage($src){   
    " |9 s* |4 p3 S/ U- H  |( ]
  70.        if(!$src){ return false; }   
    ' p2 a) D! _/ R( w) O4 X$ q7 J
  71.     : m1 Z! \% d: }% C. v: g' u
  72.        /*缩小图片尺寸*/   
    " T# f/ y$ T- C$ `$ p
  73.        $delta = 8 * self::$rate;    4 V) C  I6 ^. K, U" E9 g4 O
  74.        $img = imageCreateTrueColor($delta,$delta);   
    5 i! ]8 n! X& Z& Q- o- N8 p) C4 A
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    & I1 A; m; E( J
  76.     ( ]/ {) R3 Q4 H  z6 q
  77.        /*计算图片灰阶值*/   
    : ]2 [" j9 R  p4 p5 C/ J
  78.        $grayArray = array();    ! w5 y- S8 V- P! t1 H0 p9 Q: E
  79.        for ($y=0; $y<$delta; $y++){   
    + D. h5 I3 K0 n2 x1 C1 ~* X
  80.            for ($x=0; $x<$delta; $x++){   
    ! d4 z: b- \6 `( Z) {+ b1 H- H
  81.                $rgb = imagecolorat($img,$x,$y);    - U5 t4 k' p! H$ w3 k1 h& Z
  82.                $col = imagecolorsforindex($img, $rgb);    . [" H+ K/ n- @- j! G( a- j
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    & z1 ?5 @& t6 `# h! f& Q7 l
  84.     ; N( S0 I& {' G# e. p
  85.                $grayArray[] = $gray;    $ i# J" E+ g. b& |
  86.            }    - t9 \2 ]) F% q
  87.        }   
    6 C8 x7 e' o/ d3 C9 `( |$ x2 x
  88.        imagedestroy($img);   
    ) h2 @: |; S% x9 n8 L8 O. X1 p
  89.    
    $ N# P5 G5 l! n. E
  90.        /*计算所有像素的灰阶平均值*/      R- \: D8 k* E) {; @
  91.        $average = array_sum($grayArray)/count($grayArray);    7 I, ~4 _' Z* E/ e& X
  92.     6 v5 F% c0 W3 Z' X' M
  93.        /*计算 hash 值*/    % i9 ?7 u! o0 R9 @
  94.        $hashStr = '';   
    + q: Q- F/ V+ q4 v9 ]6 u
  95.        foreach ($grayArray as $gray){    . M5 d/ l8 x+ q1 l
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    2 }, w3 _8 o9 E; l
  97.        }   
    3 I5 i$ X* w2 {- b
  98.    
    ; u$ d9 p; d% F6 N! {4 I
  99.        return $hashStr;    6 Y5 m, B/ R( B0 M0 [
  100.    }    - n9 \: Q) B) W- Z  N$ ~" z1 e3 U. |" z
  101.    
    8 o4 B" N) ~. z" c& y
  102.     * u# K; A. N! _6 i
  103.    /**hash 图片文件   
    # ~. d, g8 T. G, c6 x2 y& b" [
  104.     * @param string $filePath 文件地址路径   
    " f& `& u% f3 b
  105.     * @return string 图片 hash 值,失败则是 false   ' Z' ]* s0 X$ N2 H! T3 y
  106.     * */   
    . f, `  k* }6 p# A2 m& x
  107.    public static function hashImageFile($filePath){   
    7 u6 ]# c/ W, D/ t! w
  108.        $src = self::createImage($filePath);    " T5 B# k9 g2 r
  109.        $hashStr = self::hashImage($src);   
    1 g  [7 e9 |, f! _
  110.        imagedestroy($src);    , c' L2 J, G2 Q! f0 \
  111.     ; {) h" [% J, h( F. {# v' _
  112.        return $hashStr;   
      s* Y6 x8 Q2 I. G( Y
  113.    }    2 f; F5 n$ n4 J/ \" w4 N* V
  114.     4 m$ |' y: D2 ^! O6 `
  115.     - @3 h# N2 E& q  B3 l/ A
  116.    /**比较两个 hash 值,是不是相似   
    ' m6 f2 Z" X6 p/ X& {8 d; v  `- f
  117.     * @param string $aHash A图片的 hash 值   8 K7 U! e) s. B1 |1 x' f
  118.     * @param string $bHash B图片的 hash 值   
    ! b: f  h& D$ p+ A5 d2 G
  119.     * @return bool 当图片相似则传递 true,否则是 false   : @1 h7 u7 z1 H7 `" x7 [: L
  120.     * */    ! C: u+ m( g, z/ G: I/ D% O
  121.    public static function isHashSimilar($aHash, $bHash){    ' U, |: p/ G" a' a7 c
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ! s4 @4 g) S% F2 g+ ]' V4 `
  123.        if ($aL !== $bL){ return false; }   
    & }- t- }. q7 l1 h2 I7 n+ Y/ ]
  124.     2 ]. t  C6 U& {4 _
  125.        /*计算容许落差的数量*/   
    ! W. \# Q) v) l& m  t9 h9 u
  126.        $allowGap = $aL*(100-self::$similarity)/100;    ; e  ?. I- ^# Q4 f
  127.    
    9 V3 z. t2 m$ u8 k* H: T; l9 N
  128.        /*计算两个 hash 值的汉明距离*/    * e# k6 ^& E+ z2 j' V7 v
  129.        $distance = 0;    9 m) P9 ]$ v1 S* u6 J6 w
  130.        for($i=0; $i<$aL; $i++){   
    * ?; G4 I1 I5 T( ?9 K& V
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    $ }. `, [2 Z2 l8 s. {! ?) h
  132.        }   
    8 p% M$ H8 A4 F! c& W# \
  133.    
    + s. ~' ?$ W  E- ?
  134.        return ($distance<=$allowGap) ? true : false;    : D+ W% i8 n' h9 M
  135.    }    ( m; k- W- p$ \! r  l
  136.     ( C* H4 C( W$ ?
  137.    
    6 g) M2 Z1 V! s
  138.    /**比较两个图片文件,是不是相似     v) k7 l1 \% U8 M# w
  139.     * @param string $aHash A图片的路径   $ z8 m6 r: b+ c' z: p, G" Q
  140.     * @param string $bHash B图片的路径   
    2 `$ q. ]6 q0 F
  141.     * @return bool 当图片相似则传递 true,否则是 false   8 G+ K- m( u9 X, [6 C' f1 W9 U1 E+ ~" i
  142.     * */   
    - ^. E% t2 Z0 W% k8 ~6 Y
  143.    public static function isImageFileSimilar($aPath, $bPath){    . E: |- _# Y1 ?# V* {0 D" D9 K
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    1 @3 {! e+ |; @" q8 |1 p
  145.        $bHash = ImageHash::hashImageFile($bPath);    0 J2 g* R6 a% ~/ p/ ]+ C
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    3 s0 ]! J3 D- g* B/ g- f
  147.    }    ) N4 E; D5 m7 _* I
  148.    
    ! X6 d2 y2 F7 p- ?! L, ]4 A4 V+ |5 R$ b
  149. }
    ! j6 i% {; T$ h4 j4 a3 J
复制代码
' x) B# {2 l: M/ f6 l- w8 d

  ?9 K3 d; g! Y2 z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-17 11:06 , Processed in 0.115569 second(s), 20 queries .

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