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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" _5 @% Y, g0 E5 L) u1 H! c3 m由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
8 C9 h* j9 Y5 ^( R: r
  1. <?php    % n- I& A5 F* r$ m+ ^  F/ |4 g: q0 G
  2. /**   
    . r- t4 S% k$ B% S( ?1 V9 ]
  3. * 图片相似度比较   
    % @3 }6 g+ ?3 p& ?
  4. *   
    9 ~4 _" K. |; A% w
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
      a; [6 F# }0 ^) q- [' g
  6. * @author      jax.hu   $ J9 ]) ^3 L) `  {
  7. *   7 n& j! }* y7 p% `& X
  8. * <code>   + f, B7 c+ `& K: J7 \# y0 p9 B- V
  9. *  //Sample_1   
    3 _- \4 N# B2 q+ `  @; \
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    3 W- b. @9 P+ R. J4 M) L
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
      Z% Z1 ]  s! l% r. ~
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   8 Y0 c8 Y. ~- @4 h
  13. *   * n# I* t& n  v  ~; D% B5 d
  14. *  //Sample_2   ) V- U+ T* Y% Y8 C$ c6 R
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   : K3 m$ D7 R: w# X$ Y
  16. * </code>   3 e& K2 Z6 ]5 }# M9 D2 B' U1 U) ]/ S
  17. */   
    9 C. ~5 s0 M* o  f% O. l7 r, v
  18.    
    . b! p' N, C  _" o; a
  19. class ImageHash {   
    0 o/ }+ X- o- M' T$ @( h
  20.     1 ]. u8 M; I7 k
  21.    /**取样倍率 1~10   
    " d+ v$ k/ x) V
  22.     * @access public   1 @. z9 i& g# Q9 Q6 p0 Q. w. @* \
  23.     * @staticvar int   
    - ]4 O7 X0 K$ s9 [) e! w
  24.     * */   
    1 P' O7 c3 k: d7 S% S
  25.    public static $rate = 2;    1 E! ?! d! u7 y6 q3 i. p+ p
  26.     3 C, S$ g9 H2 Z" S5 J$ t) W* u
  27.    /**相似度允许值 0~64   
    ' G5 F2 c" g% Q; T: S
  28.     * @access public   
    . k- _1 s4 z7 W2 D/ Z
  29.     * @staticvar int   8 n; u( J/ C3 |) B4 N1 D% ^
  30.     * */    7 r# t. g+ {- ^( s5 K1 H6 e" L
  31.    public static $similarity = 80;    $ F2 x$ w9 i  }6 N, a+ z7 U
  32.     0 r8 u) }: B' i
  33.    /**图片类型对应的开启函数   
    # v3 s; C3 B7 C3 D' g
  34.     * @access private   
    2 A6 j! e* f; G* e
  35.     * @staticvar string   
    7 M$ Q& k7 D0 X# a6 |' F- [
  36.     * */    1 V" l/ u% V& U! z- F
  37.    private static $_createFunc = array(   
    ! |/ K* o# m. e# c0 h' m" x
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    * i* e/ H' I* B, d
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    : T" l, E9 _* l) W& A
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    9 E$ x9 x. K! u+ {. S2 n
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    * G5 G( V6 o& y
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    + s# r4 `8 p8 P
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    # G2 q2 r9 S$ W# _$ n
  44.    );   
    5 y, A4 [( y4 E+ q
  45.    
    8 K8 l8 }* ~1 X8 N
  46.     6 P& d% E# x$ s4 U3 f
  47.    /**从文件建立图片   
    " N' O& C) A, T; f  \: m* T7 Y
  48.     * @param string $filePath 文件地址路径   * b" O$ ]3 b! b. ]% n
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ) o8 F' |& h9 K# Y. L
  50.     * */    ; M- z% d) q/ a
  51.    public static function createImage($filePath){    1 k4 p+ S6 R. @0 X
  52.        if(!file_exists($filePath)){ return false; }   
    / q, G) g! s% J/ R  c
  53.    
    + y( m8 P# n; x7 V" d; d
  54.        /*判断文件类型是否可以开启*/   
    9 ?  j; z, O9 t! N" i
  55.        $type = exif_imagetype($filePath);   
    % |# z+ j' s4 }1 V7 n
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    4 ]/ q5 o/ V: Z7 n+ L$ Q/ w4 M8 B1 j$ d& H
  57.    
    3 W* T1 _" j" A+ a
  58.        $func = self::$_createFunc[$type];    + s( q4 b8 J' C& r! ?& e
  59.        if(!function_exists($func)){ return false; }   
    1 t* ?8 I. f, y8 U
  60.    
    $ r! V4 `/ ^8 ~/ C! g( p
  61.        return $func($filePath);   
    " i. y3 h6 J  q
  62.    }   
    ( `7 J1 m7 O$ E/ v* W% M" H/ n- J
  63.    
    0 v, A0 M' F* T' V2 Q
  64.     0 z4 q1 s/ i; n( w* l2 l. ]$ i4 g
  65.    /**hash 图片   + h3 X6 z' X7 |+ n- Q# I, h
  66.     * @param resource $src 图片 resource ID   + X4 V' s# a1 N6 {$ F
  67.     * @return string 图片 hash 值,失败则是 false   
    4 g+ a' D9 j( g- V$ h& J
  68.     * */    - y9 O, V2 R% s. x2 C
  69.    public static function hashImage($src){   
    , `7 c2 r4 ?4 B( b. z
  70.        if(!$src){ return false; }    2 P( `3 u7 ~* i$ d  @/ F# P' A0 k
  71.    
    1 W, ~3 L+ H. L5 Z4 h
  72.        /*缩小图片尺寸*/    5 L8 z& }( l0 d/ W( C/ r
  73.        $delta = 8 * self::$rate;    0 @5 s  d( W! L5 H# |
  74.        $img = imageCreateTrueColor($delta,$delta);    4 Y8 Y8 K( m! T
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    6 h* K  {- q$ M* F& w" z
  76.     1 r# j" ]& _3 d0 S
  77.        /*计算图片灰阶值*/   
      @% h! G' f/ d5 l- X9 A
  78.        $grayArray = array();   
    ) N2 N6 w" c6 j& R
  79.        for ($y=0; $y<$delta; $y++){   
    / i- A8 s3 q/ D$ L8 F+ G
  80.            for ($x=0; $x<$delta; $x++){   
    2 `2 {/ W6 J3 g/ {  G1 @, U6 I
  81.                $rgb = imagecolorat($img,$x,$y);   
    8 d1 e0 f3 d* x& Z$ _' z
  82.                $col = imagecolorsforindex($img, $rgb);   
    ' _+ [: ?$ f. T6 R# f+ I' g8 A  J! o$ \+ W
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ( B8 [0 r+ Q5 |' A
  84.     / x8 f8 A- ?* q8 _
  85.                $grayArray[] = $gray;    5 J8 S: B9 A( M% b
  86.            }    + H- {0 q# Q# \# n; p
  87.        }   
    0 T" r% ], P2 F7 W2 f7 G) \  [3 C
  88.        imagedestroy($img);   
    . h/ U! a% g, \/ U% t
  89.    
    2 v: G) t& z+ v( k/ J- l
  90.        /*计算所有像素的灰阶平均值*/    5 c. ]0 N; M/ f7 ]1 i
  91.        $average = array_sum($grayArray)/count($grayArray);   
    * o% h# Z; i5 ?: t
  92.     5 G7 {; k2 }3 I7 G/ x" O7 A! k
  93.        /*计算 hash 值*/      \7 q3 ]9 s; h. i! }, z' e
  94.        $hashStr = '';    5 K) F$ l7 U, J
  95.        foreach ($grayArray as $gray){   
    ! u" m9 J8 K# O/ ?
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ) S' S: ?) k3 F6 `- z$ K" Z
  97.        }    7 B6 s9 y7 ~! B  p8 H
  98.     * G" b! ^1 r6 X5 ]& n
  99.        return $hashStr;   
    3 r2 B; u% a) l; f
  100.    }    " z5 ~6 @: u3 n# J
  101.     5 a7 [& S) J* t7 y* x$ z
  102.     / u  h/ c. f7 ~- I
  103.    /**hash 图片文件   
    ' N5 o6 b1 ]4 ?: y
  104.     * @param string $filePath 文件地址路径   
    / [$ Q/ O9 G" M0 M) T$ H
  105.     * @return string 图片 hash 值,失败则是 false   & V. o. T; x/ T: T
  106.     * */    # Z. r9 S8 {- r, j
  107.    public static function hashImageFile($filePath){   
    / U( b6 a8 c- Q9 Y8 o
  108.        $src = self::createImage($filePath);    6 Q& k/ x  J6 K
  109.        $hashStr = self::hashImage($src);    2 b* X9 r) ^# i0 y/ Y4 A' C+ z
  110.        imagedestroy($src);   
    ) K- `) @, l/ U: u7 u0 e
  111.     ( {% X! l- u, }4 y! P
  112.        return $hashStr;    ! s! F& Z0 f& s/ j, T# A+ W
  113.    }   
    , e4 y3 p: f8 m7 }% l
  114.    
    2 B1 _$ h8 G4 n1 L$ M7 K; L
  115.    
    ) x" v' [5 u* x1 G5 a
  116.    /**比较两个 hash 值,是不是相似   # m  ?( u* F) G
  117.     * @param string $aHash A图片的 hash 值   - E6 K/ d) o5 X4 `
  118.     * @param string $bHash B图片的 hash 值   
    * `( r5 c& i( M  T1 k9 W: l
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    3 e" h% ^+ ]' f$ H+ m7 Z
  120.     * */    1 A4 B0 z: ]" F" [8 r' {5 y
  121.    public static function isHashSimilar($aHash, $bHash){      J5 R" X3 u3 m
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ; U' ?, r8 J2 i5 g* |$ R* s+ L
  123.        if ($aL !== $bL){ return false; }    3 p; }, |; E; [0 e
  124.     + u- V5 Z* Y3 D3 w
  125.        /*计算容许落差的数量*/    ( O7 u5 [% k$ c5 x- r6 ?: N) [
  126.        $allowGap = $aL*(100-self::$similarity)/100;    / K. m5 I; `# w. V3 n# ^
  127.     5 V/ B# o; {! ?
  128.        /*计算两个 hash 值的汉明距离*/    " E+ n1 S: L9 g6 M% Y0 C1 I: e2 u. J
  129.        $distance = 0;    5 a: @  A1 x8 b9 }+ k
  130.        for($i=0; $i<$aL; $i++){    ; S! u+ K4 U$ t- M+ d: o
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    , P+ ~' T7 @4 P: h! r$ [8 Z
  132.        }    ' l5 C* ~5 X8 C. d' G9 l, Q
  133.     ' g6 q" E+ Y. Q! l
  134.        return ($distance<=$allowGap) ? true : false;   
    ! b& R: i# e0 g2 D
  135.    }   
    5 }6 ^  x  h+ X' K
  136.    
    # h' `+ d' X* f7 b
  137.     ; n' ^0 F5 G. t6 @  j/ v
  138.    /**比较两个图片文件,是不是相似   ; f( V- S9 y( i) Q+ Z! t
  139.     * @param string $aHash A图片的路径   / H" d7 `3 S( B
  140.     * @param string $bHash B图片的路径   
    ; W& z  X: D$ A# e( w3 i- m
  141.     * @return bool 当图片相似则传递 true,否则是 false   ; Q, i9 t( I. v" `1 `
  142.     * */   
    : R9 w7 q( s9 P' h5 k" L$ y
  143.    public static function isImageFileSimilar($aPath, $bPath){    ; n9 R8 ?! q4 E, _4 |( S& ]# u$ u; h
  144.        $aHash = ImageHash::hashImageFile($aPath);    " N! N7 g* p, t5 j/ U8 F* _) A) q0 c
  145.        $bHash = ImageHash::hashImageFile($bPath);    ( n5 `6 Z3 [1 v* c, z1 `3 |1 ^+ `. X% A
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    ( Q% m  n! M3 \% f3 Y
  147.    }   
    9 K' O3 ^: l+ D' h8 `* i0 B, J/ V
  148.    
    , O: z, I; L8 b
  149. }
    # ?2 i" D4 X/ m; `6 L
复制代码

. Y" ]; r% Q: X+ W. k( {+ ^/ v5 e  T
3 N) W/ N3 H; i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 23:32 , Processed in 0.084832 second(s), 20 queries .

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