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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

, |7 D' o: V$ w' e* f; q( M由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

7 ~: W( F! E$ |9 M& `9 U# v
  1. <?php    & _. C; X. ]* C% A0 K- t
  2. /**   3 I+ {& v% _7 m$ ?$ g
  3. * 图片相似度比较   % t: x" p+ \6 p# ?8 u$ [) H- V
  4. *   % p6 v6 V9 U. T! a& s+ K
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    5 ]4 {/ o: k5 t  V8 w4 X
  6. * @author      jax.hu   - Y2 F6 z2 n  @5 S( u
  7. *   9 _- {& l& Y" r4 f
  8. * <code>   
    0 I: Q; e, t$ S  ~6 ~1 j
  9. *  //Sample_1   
    . h2 I5 g9 M) ]
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   9 g8 R3 Z# a  l6 u- h
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    & |+ o1 b: E- s
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ' r8 f0 ~1 e9 @: c& s8 ?
  13. *   
    ! c8 k- m+ N5 J1 \
  14. *  //Sample_2   
    ) k, |- s& E+ C% l7 z$ Q4 W. w' S
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    ! H# J- m4 |8 W; h, t
  16. * </code>   
    ; u) u) H  F$ q
  17. */    , Q* {' W0 N, \' m
  18.    
    0 U" M. n& u; z/ X
  19. class ImageHash {   
    ; @; ?' j9 x$ \# D5 q2 q
  20.     # N% @+ p; z/ E
  21.    /**取样倍率 1~10   
    : i! U' K$ F5 ^3 B7 X! i8 e
  22.     * @access public   
    , U* L' N0 }' i* ~
  23.     * @staticvar int   5 H8 w& ^# W, v4 Z  i5 J
  24.     * */    7 k5 i7 h$ w% r* w4 s8 L
  25.    public static $rate = 2;   
    5 D- }* ]2 M* u* c" h# G
  26.     & O0 G! ~  `& g  \1 H
  27.    /**相似度允许值 0~64   ! @6 E! v% s7 H6 y6 l& ?5 ~) r) L+ I
  28.     * @access public   / O$ B. @7 E1 @6 u1 ~6 M3 H
  29.     * @staticvar int   1 l$ X. S0 K+ c9 S
  30.     * */   
    ! e5 @; X9 E( w' F0 K  J
  31.    public static $similarity = 80;   
    1 S: T. l2 R1 G  m# M6 R- M2 s
  32.    
    + z% I. c, {$ k9 ?' J8 }
  33.    /**图片类型对应的开启函数   & H; Q+ `  {% h: v% [  W
  34.     * @access private   0 h/ ]+ ]9 }* |3 G& j8 \: q" m
  35.     * @staticvar string   
    # e/ |% U4 |9 T, ^6 w6 l6 R$ I
  36.     * */    0 F' T+ o- b) [7 V7 x* N
  37.    private static $_createFunc = array(   
    / @: c2 r. r. d" n: ~
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    7 K; `" \3 y0 e+ U$ A
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ' c$ B$ g3 ~% u$ t& Q6 m
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    - ]# P9 O- r& J7 w( _# Z
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    + `7 [, ]9 W/ Z( L
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    ' E7 p! Q; h/ ~( F3 S- G
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    4 t% o4 m8 ^' Z$ p8 X
  44.    );   
    9 A& o2 o4 w, X+ Z; g
  45.     7 L, ]$ ]5 }4 n6 B5 U
  46.     ' V( d2 R, Z& i! Q  S
  47.    /**从文件建立图片   : `( T, w+ H2 B8 x5 ]/ n
  48.     * @param string $filePath 文件地址路径   
    & l* G, w) o" x+ R2 ^
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   # B  n+ l8 a: Z
  50.     * */    & b" @0 s% I* |/ V8 S1 s
  51.    public static function createImage($filePath){   
    & ^8 x6 E& u' b5 u$ m* S
  52.        if(!file_exists($filePath)){ return false; }    # x9 h  u9 W  p0 ~; [
  53.    
    6 @( }: N: G0 Z5 _5 e
  54.        /*判断文件类型是否可以开启*/    0 ?- E+ b8 T& Y9 L
  55.        $type = exif_imagetype($filePath);    - G7 S- o, n8 e3 E. l
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    / r5 j# n* E7 X# m2 k& }
  57.    
    5 z# e* {' E) z
  58.        $func = self::$_createFunc[$type];    - U3 w6 t4 a1 |  I% }% C( R
  59.        if(!function_exists($func)){ return false; }    - z% m; J1 n. j: m9 ?
  60.     ) z8 |6 F! C7 h3 ]0 H/ s9 K
  61.        return $func($filePath);   
    7 B1 M8 T& B) F+ c2 z. \
  62.    }   
    # i- F' d  m7 b6 v0 F) u% b  w; Z
  63.     7 {5 s' i1 `" Z% i7 d. `& P- y
  64.     $ G2 }, L& ]- Q& X2 Y
  65.    /**hash 图片   
    : n: ^5 U) \& O  i3 ]
  66.     * @param resource $src 图片 resource ID   
    4 A0 O  F/ ?7 f8 {7 S9 ?$ u* o
  67.     * @return string 图片 hash 值,失败则是 false   
    $ H/ I0 e: ?, W+ G8 m6 P
  68.     * */    0 K0 l- @4 F& y: ]- I7 t# E8 b- `
  69.    public static function hashImage($src){   
    * z) o1 m' R1 \' G0 L7 n8 D
  70.        if(!$src){ return false; }   
    + s5 D" P1 X1 Q
  71.     5 R6 e0 U7 ^2 ?* L+ u8 b
  72.        /*缩小图片尺寸*/   
    + ~; {9 P1 v( m# A% k- b" w6 p
  73.        $delta = 8 * self::$rate;   
    7 c+ C5 s& H* c+ V. m
  74.        $img = imageCreateTrueColor($delta,$delta);    1 M- b& u5 y5 P6 K$ Y8 E
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ) P, K! F" q3 H4 s  B+ ^
  76.    
    ' Z* {$ D9 @; r! W) }/ B& X$ m( X
  77.        /*计算图片灰阶值*/   
    0 s$ p8 B9 p' U2 {# e# F; T
  78.        $grayArray = array();   
    ' i- r1 n2 I: A( y9 c
  79.        for ($y=0; $y<$delta; $y++){    3 q0 c, q( r) D/ p9 E& Y8 Y
  80.            for ($x=0; $x<$delta; $x++){   
    6 J5 W+ L7 j/ w4 F
  81.                $rgb = imagecolorat($img,$x,$y);   
    + `( G5 |$ n- ]- Y- B
  82.                $col = imagecolorsforindex($img, $rgb);   
    7 g. S8 \6 y: j% k6 v7 a
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    + p* I2 W& [% Q" N$ l9 s! `
  84.     & Y1 M7 D. J: e, g9 L$ _# J
  85.                $grayArray[] = $gray;    : W4 d9 u0 V  ?, b( D3 t
  86.            }   
    - c- |. M& u6 `" k
  87.        }   
    . j5 ^# l( u) e8 F" c5 Z
  88.        imagedestroy($img);   
    * ~" W4 C% z& F/ k" s3 d) p
  89.    
    ' d7 i8 I0 i8 F3 I6 z  {- R
  90.        /*计算所有像素的灰阶平均值*/    % G9 S% G3 B/ |/ L' F
  91.        $average = array_sum($grayArray)/count($grayArray);    2 `- j. @2 \1 d' q
  92.    
    ( A' ]$ Z, o& _8 E% x* l/ v
  93.        /*计算 hash 值*/   
    0 m7 o- j% r8 I( @$ Z( b# v! T
  94.        $hashStr = '';   
    ; |# h7 R( f4 O
  95.        foreach ($grayArray as $gray){   
    ! F# R! O0 z! I2 Q  _! Y/ _% r$ B8 I7 _
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    7 e6 C5 {8 t: \; _2 ?
  97.        }    7 S* R6 L6 e5 l2 F, k" y7 H
  98.    
    5 A0 q" m- X2 l# v) Y
  99.        return $hashStr;   
    $ l3 i$ f- r/ A) ?: L8 F
  100.    }   
    , N' j  _0 V  w1 y
  101.    
    0 |- _7 j) B: S
  102.    
    ! `$ m+ g; R4 ~. P6 H( N) d
  103.    /**hash 图片文件   ( k& h- e: _& x6 V
  104.     * @param string $filePath 文件地址路径   
    8 n6 {# b' G' ]; G# ^7 y2 b# G
  105.     * @return string 图片 hash 值,失败则是 false   6 k; p. {- N( r/ m5 Q
  106.     * */   
    , U! F6 O* F2 J4 ~1 b4 Q3 H; S
  107.    public static function hashImageFile($filePath){   
    ! l& H7 Q' H5 j
  108.        $src = self::createImage($filePath);   
    9 E/ P: V2 V0 @1 z
  109.        $hashStr = self::hashImage($src);   
    # g  l# U' z7 v  D  \( I5 |
  110.        imagedestroy($src);    , _' W, B# s2 b8 _# Y
  111.    
    , w+ m! H1 e* e. C( n$ ~2 d
  112.        return $hashStr;    1 n9 V. R  |5 B4 L
  113.    }   
    8 x% X. I! a* z! |+ D
  114.     0 i# u% C( c3 r! Q3 p  e
  115.     * o! G8 J5 e5 B  F9 ~* ?9 k7 V4 c
  116.    /**比较两个 hash 值,是不是相似   : p, _2 [3 f3 e% V2 Q
  117.     * @param string $aHash A图片的 hash 值   
    . C/ Z) _4 S9 @1 v* r- {
  118.     * @param string $bHash B图片的 hash 值   ( Q+ B. \- m9 N% h5 r
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    7 k' e' Z& [$ h0 S8 K7 }$ r
  120.     * */   
    7 S6 E% `5 P: y3 M
  121.    public static function isHashSimilar($aHash, $bHash){    & n$ E+ N, a0 _5 z/ N5 Q& [5 y' o
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    2 w3 |: ^3 }7 r9 j
  123.        if ($aL !== $bL){ return false; }    ( [  R9 ~5 ]9 N6 Q) q
  124.    
    0 p% ]6 B4 |. k
  125.        /*计算容许落差的数量*/    , u) k, [: L0 k5 _! u- t
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    + d$ {' {# c' M
  127.    
    ( _+ I. |& H0 B# C; z' k
  128.        /*计算两个 hash 值的汉明距离*/    " }0 F5 G$ q5 ^
  129.        $distance = 0;    3 h5 }% S9 }) L' M* A2 n; t- |7 {+ p2 c
  130.        for($i=0; $i<$aL; $i++){    % m: W! C$ v0 ?6 G
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    + U6 T/ }) {/ |
  132.        }   
    * ?/ j! o) F5 \4 O+ J# H
  133.    
    - {3 ]- u7 L" W
  134.        return ($distance<=$allowGap) ? true : false;   
    & @' {  e) s3 B  r6 b+ c* P  g
  135.    }    : N9 u% T  P& ^- U$ U( a
  136.     - P# U; M. |* n4 S
  137.    
    & F+ G# L$ S& f. \) ~
  138.    /**比较两个图片文件,是不是相似   
    & e5 g3 y' F6 w- e6 ^
  139.     * @param string $aHash A图片的路径   ( H2 J0 e  `8 M' l0 _4 W# a
  140.     * @param string $bHash B图片的路径   $ W# s, I9 u, o" b& M
  141.     * @return bool 当图片相似则传递 true,否则是 false   : [3 l% D8 j3 [! K
  142.     * */   
    1 U& b7 x$ T' `; d- S
  143.    public static function isImageFileSimilar($aPath, $bPath){    + X9 ?2 c* }* }2 w5 l/ B9 X1 c# n/ H
  144.        $aHash = ImageHash::hashImageFile($aPath);    # M; N, [. \7 z2 N* r) o& y
  145.        $bHash = ImageHash::hashImageFile($bPath);    ) ^5 _  a) t; p9 [! w, S9 [
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    9 Z' r5 t/ C! {; I, i
  147.    }      c, a- i% v) p- F% q# j' U
  148.     / \7 f- e8 U+ x" t/ u
  149. }
    8 n/ V& d5 o6 ^
复制代码

, }4 v9 [6 w. Q8 c; R. x% \8 P/ @: o5 V! K4 L& Q& }
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:24 , Processed in 0.051901 second(s), 19 queries .

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