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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

4 l' a6 \- u7 X

; ?: P: S" ^0 P# l& H3 ^由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

8 r4 w9 T9 o% H. x$ p! d
  1. <?php    8 k! w. d5 ]4 _- b0 t
  2. /**   
    % {, x8 i1 v  P( P* H
  3. * 图片相似度比较   
    " [% i: T% B9 |/ ?! T% _7 k
  4. *   $ p) P/ b  i7 N
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  % V4 ^  g0 r: J" O3 o6 R
  6. * @author      jax.hu   
    " {# Q9 F" D/ @
  7. *   
    5 T7 S4 F( b( R! a$ {' T5 @
  8. * <code>   
    1 L; X' L( f* E: g0 |  {2 _
  9. *  //Sample_1   
    # z9 x9 H# j" Z
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   9 B; o( M7 h4 w' V) t4 G
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    5 p& C8 O6 A0 t2 N  x
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    # s  r8 [; m% P% K( J4 x9 F
  13. *   6 q) ]" G5 u1 q3 q
  14. *  //Sample_2   - \  w4 Q% i3 [3 J' G
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    4 h& D- A6 ]+ n0 b4 V3 O5 W% i  Z
  16. * </code>   : w# G" k  Q0 {. u$ m9 p
  17. */   
    ) {4 \6 D4 ^! A
  18.     7 b; }; z! H3 ^9 }. ^/ Z  D
  19. class ImageHash {   
    5 R% Q0 L4 K/ J2 G9 ^
  20.    
    - Z$ n0 s) P2 |
  21.    /**取样倍率 1~10   1 s5 m  {5 x" l0 v) s
  22.     * @access public   ' Y  C' \3 |  p: M- c, X
  23.     * @staticvar int   + {$ ?; D" n% D
  24.     * */    : P2 i1 U# ]- W9 H' E! `) B: `
  25.    public static $rate = 2;   
    # W7 I" @- O8 K( N* K$ n, K
  26.    
    + c# N& t8 a9 [+ D
  27.    /**相似度允许值 0~64   
    ; d' W4 m5 u2 W
  28.     * @access public   
      U2 d1 q8 Y9 x; J! N
  29.     * @staticvar int   ! a$ e$ [' c# v% S: r2 W
  30.     * */   
    ) d9 t0 z, F0 g
  31.    public static $similarity = 80;    ' T. V4 i" F# T! y
  32.     1 l( g2 C, \+ S2 g# V: t, r
  33.    /**图片类型对应的开启函数   
    * W9 e1 g2 W0 S& g, b  \' K
  34.     * @access private   7 g% f/ w- \& V4 f3 l, g
  35.     * @staticvar string   
    7 F8 w2 @6 I0 R! I) b: R/ \* R
  36.     * */   
    5 @$ p; ^. M1 {; O+ e
  37.    private static $_createFunc = array(    6 d2 k) F$ M. V  n
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    & y6 w1 l; n* h. M( F: s
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    $ Q; |# [9 w1 O4 P* f
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ' A  Z$ _* Z  v& q: o( q; K
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ' D; j+ N1 o: m; K$ N$ g
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    / C# O5 w. a4 T' Q
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    , ?& Q2 `9 [- P6 |4 W
  44.    );    : o- L6 {' T( N- r1 D$ B  ~& r! V
  45.     8 o5 m7 v  P& v; W
  46.     6 d! v5 j( w4 k/ E/ p
  47.    /**从文件建立图片   
    3 k6 S' }/ }' {7 z- l
  48.     * @param string $filePath 文件地址路径   9 P5 J7 c, v$ w" E  E' Q, I  D# C- K
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    7 Z! P9 Q3 N  E' b: M1 g
  50.     * */   
    ) b6 |) e" V9 ?, b. q
  51.    public static function createImage($filePath){    6 Z- |7 E, [) X$ |6 m
  52.        if(!file_exists($filePath)){ return false; }   
    % z/ m2 i8 c5 D  A
  53.     , k( j+ \& ]- v
  54.        /*判断文件类型是否可以开启*/   
    ( U( r. {; y, x6 v- R9 U* c
  55.        $type = exif_imagetype($filePath);    3 S) u8 h# a. W1 b# h/ ~3 B
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ) f' I1 P# L* M+ H  n
  57.     2 r) f2 k5 s9 c+ ^8 b7 {
  58.        $func = self::$_createFunc[$type];   
    4 e+ _7 _' j" ?/ J% D
  59.        if(!function_exists($func)){ return false; }   
      g3 R8 O& o9 t+ \- z. m! w$ O
  60.     8 w- c% _0 d  g- o3 ~
  61.        return $func($filePath);    6 `+ `* z7 a" L8 F) B
  62.    }   
    % P1 w! v0 W; c5 X  }
  63.     3 A* C  |% D% O( R' Q& c3 ?
  64.    
    ( X  S! g* u" G6 K5 k7 E
  65.    /**hash 图片   7 U0 A7 o; B+ G, n3 E1 H2 l
  66.     * @param resource $src 图片 resource ID   7 i* g9 b* }" B) e* O1 M
  67.     * @return string 图片 hash 值,失败则是 false   7 t) d, b& @3 g* i- ]
  68.     * */   
    0 Z) ?) M* q- |9 p/ y6 Q- p
  69.    public static function hashImage($src){   
    ; o8 d; |$ D9 p* j8 A
  70.        if(!$src){ return false; }    ; E& C8 ^: A' x  r$ J
  71.     " \: A" |" L! _0 E8 u4 I
  72.        /*缩小图片尺寸*/   
    , @' u- e8 [: G- f
  73.        $delta = 8 * self::$rate;    ! D4 W. B% a' R$ A  N
  74.        $img = imageCreateTrueColor($delta,$delta);   
    4 h2 r: \% i9 d! `. O. G
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    / h1 }8 U. `8 y: r! P7 \$ F
  76.    
    . ~4 n; t( k. N1 ?$ v
  77.        /*计算图片灰阶值*/   
    - t; b; n- o% ~5 b, ^
  78.        $grayArray = array();   
    6 c! M1 @* |: O; Z
  79.        for ($y=0; $y<$delta; $y++){    * D+ f1 F+ A0 q! H2 V
  80.            for ($x=0; $x<$delta; $x++){   
    4 z( q) ]# t* F3 ?# O  O6 \
  81.                $rgb = imagecolorat($img,$x,$y);    & t& [6 J/ d1 E, O
  82.                $col = imagecolorsforindex($img, $rgb);    # a% \; C9 M, b0 H
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ' L) q% s4 Y) K4 z9 B
  84.     # k+ s" [9 D, s* H, L
  85.                $grayArray[] = $gray;   
    , }) }( h- S* h% l0 ]- M& |
  86.            }   
    9 c4 H& Q2 g( p( T: p! C5 x
  87.        }    1 H; N# y/ d* E
  88.        imagedestroy($img);   
      @, ]/ m0 H/ K4 j! T) K
  89.    
    & F0 b& X: t3 X
  90.        /*计算所有像素的灰阶平均值*/   
    ! M) y! \% G1 v( m9 @: {) T+ O
  91.        $average = array_sum($grayArray)/count($grayArray);   
    7 L7 J& J- [: E7 Y
  92.     & F$ f' r0 c( R, K; r
  93.        /*计算 hash 值*/   
    5 N+ _$ F+ d! l  o0 r
  94.        $hashStr = '';    + D3 }2 T' |5 C* u# P) Q+ N
  95.        foreach ($grayArray as $gray){   
    4 |2 n  s0 E6 Z% U) |' u
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    1 a% e3 y4 q9 [3 X# D
  97.        }    ' s5 U3 j- O- E8 x! p. E$ V
  98.     3 W3 n& ?4 }- c3 K- P& _
  99.        return $hashStr;    ! D5 Z$ ^% }# b5 X& a! I
  100.    }    & X) C' z4 z- w) s0 p6 R9 _! |$ S2 G
  101.    
    % y' f" d5 ?6 n9 d" s  Z
  102.    
    5 i0 b& n! @; S# g1 |: Y$ z" j
  103.    /**hash 图片文件   
      C$ a$ L2 [8 m. N( ]5 V9 g
  104.     * @param string $filePath 文件地址路径   
    3 S! l7 D+ H( S6 b; q
  105.     * @return string 图片 hash 值,失败则是 false   * u+ `1 z; T9 {; d3 b
  106.     * */    $ @" |/ k8 Q. T1 s/ R9 l& x( V
  107.    public static function hashImageFile($filePath){   
    : ?9 O$ x4 W# y! H
  108.        $src = self::createImage($filePath);   
    1 t( n% c0 Z, X) v) s* N
  109.        $hashStr = self::hashImage($src);   
    ( r  I( q- S: b. s$ M
  110.        imagedestroy($src);   
    - ^7 ~' c3 l* ?% f
  111.    
    5 [, H& W0 X; k
  112.        return $hashStr;    ) K) G6 r  q6 ]9 @0 I
  113.    }   
    & _) A" w; E3 I. M" L/ r
  114.    
    7 L" L6 ^/ }8 o9 s. R
  115.     * h2 w' R: E* |( S7 H
  116.    /**比较两个 hash 值,是不是相似   
    ; U  J" {/ ^5 v+ p# G4 ~
  117.     * @param string $aHash A图片的 hash 值   
    ' S+ z$ I, ^5 r7 R6 }
  118.     * @param string $bHash B图片的 hash 值   
    8 W# O4 ]2 x/ D
  119.     * @return bool 当图片相似则传递 true,否则是 false   ) [* {5 _5 M8 m2 k. I$ ?  |
  120.     * */   
    : c0 `9 P: K8 E& m3 q/ ?% k
  121.    public static function isHashSimilar($aHash, $bHash){   
    7 ]7 @0 @  \6 |$ D5 H, Y
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    & O0 q- q  k+ b
  123.        if ($aL !== $bL){ return false; }   
    + ~: \1 t8 ^3 {1 Y+ R
  124.     5 G# K' g- I+ E* x
  125.        /*计算容许落差的数量*/    0 u) i9 r/ F7 _0 v0 f# ]
  126.        $allowGap = $aL*(100-self::$similarity)/100;    , T% v( F( b" H4 Z
  127.     * G% P$ V" Y, l  B6 q
  128.        /*计算两个 hash 值的汉明距离*/    1 k4 Z5 x( o8 R6 b& a8 {" p
  129.        $distance = 0;    . J# ~+ C# {: N  j/ y
  130.        for($i=0; $i<$aL; $i++){   
    % Z: k# B8 _( o! B" P
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    + G& J6 ]+ ]3 p- r
  132.        }    8 n7 w: V7 V$ b" \9 H& |* T8 ?
  133.    
    ( X+ w+ F8 f/ b2 U: ~
  134.        return ($distance<=$allowGap) ? true : false;   
    , w" M# ~3 _+ `2 c+ J: @2 w( M9 T
  135.    }    ! }9 e5 ^+ a# ?6 H5 a
  136.     6 _% d, S: _% F  p
  137.     % k3 @5 k4 g6 q1 E. y
  138.    /**比较两个图片文件,是不是相似   6 J+ A8 P; S. u; X2 f+ I
  139.     * @param string $aHash A图片的路径   ) d5 H5 L3 e' ]4 C# {9 b! {
  140.     * @param string $bHash B图片的路径   4 p! o* ]( m% j" r. I  i& x! V3 [
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ( a+ H8 B6 N. X( O" {' K
  142.     * */   
      q0 h3 i  m1 u4 ?9 O4 b; p
  143.    public static function isImageFileSimilar($aPath, $bPath){    ; B/ p+ o- {- A! t7 Z
  144.        $aHash = ImageHash::hashImageFile($aPath);   
      |' ?1 r8 J) T
  145.        $bHash = ImageHash::hashImageFile($bPath);      Q6 c7 N1 a0 K/ M
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    1 `) [8 N3 j- N5 }/ d" x
  147.    }   
    * ]: u. O1 l. t2 Z6 w# N3 P
  148.     1 o5 H9 E7 D1 v) G
  149. }- F0 T9 X- ]7 D) N
复制代码

) r$ Y, k( O$ h9 n* z; \
& b5 S9 N  m  P' I" B7 |
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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