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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
- i8 c3 l8 F/ c% L; m6 \, j" X. P2 }( ?% z
; e2 ?8 P6 r( C' Y* l4 X" Y
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

( u" G* I% J; b* l, \: k
  1. <?php   
    * r" Q: j  [9 e" T1 P
  2. /**   ) k) H5 O  g9 A) i0 k2 u1 D! ^
  3. * 图片相似度比较   
    # w8 a, W1 c2 C; S  t
  4. *   
    * m4 [. u/ c" ^% l* B5 K1 g
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  - f; h0 F5 K4 p8 U% K# I0 A3 _7 O
  6. * @author      jax.hu   
    + v* J' Z1 W" f1 N3 I" v
  7. *   8 L  |( X5 q3 s% X
  8. * <code>   
      l* B- @6 j& |$ O/ S% A( l
  9. *  //Sample_1   
    $ \! P2 }6 x( l/ H2 g
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   : p( G7 y$ z* J  ~
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   0 Z2 F' ?3 n: c6 u. x2 \
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ! G* R+ @. h" y* ?
  13. *   
    % {! J+ S1 F) U* Z( g5 \+ T, j& m
  14. *  //Sample_2   
    ' X$ R- {) y7 O. ]1 V: z( q( {
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   2 X3 a2 Y* j9 l  m$ I' C* Q/ @
  16. * </code>   
    & u  V+ u) a3 T" g0 @6 h3 |
  17. */    ( E# r7 h5 y' s
  18.     ) _9 f5 y/ E* M7 o" R
  19. class ImageHash {    6 |! W2 W0 i8 {
  20.    
    2 j5 d1 X  Y4 }  T/ u0 L
  21.    /**取样倍率 1~10   " f+ V6 x7 d' j
  22.     * @access public   ) `( u6 @& @: T2 k. j6 u" e
  23.     * @staticvar int     A5 f& e) X  T
  24.     * */   
    * A7 v% [* x& L& \% K: Q9 Z
  25.    public static $rate = 2;    0 r: X& Y4 v0 [! x; g) Q, b  R
  26.    
    / U$ L1 @) o6 ^0 _5 b
  27.    /**相似度允许值 0~64   
    # a; d% ?% m( n
  28.     * @access public   % G, O2 k- j2 @( A) g' Q* e$ \+ K  Q
  29.     * @staticvar int   
    $ ?9 y" g8 s3 V8 Z  j* `
  30.     * */    7 m* B" S4 y8 f& R1 N6 T- I
  31.    public static $similarity = 80;   
    2 C: A5 \; }( z+ j  }
  32.     : p6 Q) Q3 e  `
  33.    /**图片类型对应的开启函数   
    + r, k  K- C6 y. c  I5 d
  34.     * @access private   3 }9 g2 K1 ~" K  P+ f- {' W
  35.     * @staticvar string   6 ?' @, A$ k( f- `2 r
  36.     * */   
    ( f% _5 ]$ Z  u, x* B4 O
  37.    private static $_createFunc = array(   
    1 J3 |) k5 t( Q( I
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    " ?! X2 {: f. S6 E" u
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    9 u2 b) q4 z6 K$ W
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    + |( K, m( s2 O) K' b9 @6 s* x
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ( k- u; ~3 G) |; r: G$ s2 a
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    / Y  D* R) e8 P0 }1 i
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
      I) p$ [9 d" T
  44.    );    0 `" q; v7 s! T! o  @- a/ i
  45.     $ f5 e5 F9 i) s# t0 o3 B
  46.     $ Z8 _8 N; j0 |3 _4 s1 b$ G
  47.    /**从文件建立图片   
    " \. Z+ Y3 E6 k% Q& _
  48.     * @param string $filePath 文件地址路径   
    . X$ j, t8 |9 D! G
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    & l: @2 f' ]8 X0 M- g
  50.     * */      \# `& U' F8 R0 h( C
  51.    public static function createImage($filePath){      i! N1 d% k) P7 B
  52.        if(!file_exists($filePath)){ return false; }    9 u# U/ [9 w# q( a/ r# |
  53.    
    , {3 F$ H& ^* a* h
  54.        /*判断文件类型是否可以开启*/    8 q7 q9 d* _7 e5 n
  55.        $type = exif_imagetype($filePath);   
    9 F& H0 h) l5 P% ~
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    : o8 @& f# h/ x- z  d
  57.    
    % o1 g1 o" ]% y6 o8 j5 ^
  58.        $func = self::$_createFunc[$type];   
    ; q. T5 N! j' s4 b
  59.        if(!function_exists($func)){ return false; }   
    $ Y) q/ ]& g; ~; H
  60.    
      B7 p, p& ?$ U( v- G
  61.        return $func($filePath);    4 j& a& e( G' i+ ^; T# d) J# g
  62.    }   
    ) U" i* G6 Q) I/ d; V1 ~  E# m0 t
  63.    
    5 X: U2 }' o& s! V5 X7 `
  64.     0 h, Y( o7 z# [8 Y6 }3 A3 Q! K5 V
  65.    /**hash 图片   
    2 K# z/ g, l5 X4 E
  66.     * @param resource $src 图片 resource ID   ' M3 ^/ ?) F/ C+ T
  67.     * @return string 图片 hash 值,失败则是 false   
    # d6 ^# M, l, J- E; J7 n
  68.     * */   
    / Y; V, U% j" J; [4 i$ @
  69.    public static function hashImage($src){    3 `2 G0 b2 i% b! U3 X& X) w8 ~/ S
  70.        if(!$src){ return false; }    / i+ Y% }2 v% x
  71.     ( L+ J0 ?* Z, s. ~) P" ]. [9 ?
  72.        /*缩小图片尺寸*/   
    2 l0 U3 l. i4 ^0 J8 w/ m
  73.        $delta = 8 * self::$rate;    1 u) a9 n- z( T) o
  74.        $img = imageCreateTrueColor($delta,$delta);   
    ! q1 _9 q: @7 b1 z! M  B
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    . o4 l) D3 L& r$ ^# S. m
  76.     * g9 S; N+ @7 Y; I- c) B; H
  77.        /*计算图片灰阶值*/   
    7 M# L! J0 O) L2 g7 z
  78.        $grayArray = array();    ' r  F' A' Q0 r( A, \
  79.        for ($y=0; $y<$delta; $y++){    7 ?  a$ o& R# H
  80.            for ($x=0; $x<$delta; $x++){   
    ! p+ ?' x% Q% a3 h! r1 w, a
  81.                $rgb = imagecolorat($img,$x,$y);    9 V3 M/ I3 }$ b$ z! o' G
  82.                $col = imagecolorsforindex($img, $rgb);    % X: n, h  b3 k5 u
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    - E" k0 e# M7 e: U  a. C. K) I+ b4 a
  84.    
    + D6 J0 m4 {! s* R+ }
  85.                $grayArray[] = $gray;    9 }2 e) i5 \9 @+ J0 j' E
  86.            }    6 ~, K3 l* P+ R( i" K4 W; Y
  87.        }    ) _- i( ~6 ^0 J( U
  88.        imagedestroy($img);   
    1 _( r5 O' L, O. v% Q0 f' B7 [4 d
  89.    
    . `- T; z# t* ]- i
  90.        /*计算所有像素的灰阶平均值*/    7 }( ]; j* F2 x1 j$ t
  91.        $average = array_sum($grayArray)/count($grayArray);   
    7 x8 h  z* v% r( Y" f  _+ @5 j
  92.    
    $ E) {$ Z1 O# P( ~' n9 `# H
  93.        /*计算 hash 值*/   
    . `& a+ p  J0 V2 {$ ]- m8 w/ n# g
  94.        $hashStr = '';    , N5 K: ^/ |8 r0 v2 M
  95.        foreach ($grayArray as $gray){   
    5 t# q. [+ ]8 u& N0 h$ b
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ' n/ H" r2 r+ V6 q5 U# ?" h4 K* V- ^3 u
  97.        }    / `' `  L/ H# I) R4 U% m  f
  98.     $ W1 O4 ^: c- B' ?) {  J
  99.        return $hashStr;   
    6 r/ g- Y- f0 p2 W0 ~) t
  100.    }   
    3 Z8 e% p% D/ q- }: }$ m
  101.    
    / d; L- C6 C0 \1 M
  102.     2 J' A/ o7 @" D7 T+ h
  103.    /**hash 图片文件   
    , @/ g/ i) Y. J" o7 |. ]2 o' r# _
  104.     * @param string $filePath 文件地址路径   
    5 O$ h. C% m* W1 Z# @5 n
  105.     * @return string 图片 hash 值,失败则是 false   
    $ ?! k( Q+ u# Y* _0 n
  106.     * */    , I/ z' n" R( d3 l
  107.    public static function hashImageFile($filePath){    $ w7 S; t. [% W/ K5 P# s9 O
  108.        $src = self::createImage($filePath);   
    7 h# |& Z/ x0 B% b' y1 {
  109.        $hashStr = self::hashImage($src);   
    2 }$ O6 i+ e5 G& m* B' L
  110.        imagedestroy($src);    ! G: Z! N8 f  J5 r, q( o
  111.     0 Q- a5 p; \! O" W  s7 [
  112.        return $hashStr;    ; k# l5 Q3 A! e9 H2 o! g
  113.    }   
    & r+ @* R; l5 j/ D" r# c( l8 L
  114.     " [' _8 h2 w# t# T7 I
  115.    
    + V9 l6 _( N# I3 r# B( @6 V
  116.    /**比较两个 hash 值,是不是相似   7 G  c4 h  O$ k% [9 J( s
  117.     * @param string $aHash A图片的 hash 值   
    # K8 u( o* N7 u" l- K5 T# ^
  118.     * @param string $bHash B图片的 hash 值   3 a! H+ O, ^! ~4 @8 }, o7 m9 z! x
  119.     * @return bool 当图片相似则传递 true,否则是 false   4 O2 n( [7 v" e) B
  120.     * */   
    - W5 w! ^* i. e" t) |
  121.    public static function isHashSimilar($aHash, $bHash){    $ N' Q# u4 M: A$ g' w  d
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    + [7 J, R. g( n+ K" r% N1 l
  123.        if ($aL !== $bL){ return false; }    6 S$ S  M; a" W/ V
  124.    
    0 W& t% }$ p( }9 M
  125.        /*计算容许落差的数量*/   
    ! v! }' b  O3 U0 P8 t# w$ r: Y. _0 s
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    5 I6 g) o; ]. {; m3 y" U1 `3 A1 q
  127.     : i6 Y0 O' M8 E* V4 O9 r/ N" M
  128.        /*计算两个 hash 值的汉明距离*/    " H5 D! s. T, i7 d+ `
  129.        $distance = 0;   
    9 `- o2 K* k$ y
  130.        for($i=0; $i<$aL; $i++){    , y* M8 m, O+ `! H' L
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ! m& a8 E% @) |. q4 f# G  ~
  132.        }    ) t) }* |( L5 V$ [$ A
  133.    
    8 ~" e$ l6 a: d' H+ B
  134.        return ($distance<=$allowGap) ? true : false;    % D/ _. |. K: U6 N2 Y) }; ^# r7 q
  135.    }    & P# h8 A5 S. z: s
  136.     8 M) ^+ }5 K4 d6 F+ b9 [8 @
  137.    
    4 B. u4 S4 _0 `/ H& h% W1 p
  138.    /**比较两个图片文件,是不是相似   , w, I2 U) Y( M! U5 W
  139.     * @param string $aHash A图片的路径   
    0 |9 g5 n: [. \* X  L: T
  140.     * @param string $bHash B图片的路径   ' ^7 M; ^  N( Q% J5 B6 z+ w) W, v
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    + o- ~; l* i0 s2 }0 C3 X2 U0 V5 f4 |
  142.     * */   
    4 _" y" ~0 C! h! a# a2 H3 t
  143.    public static function isImageFileSimilar($aPath, $bPath){    # \! s. @9 W. i( m$ w
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    - M( \+ u- Y/ q! q
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    $ M( M) m+ F: g9 X
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    ) U, _* @, d( n5 t
  147.    }    : V- I$ C2 o& I1 s0 h( G  r
  148.     9 S$ |! g, G5 x( G" o
  149. }
    ' }4 @8 `3 f1 v0 W( Y  Q
复制代码

0 L' u1 ~: A# X  y# J
3 m& ]1 [" v6 z1 S. G& L3 j7 K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:45 , Processed in 0.073333 second(s), 22 queries .

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