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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图* `/ U  }5 l' m$ {' `
# C4 U: X6 y/ |9 Q) j$ t
$ s$ [2 T7 M% L8 v7 j9 {. `0 c" |
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
; K0 C. j: S( a+ c
  1. <?php   
    : O$ V& {, z) a- i
  2. /**   
    " _4 t7 b2 L# F; x3 Q2 S( O3 ^
  3. * 图片相似度比较   
    : m% Q) J% e& w4 t+ p
  4. *   
    - l+ m: P" w) a! T( a9 V7 o0 n
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    * {; \. A3 I: y# }& [/ S( C5 h
  6. * @author      jax.hu   
    1 T( S, f+ ~- e8 [( L
  7. *   4 Z$ c0 G) X% W, s( O# o8 Y
  8. * <code>     X( @- k* R% W' w
  9. *  //Sample_1   
    , K* M2 k- [; {& w- g7 r8 h
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   ) m- {( @. r6 F  _/ C
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    6 m& H5 z2 Z- ^% h1 v
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    6 g+ a1 ?  \- u$ t
  13. *   
    6 V% f- q  P. z0 l6 Z+ ^/ [3 f
  14. *  //Sample_2   ! |+ p! e& O9 z' q& X2 ~4 K
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    " ?: O5 y! [* G" f' R
  16. * </code>   
    , G- \7 K3 S, r' `
  17. */    " t7 Q0 f9 w5 a2 q2 o5 W
  18.     , ?: A; C7 e% J& d8 q& T/ m2 z0 `
  19. class ImageHash {   
    ( Q- |: u) e* b& ~6 r( |
  20.    
    " s& w" V5 V0 Q/ s- |' _+ J
  21.    /**取样倍率 1~10   ) ?' r+ a5 ?8 q2 A& D
  22.     * @access public   1 h$ Y- u# l# A$ {
  23.     * @staticvar int   2 o" {6 Q# o& B! g! e
  24.     * */   
    - g! }4 F4 k% e( Q7 T
  25.    public static $rate = 2;    & v2 v; \; V5 ]2 u8 {8 C
  26.     ( U8 F$ b9 E9 {1 d# K2 t1 W) `
  27.    /**相似度允许值 0~64   * K6 I( F+ N6 C3 j7 r
  28.     * @access public   ! Y- {7 h( g: {5 t* D& u
  29.     * @staticvar int   
      K) x2 |& ~( e$ V
  30.     * */    6 I% x. E, X1 A/ Y( u' Q
  31.    public static $similarity = 80;   
    * K- [$ |' i, c5 \8 s
  32.    
      B/ `3 c( U. H3 i0 {% V
  33.    /**图片类型对应的开启函数   : }: q5 x3 Q5 e0 W
  34.     * @access private   5 i7 C8 \; W6 c) u& H. ?! N
  35.     * @staticvar string   + }; S5 k$ w8 j- @% Q* e/ J& _9 C2 l0 N
  36.     * */   
    6 F! T" O+ N2 z1 n3 v
  37.    private static $_createFunc = array(    - W6 {7 e3 u. l: A! w- G+ J% K
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    % g0 E8 q) J* k7 V9 H* p5 G
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    8 n+ e7 k, v( a9 p9 |( ]
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    * H$ G  m  q* N* @# `7 G6 d( k$ t  ?- Y
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    & g* m& \2 X+ s, M
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    7 L7 _- X8 k4 x; y0 `
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',      k, I. @- O% c
  44.    );   
    ) j5 r( Q0 w# f# C) _: C& W
  45.     3 L# F6 p' }. h
  46.     5 c1 V3 k! z" t- p# H8 T
  47.    /**从文件建立图片   ; s; {8 \- Q* i# S' j7 d3 ^
  48.     * @param string $filePath 文件地址路径   
    $ ?. ?5 U- A# z# j7 h
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   6 K$ N' n1 q$ w. ~
  50.     * */    ( C# c: W4 q% W; B6 }& ?2 h
  51.    public static function createImage($filePath){    ; j+ K' q4 x/ F" x
  52.        if(!file_exists($filePath)){ return false; }    9 I5 o+ K5 K  n& s6 |
  53.    
    * L; @* l2 b# x9 P" M
  54.        /*判断文件类型是否可以开启*/   
    % {! o9 W& w$ H* V+ Q6 G  b" y
  55.        $type = exif_imagetype($filePath);    , I% j6 _4 w$ @: b4 V; V
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    1 ?8 B$ {; W0 F
  57.     : V. S1 g4 i! n$ B3 f# M0 k3 A
  58.        $func = self::$_createFunc[$type];    & D- v7 W# r6 A( x& G
  59.        if(!function_exists($func)){ return false; }    5 Y  \0 `% d& y6 g9 ~
  60.    
    7 w( W, `9 Q5 o0 e
  61.        return $func($filePath);   
    ' N" Q) N  I( g. L
  62.    }   
    1 z9 e* |3 r. _( f8 W) i4 l
  63.    
    0 `5 g* p' u* a2 H# P  E  s
  64.     6 m7 m4 H# S& \# d0 Z& u' w( a
  65.    /**hash 图片   
    6 D" Y/ N2 P3 p
  66.     * @param resource $src 图片 resource ID   
    6 W$ x" m+ U$ u( \: `; F
  67.     * @return string 图片 hash 值,失败则是 false   
    1 _0 O: ~) u1 w& V
  68.     * */   
    ' K7 K8 I  j9 }. n0 W8 x
  69.    public static function hashImage($src){    % q8 s4 l6 ~) K4 i0 X% L6 @" r/ v  O! `
  70.        if(!$src){ return false; }    $ Y5 S4 R# b$ U- g+ T: K9 x2 U
  71.     8 C# f" }# H- f. }3 ]' i
  72.        /*缩小图片尺寸*/    1 A2 ^) `' A7 d2 a
  73.        $delta = 8 * self::$rate;   
    * G# Z3 h( Z8 v( d7 L2 ]0 [! p
  74.        $img = imageCreateTrueColor($delta,$delta);    2 f, m$ _" C+ b
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    - x+ @6 e/ T1 Y$ W
  76.    
    9 g( U; h5 q$ E; v1 y
  77.        /*计算图片灰阶值*/   
    ' _+ ~# F  A, z3 k3 ?+ i. Y
  78.        $grayArray = array();    - |; k5 V: `6 d( k. W$ Y
  79.        for ($y=0; $y<$delta; $y++){   
    # }5 G: K( ~; P( W
  80.            for ($x=0; $x<$delta; $x++){   
    5 ]3 R( K/ j- S, o/ D5 v& [
  81.                $rgb = imagecolorat($img,$x,$y);    # S" D6 R( b8 m
  82.                $col = imagecolorsforindex($img, $rgb);    # |2 G/ ~3 N3 e
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    & q. m8 N1 h6 ]8 O' y8 v! e. x
  84.    
    $ T0 X1 x5 e) }! j- ^& W4 M0 j( x
  85.                $grayArray[] = $gray;    9 @5 T# Z8 s7 f6 L. E! N! E
  86.            }   
    0 o* [8 X0 ^+ u, i$ f
  87.        }    6 n' y% Y* g: f" y
  88.        imagedestroy($img);    4 S2 J6 O3 A- t9 q! o
  89.     0 l1 v! l5 H& \8 I* N8 F
  90.        /*计算所有像素的灰阶平均值*/   
    % p' X  O' W  i4 @- v. l, ^
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ) G6 F' e7 H/ O9 h# }
  92.     ( B9 R" ^7 V1 p) S& @5 L7 _
  93.        /*计算 hash 值*/   
    1 b8 z( c) `; g  x. J' R" @0 ?
  94.        $hashStr = '';    & {6 c, A0 w6 E$ t0 a$ m
  95.        foreach ($grayArray as $gray){    $ \0 B. G5 F% V% M  T  q, I4 a6 y
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    , z8 v& L8 d5 h/ g" a
  97.        }   
    6 p  }6 I+ @, D9 n  ~. j, x1 r
  98.       Q; f  X& |8 N6 `5 {0 d
  99.        return $hashStr;    ) r0 p9 W  S! t1 l2 p
  100.    }   
    ' N7 _0 S; c; g  j" G* d
  101.    
    9 W6 h+ r( `. |* P) y  S9 p/ c
  102.       K4 q$ Y$ B  e6 i/ e
  103.    /**hash 图片文件   
    ) j* n& O: }: P9 k4 z4 {
  104.     * @param string $filePath 文件地址路径   
    8 n2 b+ ?+ G- k$ s+ f
  105.     * @return string 图片 hash 值,失败则是 false   
    2 V# z1 I. x& a6 G9 W6 w
  106.     * */    ' ~8 Z. r/ r, N* `6 _
  107.    public static function hashImageFile($filePath){    & W2 X3 V7 Q# ~* q2 s, R
  108.        $src = self::createImage($filePath);    + N- v. u3 s: i- _/ E
  109.        $hashStr = self::hashImage($src);   
    4 ]: z( A6 f# a
  110.        imagedestroy($src);   
      B2 E: H. B, C0 ^$ Q8 [
  111.    
    + [3 e+ s! e# P* L! i
  112.        return $hashStr;    9 O1 G1 |6 S4 @
  113.    }   
    . V. a9 o: W" r, N
  114.    
    - w4 ~3 Z) G- y6 o' h/ i" x
  115.    
    8 E2 b4 ]. f; ?. W& O/ L
  116.    /**比较两个 hash 值,是不是相似   ; T( E$ P5 ?7 }, Y; ]3 v  K
  117.     * @param string $aHash A图片的 hash 值   
    - d/ U# q+ W% `1 F6 Q3 `% v% h
  118.     * @param string $bHash B图片的 hash 值   6 c3 L. [4 d1 }# V
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    & u2 L2 {% }: I8 l' M
  120.     * */   
    3 `$ l! ?$ o  [3 i9 L4 x2 O% I" |2 Z
  121.    public static function isHashSimilar($aHash, $bHash){    : E0 r7 T# V" ~* l
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ) F3 J8 B) z0 f/ z
  123.        if ($aL !== $bL){ return false; }    4 B, c" x9 u$ M2 @
  124.     - }( f. a; F8 r/ N0 V
  125.        /*计算容许落差的数量*/   
    4 [6 p! A; ]3 |+ ^
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    + d- _0 j# P+ `1 f
  127.    
    7 T9 B$ ]6 {- u
  128.        /*计算两个 hash 值的汉明距离*/   
    / @2 f: c0 X' a: h( ?7 \
  129.        $distance = 0;    - t9 }' E3 S; X4 t! g. s) a
  130.        for($i=0; $i<$aL; $i++){   
    , ~/ m* ~0 @) }
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    6 K- ^8 o0 m. o2 {
  132.        }    1 k4 ~2 p8 [9 D
  133.    
    . C: D, t! C: ]0 w
  134.        return ($distance<=$allowGap) ? true : false;   
    - y$ P+ p( G5 n1 [% e* h/ R$ v1 G
  135.    }   
    9 v5 I) _0 k! u/ c; B) X' \. z
  136.     # t3 b+ R) o5 ^5 ]
  137.    
    5 r. n( [' g4 h8 j
  138.    /**比较两个图片文件,是不是相似   7 b& t3 j5 ?4 u0 m& l6 z! M* W
  139.     * @param string $aHash A图片的路径   - c. u3 f  G! F& Q+ v0 D7 |
  140.     * @param string $bHash B图片的路径   
    ! h( T' n# K0 E* _0 H+ @
  141.     * @return bool 当图片相似则传递 true,否则是 false   ) i2 ~9 i+ Y2 l/ R* l' Z
  142.     * */    4 N% B) o/ h, v, h' k( A
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    + p! p) f; m2 V. m
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    + p; z$ O8 h; {
  145.        $bHash = ImageHash::hashImageFile($bPath);    - X6 [" g: n: A1 P) G1 C/ A
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    2 H! c# b, n4 F2 |
  147.    }   
    ! P: ?+ M- z6 U4 T
  148.    
    # V9 `, i, C& C, R' w3 O
  149. }
    " I' i/ N% r' S% T4 m  W# \
复制代码
5 K1 X. U8 n( f3 g* ^8 y8 n- T* M
2 u! V: K8 f' h$ @6 {  T+ d* Z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 07:35 , Processed in 0.132587 second(s), 21 queries .

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