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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
. e2 |& m6 P, f# h& Z1 i% F+ }! Q2 D/ U9 X: s! P4 W' c: V
% ]1 C5 }' i+ {
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

$ D" D, U6 I6 p' v5 I
  1. <?php    2 b, X9 B( p! V3 V' m, j
  2. /**   
    , a- w! n. ^  Y7 G
  3. * 图片相似度比较   
    ! [. S, @0 J8 i
  4. *   7 R; Q4 P! S! @5 e3 Y
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ) L( d' Q8 C$ G' J  [
  6. * @author      jax.hu   
    8 Z4 U3 c$ `  z/ j! Y/ W% h, ]
  7. *   6 g+ P; C2 d: T% }5 E! Z" u
  8. * <code>   
    ; X4 m3 T: M3 [7 ]; a& b
  9. *  //Sample_1   
    6 L' N: b: l3 x* u/ @( s4 D
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    3 t3 P. D: g& T7 ]) c- J0 I! m
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    . ^7 N4 z7 w' L% W4 C
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ! K1 p: F" Y6 g8 s  d' `
  13. *   # c- s9 M! k% z, i; ]" Q
  14. *  //Sample_2   
    1 u- C5 z; r9 M3 @7 q' a7 [
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    0 I' A( \) e7 ~# l1 @# R
  16. * </code>   
    ! g5 |) |& V! d5 n, j+ b4 q
  17. */    $ l1 a" O7 q, w
  18.    
    " m" ^7 W7 W& Z% V" U) y6 k% Y1 F
  19. class ImageHash {    / x3 a  t7 _& p' u) y
  20.    
    9 ~# q- `6 A/ c5 W$ ?1 K4 O' j
  21.    /**取样倍率 1~10   
    9 _$ o9 `1 y9 z
  22.     * @access public   
    % C6 X2 }# y  I' Q' O
  23.     * @staticvar int   
      j* U2 i4 f5 z: J! i
  24.     * */   
    % g$ U. X- p' l& S$ x& P4 O
  25.    public static $rate = 2;    " n$ R" n; l5 m+ d  }9 h$ j
  26.     ) f6 s7 S; ], U  o
  27.    /**相似度允许值 0~64   " m" U9 ~+ c% V7 N$ h, b
  28.     * @access public   
    4 N, D& R/ [$ V8 w6 K9 m$ r
  29.     * @staticvar int   
    & M; a0 @$ `( u7 v% Y  k1 M/ Z
  30.     * */    . X& M: T1 e+ {$ a4 [% Y7 G8 a
  31.    public static $similarity = 80;    , M8 B  j3 h) q
  32.    
    1 V0 T9 e. K) z& ?) r- ~
  33.    /**图片类型对应的开启函数   1 y2 f# j  w2 H. w
  34.     * @access private   
    & _; c6 \4 |) {1 i- B
  35.     * @staticvar string   ! G' [1 E4 m4 y. E2 M
  36.     * */   
    8 _$ y: ?/ F) m
  37.    private static $_createFunc = array(    * ^0 Z1 a& I% e8 y# |4 f
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ; _9 F6 T  r: l6 r! v6 ^$ o
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    / G1 o% t4 x$ x, m% Z( [
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    9 l3 u; T8 x. E. d8 u* D- E
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ( l3 j! [: ?( ^% e, X% T
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    / Z( v, |  a" K3 _
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ; [: Q' V2 q! m2 B
  44.    );   
    3 q, e6 f8 q: L$ X* L) |
  45.    
    9 S8 J% ^( w' Q2 H  j' Z( w
  46.    
    5 a$ b9 z1 N7 w  R0 H( S7 J# H& k: ?
  47.    /**从文件建立图片   . V1 ~4 c' {% }0 b* x1 \' O0 u
  48.     * @param string $filePath 文件地址路径   
    ! G6 Y2 m. o7 l  U% ?
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ) u5 Y( B+ ^9 ^4 P
  50.     * */    ! Y5 |( `2 n+ Z9 b5 k" s! W/ v
  51.    public static function createImage($filePath){    " o+ w5 l7 |( F5 o2 \
  52.        if(!file_exists($filePath)){ return false; }    0 E" j" {5 T" B! M
  53.     ) z/ D- l1 S7 b4 k9 A
  54.        /*判断文件类型是否可以开启*/    . T. I4 e" h" D! R: W% z  W
  55.        $type = exif_imagetype($filePath);    1 F# r/ D- t, s5 X
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    7 k/ q* e9 m" H1 r( N9 C+ o
  57.     6 V2 T3 G' K% r7 ?
  58.        $func = self::$_createFunc[$type];   
    3 v2 z& t. F- ^5 Q4 w
  59.        if(!function_exists($func)){ return false; }   
    " Q! I" m1 U0 I2 D7 N
  60.     $ O% @! y1 _+ L: N
  61.        return $func($filePath);    8 y0 V8 u0 a* {/ |
  62.    }    * b- F6 N/ w, h
  63.     4 Y0 Z1 h. u3 N  y& G
  64.    
    8 M7 a/ F1 q. h) C* p- |
  65.    /**hash 图片   
      ^& T4 n( R# s$ m5 J. W% g
  66.     * @param resource $src 图片 resource ID   " u/ Q3 t# L9 F2 }% \0 g
  67.     * @return string 图片 hash 值,失败则是 false   7 O) y9 Y- g1 s( E
  68.     * */   
    + c9 _. H3 e" N% ~0 z
  69.    public static function hashImage($src){   
    * @5 Y% E$ J% m+ ]+ ]* H
  70.        if(!$src){ return false; }   
    ! W( a( I" ^) W: F
  71.     % s6 ?) r% h7 ?8 l9 ~
  72.        /*缩小图片尺寸*/   
    , R9 J; E% r  T* w5 F. o: n
  73.        $delta = 8 * self::$rate;   
    1 e2 @, W5 [: c: _* n/ i4 A% q
  74.        $img = imageCreateTrueColor($delta,$delta);   
    - s/ p( g4 X5 s
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    2 W1 S1 y5 c% t
  76.    
      ~4 {* M& |" |# T9 d
  77.        /*计算图片灰阶值*/   
    , g2 n& [& F2 x8 K# X
  78.        $grayArray = array();    ( U" q. C7 b3 ]) u# t4 t
  79.        for ($y=0; $y<$delta; $y++){   
    # w1 x6 W% s2 o4 f. \6 f& n
  80.            for ($x=0; $x<$delta; $x++){    - `/ h+ J! |* d% `
  81.                $rgb = imagecolorat($img,$x,$y);   
    % ]! o& W$ K% d, ?+ t- \7 w
  82.                $col = imagecolorsforindex($img, $rgb);   
    : n( F7 U. n; S5 I, {8 C: J
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ! p$ T# o% P4 ~
  84.    
    9 _- z+ X( j: z6 `& T' _" J$ t8 i
  85.                $grayArray[] = $gray;    % @, F# R: S4 H1 V- I9 t
  86.            }    4 H. A& b% E. l: Z2 K+ Z" z) @
  87.        }   
    1 P0 I# x) W  x9 K. n1 D$ g
  88.        imagedestroy($img);   
      d" y3 f6 _" s, \9 d, O  u
  89.    
    2 S/ U- N) @, L) M2 G6 a; }4 n8 k
  90.        /*计算所有像素的灰阶平均值*/   
    ' L+ k" l! ~* n' ?* }; a8 [% {
  91.        $average = array_sum($grayArray)/count($grayArray);    $ a8 R/ E1 R3 T, @+ N
  92.    
    # `- O6 Q0 P+ `' Z
  93.        /*计算 hash 值*/    4 g9 f/ i! K/ o* L& a" S$ w
  94.        $hashStr = '';   
    8 X, v+ `2 m3 V3 z3 t# E$ O! O) t( k
  95.        foreach ($grayArray as $gray){    1 W- t) U+ p* E7 C" o% ?
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    " `! [& h6 ]% n6 F
  97.        }    & T4 M# [. U: b2 {
  98.    
    7 e5 |1 n* E1 j2 }+ X
  99.        return $hashStr;   
    , M5 ]* w" @; K, n8 S6 ]
  100.    }   
    9 ]/ T. F( q9 G
  101.    
    / g3 C1 V& o* _
  102.    
    % n0 S9 u6 I) d$ t" k
  103.    /**hash 图片文件   : n. v/ m) W: @& r5 L
  104.     * @param string $filePath 文件地址路径   $ s' m0 D2 x9 E1 Z+ g* w, j
  105.     * @return string 图片 hash 值,失败则是 false   ( Q- n0 I: I4 q" Q' a* ]
  106.     * */   
    : n* {  O3 H$ f- U& {! t
  107.    public static function hashImageFile($filePath){    $ R/ ]' C, x7 E5 J
  108.        $src = self::createImage($filePath);   
    * f' e& S+ p. t$ `
  109.        $hashStr = self::hashImage($src);    ) o" Y1 S% t& R$ A! G( e
  110.        imagedestroy($src);    ! p! Y8 D- C/ e) H+ o% Z/ e
  111.    
    ( K, E- r4 h# S  Y
  112.        return $hashStr;    ' J  l& h4 G; g" B
  113.    }    4 C, K, ^# Z: r# C# m* u4 @$ E
  114.     + G5 x" D) c6 ~. W4 b
  115.     0 J6 W& J- y  f( B) N6 z
  116.    /**比较两个 hash 值,是不是相似   + r2 A8 W% U& c+ F6 H
  117.     * @param string $aHash A图片的 hash 值   
    ; i  B% h) p2 U  q4 m8 D' e  T0 s
  118.     * @param string $bHash B图片的 hash 值   8 u) K  ~$ \5 D8 F( ~% N
  119.     * @return bool 当图片相似则传递 true,否则是 false   . F1 I0 U' ~; M
  120.     * */    ( h3 ?6 K6 m% ]
  121.    public static function isHashSimilar($aHash, $bHash){   
      w! m. N2 n7 T/ U! \5 G
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    " Q8 d+ ~7 D; u7 R
  123.        if ($aL !== $bL){ return false; }    3 \' B9 u; s# d( T3 @- N
  124.     0 G  m! {4 k" v( b9 J% r
  125.        /*计算容许落差的数量*/   
    % p" `0 Z! Q( F0 C7 o
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    , }( n4 d6 W8 {0 E- e0 v* R
  127.     1 j- D7 M0 v% U9 W. Z* u/ @3 t
  128.        /*计算两个 hash 值的汉明距离*/   
    * {( G# r) \+ y4 k. y( Z
  129.        $distance = 0;   
    ; [/ Q( k6 v2 B5 i) {
  130.        for($i=0; $i<$aL; $i++){   
    - D3 I* P* N' |, `+ V, V! [& ?1 I
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    % N5 ]4 M8 W1 S; C- u
  132.        }   
    - L# U5 x& S* C) v. x  y* b2 C
  133.     3 [) }6 V, `$ c. l5 V- I
  134.        return ($distance<=$allowGap) ? true : false;   
    # b7 }9 Y( W5 p
  135.    }   
    ' s/ |, z% e% L; O$ f% L! x
  136.     " A5 m' V6 y2 ]: V
  137.    
    ; ^" d' |( x: z$ x. E, L1 i
  138.    /**比较两个图片文件,是不是相似   + p& F  T2 X- U6 E. ^9 e8 V
  139.     * @param string $aHash A图片的路径   
    . B9 D2 K/ v# v4 B% n0 z
  140.     * @param string $bHash B图片的路径   ' |% l- e0 J& ]% i/ m, o  A3 d2 d- W
  141.     * @return bool 当图片相似则传递 true,否则是 false   ) M* p# y4 ]1 y3 x0 \, x
  142.     * */    5 j; B3 O+ w$ E, L& e/ u4 s
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    + N! s% J! U: T: F2 J
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    ) A. L3 k! W, i  w: p
  145.        $bHash = ImageHash::hashImageFile($bPath);    7 M: A6 z0 p/ q% I6 H
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    ; W. ?% [# ]4 }
  147.    }    ! _: C, L0 b: `/ E
  148.    
    % g3 G9 [9 M2 k: H2 O) q
  149. }9 q4 Z) ]4 O7 E
复制代码

3 ]6 k" J/ |0 p) A* U. w* b. W0 K! D& a; ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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