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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" B' `9 L* M- N5 _, g由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
( T' \+ s* b, E( k7 y" D
  1. <?php   
    8 G* k6 r0 A! _
  2. /**   
    ' ?; u. c3 I4 A; ^3 I; M* F
  3. * 图片相似度比较   
    / v9 L  W$ x9 q9 c* l
  4. *   ) \( d' }, r0 T3 a& O: ?- [
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    5 v0 H  O, G' v0 J
  6. * @author      jax.hu   ) j- d2 J, i* A
  7. *   & W- F+ u8 @( a2 u$ H/ ]4 m' Y$ Q
  8. * <code>   6 k9 Z( n  z: F
  9. *  //Sample_1   
    5 d* m0 Q. P4 }
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   - O/ V2 s/ t; C( E9 W0 l% X
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    / ]% H: q; n% g/ E. w. h  }
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    7 s4 r" n& ^- t  Y$ {; l1 k
  13. *   ) q6 j2 p0 M5 `9 o
  14. *  //Sample_2   6 J$ \# [3 p. T. i
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    9 z! Z" E( T! b! E
  16. * </code>   3 N6 R6 w& W+ z5 C8 F
  17. */    9 J5 g5 b& G/ @3 Y
  18.     ( F7 ~% j, w  u% E0 R7 m
  19. class ImageHash {   
    6 _( u, d9 c4 v3 ~
  20.    
    4 D6 g( L% l  i# ]' {/ Q
  21.    /**取样倍率 1~10   2 _9 ]! o+ C0 {/ z" ?
  22.     * @access public   $ R# A  P, n' x& i$ M8 I1 f
  23.     * @staticvar int   
    $ V/ ~1 |/ W! j5 q+ }; v
  24.     * */   
      S3 \0 `, ]; z
  25.    public static $rate = 2;    1 h' ^3 `1 _8 \( c& C" p5 O  g( V
  26.     - ^+ }5 V8 \" l  i! n) H+ ?0 A: j
  27.    /**相似度允许值 0~64   
    + g+ ^: L$ e& V0 u# Z
  28.     * @access public   
    6 ]6 I- r; h; _/ X' N
  29.     * @staticvar int   
    4 ?6 `9 G5 |: i/ u1 D. C
  30.     * */    2 a3 }0 k2 r4 O, c8 j
  31.    public static $similarity = 80;   
    " x  m" S9 H  j5 M# ]8 e. B
  32.     1 `( q" {5 J. j7 M
  33.    /**图片类型对应的开启函数   ) T0 ~, l! T5 k1 `7 _
  34.     * @access private   + u( F" A- X8 _& P  l  Y
  35.     * @staticvar string   : P* e0 h# F4 w% V- |% L, Q
  36.     * */   
    0 e) s4 a) k2 _' ]: [+ p" |
  37.    private static $_createFunc = array(    / Q& J( ^7 C* i% g' h$ j% r
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',      G; G' i) o) U7 q$ t
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    * p2 j6 y! `6 L! x, ?
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    - r1 e  X% x: q/ d. r
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    $ x* ^2 X% _% H1 _9 S8 R" X1 ?
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    " h( d: C3 \: ]6 j3 \+ w
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    - J/ j' b$ Y: h  A0 k
  44.    );    $ c9 f* z$ r2 v  p
  45.     - A+ D9 g  [7 e) w8 l6 f+ l4 I& i
  46.    
    & y2 i0 X/ A$ J8 k# n
  47.    /**从文件建立图片   ' z, L* g/ t+ e% M7 q/ }/ d
  48.     * @param string $filePath 文件地址路径   0 o9 K" S" ~9 H; H, Y% Z: A
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    0 p3 K9 l' k) {7 g3 C+ E0 F
  50.     * */    $ S# g9 y. a5 F; F2 f' t. J1 h
  51.    public static function createImage($filePath){   
    9 U7 W, V8 t) }; s! z5 c
  52.        if(!file_exists($filePath)){ return false; }   
    - Q1 O! [! S" F
  53.    
    5 T& n8 K: Q) ?8 ~8 ?" j
  54.        /*判断文件类型是否可以开启*/   
    : D$ K; i  l/ y. `
  55.        $type = exif_imagetype($filePath);   
    3 G* ^' r9 L0 _
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    9 g, A$ M0 ]6 N% Q" X
  57.    
    1 n- G) V: Y2 t
  58.        $func = self::$_createFunc[$type];   
    $ S0 o8 ?& ~) x0 m0 `
  59.        if(!function_exists($func)){ return false; }    . u5 N' ^8 g) G% n
  60.     - l, f1 R/ m1 T8 p
  61.        return $func($filePath);   
    * d6 t  F" h9 W2 g7 R6 z" |0 a
  62.    }    : I+ I: W# Y% N
  63.     8 L' }) i3 I( ~) i, h( N8 p. T
  64.     * f; H. I- b" L# J1 W3 w
  65.    /**hash 图片   
    ) k4 K" j" S. V! E6 o/ r
  66.     * @param resource $src 图片 resource ID   2 d& @" w) L- Q& `1 |
  67.     * @return string 图片 hash 值,失败则是 false   
    8 f; M( t+ T. _  n
  68.     * */   
    6 F1 T- G6 Y: D" d: q
  69.    public static function hashImage($src){   
    ; g/ c+ G) X1 d. A4 ~4 k( [# f
  70.        if(!$src){ return false; }      J) N7 Y& n, A3 K. y/ m9 Z' P! B
  71.    
    & P3 J; e  X2 p
  72.        /*缩小图片尺寸*/    , j! x/ Q6 H0 G& l
  73.        $delta = 8 * self::$rate;   
    0 w5 {2 Z6 }: O+ e! G0 _: W
  74.        $img = imageCreateTrueColor($delta,$delta);   
    , p" v9 G$ Z5 p! O, j; d& k
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    " V3 J; W% K' w6 m9 d
  76.     8 a( P6 s( r' a& \9 ~8 f
  77.        /*计算图片灰阶值*/   
    5 r+ a' \  U, p* _2 v6 `1 Y( P
  78.        $grayArray = array();   
    8 V2 C4 w. r& O: s5 `% h
  79.        for ($y=0; $y<$delta; $y++){   
    0 B8 S- f+ q; n
  80.            for ($x=0; $x<$delta; $x++){    % E7 _+ k" V2 H3 z
  81.                $rgb = imagecolorat($img,$x,$y);   
    ) o( z, k1 x5 b* x
  82.                $col = imagecolorsforindex($img, $rgb);   
    9 m8 [  x5 G, w5 h$ @  Q& Y( Y
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ) i6 a  O- A' U! I5 K' X
  84.    
    / {' e4 x0 J4 S! A: X1 p4 c
  85.                $grayArray[] = $gray;    + ^% H! u& `8 e3 i) t
  86.            }    . \2 V% J5 z5 j! K+ A1 ^
  87.        }   
    - o4 N% Q$ N9 T* \  M
  88.        imagedestroy($img);    . u3 X+ m0 }9 ^6 C5 R
  89.    
    # p% c9 c( e! U' m  o) N
  90.        /*计算所有像素的灰阶平均值*/   
    8 p3 e4 g: v: m; Z! e9 I9 V7 F
  91.        $average = array_sum($grayArray)/count($grayArray);   
    5 U& i' I* M- z1 D& T# i! [
  92.     4 b  F* P+ Y. p
  93.        /*计算 hash 值*/   
    ( v; _! h' K3 e( Z
  94.        $hashStr = '';    7 Z# E9 H3 \& Z, K
  95.        foreach ($grayArray as $gray){   
    / d1 U; H# k8 T9 B$ U
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    7 ]' r$ J7 j2 G6 \# w# o
  97.        }    1 d9 _$ {# x) h' z9 c6 Y
  98.     & d* o% ?# P8 E2 Z! c
  99.        return $hashStr;   
    3 F, N0 k( z9 k0 N- ^* K6 [. h
  100.    }   
    4 v2 b. L' J4 J: C3 K/ a+ ~# t
  101.     ( U2 s. Q0 y" Y: S4 n
  102.    
    ' j) a  ~$ x2 C% C( ?0 j9 P$ E
  103.    /**hash 图片文件   
    1 C. Y7 c+ @+ ^* C, a# o" P1 \
  104.     * @param string $filePath 文件地址路径   
    % B0 j# s, V' I  z5 b$ j& e1 h3 r
  105.     * @return string 图片 hash 值,失败则是 false   
    3 u* l: k$ n. ]! q+ {. k
  106.     * */      U2 ?; r5 m8 ^- w; T* C
  107.    public static function hashImageFile($filePath){    % T! u4 l! \& C8 x, @. p
  108.        $src = self::createImage($filePath);   
    : f) K; W- {) P& g! ?) \4 |9 z
  109.        $hashStr = self::hashImage($src);   
    , |* j: F0 U" \0 u
  110.        imagedestroy($src);   
    $ d) K6 h: g% W* ~# D
  111.     8 R% h$ c; ^, e; K4 X* p, x& M
  112.        return $hashStr;   
    $ H  S& W: _6 K9 Y& ]! ~
  113.    }   
    ! P$ S1 U# P( c! x% h
  114.     & _5 a! O( n/ |( w& u
  115.       f, m2 n* p8 E( t
  116.    /**比较两个 hash 值,是不是相似   * C" h, x+ m7 C1 L& {/ \4 ^! k
  117.     * @param string $aHash A图片的 hash 值   - y( H" o$ f" Y* Z- H( Q
  118.     * @param string $bHash B图片的 hash 值   - o  @/ A1 I" v* L5 J" u
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    2 K  b5 }5 m  G: y7 O6 |) V
  120.     * */    + I! M5 X! q8 v7 Q) |  m" `. R
  121.    public static function isHashSimilar($aHash, $bHash){   
    - k" I8 f4 q+ t# w
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    $ w, O! @2 b* r. a* v. Z3 n' g
  123.        if ($aL !== $bL){ return false; }    8 F3 B$ }  V1 {/ L5 u6 t% z
  124.    
    - X4 V7 O9 f# R7 [: f% p
  125.        /*计算容许落差的数量*/   
    , G( f+ T4 R. |/ \/ j
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    $ N4 K% s' q% s0 y
  127.     8 A+ ~4 \* ~  e2 k
  128.        /*计算两个 hash 值的汉明距离*/   
    ( j/ |! _/ D( S3 d
  129.        $distance = 0;    ! i3 |+ c" l7 a1 I1 \, l! U' t
  130.        for($i=0; $i<$aL; $i++){    ( G" k: E( @; ^6 [
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    7 R( v/ Z! X, o3 z
  132.        }   
    4 l/ p; f7 o+ O! K. \: i; ^  F
  133.    
    : w9 y, ?* y1 U) U/ L. h5 q: G
  134.        return ($distance<=$allowGap) ? true : false;   
    ) j( E% u" ^8 e) Q+ {. K
  135.    }    - x. }/ Y5 @. \& [2 o; m
  136.    
    ! q* q+ ]) K2 \6 W5 r5 L( Z6 x1 }
  137.    
    4 t0 A) G6 I) f) a
  138.    /**比较两个图片文件,是不是相似   
    & h7 C+ t) u1 F: i4 s/ F
  139.     * @param string $aHash A图片的路径   
    % ?1 `' B$ R7 v9 R, _! w
  140.     * @param string $bHash B图片的路径   9 C$ t" Z1 F) g- q- o% v/ s
  141.     * @return bool 当图片相似则传递 true,否则是 false   $ ~, x/ `5 P( F# _2 A% z
  142.     * */    $ j; `9 T5 c& k3 ~: Y" d
  143.    public static function isImageFileSimilar($aPath, $bPath){    ; \8 Y% `' W/ J  [% ~
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    7 U: d/ `; o: B+ E, i
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    6 B9 y, l- F9 U! ?* R1 L
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    . G2 p3 ?( Z1 ?7 Y) ?" M
  147.    }    ' g, {( ?) I; P3 G
  148.     * S9 b7 Z8 n9 o! ^% ]
  149. }* B' B) F& l* L9 _7 L0 J( e
复制代码
1 q- c: G) z  F8 a) o( J
! T) ]: m' ?7 t2 j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 04:17 , Processed in 0.078012 second(s), 20 queries .

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