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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
/ O4 |' O  J; z3 O& W0 n! V9 c2 o3 b4 I9 C1 n
" M- b$ R% t7 h0 s
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

+ e$ O% R7 e( V6 h8 b! F$ l6 U
  1. <?php    4 K! z* _6 u: \2 }- s4 J& L
  2. /**   . U* A7 B( A6 P4 V+ u' j
  3. * 图片相似度比较   
    % X( Y" f3 y/ j' M& M9 [
  4. *   
    ! b/ h8 m  @# @" H  z) H, Q
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  0 }( \. U/ T! L
  6. * @author      jax.hu   1 k% u6 y/ {# H7 k; L# K0 B8 y
  7. *   0 U* d3 z. X  K0 F4 ^
  8. * <code>   # m( D1 F& y/ q! s8 b7 I
  9. *  //Sample_1   
    ; N& C5 M3 n7 f1 x
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    7 R3 O) @2 O0 M: e
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    7 M5 S# f. \6 I7 n1 v1 A% m
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    : [1 R0 l" [& S5 ]/ J- F
  13. *     C3 o- a& d# @* F% ~& b/ O
  14. *  //Sample_2   
    1 D$ r9 Z; ^- f$ `# b$ `' n. g( y
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    4 `4 B) [7 \0 q! ^* D3 ^/ f6 h
  16. * </code>   / z: O6 n2 N0 h3 {9 g
  17. */    ( i( d1 j8 K% O" R3 \6 h4 W2 M  S
  18.       O- G0 I% }7 @/ z4 T, `
  19. class ImageHash {   
    1 Q1 P. o) i: x/ r1 E5 P# R1 C- K
  20.     1 e; j$ ]/ _; q" w2 b
  21.    /**取样倍率 1~10     d! k4 n+ K( j. ^
  22.     * @access public   
    # X8 y. `- G  l+ m, |
  23.     * @staticvar int   : w/ l! R8 P# Q2 n) i5 u1 L
  24.     * */   
    0 T+ c* z0 y' {, M" e& w
  25.    public static $rate = 2;    % I, s5 g# ^0 i* c6 E/ ?
  26.    
    8 [: A. W8 J2 x1 H
  27.    /**相似度允许值 0~64   * t7 i+ O. |( T5 X7 v$ F
  28.     * @access public   
    2 y9 ~( a0 K) ?8 Z( V) ?3 V- U% v: X/ R. r
  29.     * @staticvar int   + h) Y( a; }# ~2 b! H
  30.     * */    ! q: W7 x7 n! @- n6 V& E- w+ u8 a
  31.    public static $similarity = 80;    + R$ `: X- h( j- I. I4 n5 T% i( H# H8 h
  32.    
    / A+ ^. w3 ~' d4 a% j# H- W* J0 \
  33.    /**图片类型对应的开启函数   
    + ^; Q3 {# i" v, A
  34.     * @access private   2 {7 D/ V# X$ _5 n
  35.     * @staticvar string   
    & ^! m# l% P' j
  36.     * */   
    8 i; p' h' q% e9 z
  37.    private static $_createFunc = array(    ' I9 y3 Y, r$ {8 s
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ' w# ?- E6 Y& M/ Y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ) o" t% \$ Y8 K2 s4 w3 T4 Y+ A
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    - Y. g% b9 J" _1 ^
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ) L: |% c8 h( @
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    1 A" Z, x' n: B, @2 D; K
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    # Z# E6 O4 ~5 n
  44.    );   
    - ?& h$ O' o4 D$ R
  45.    
    6 s" Y, E; w7 m. B+ g& x
  46.    
    1 M9 r3 @/ n. r1 i6 P5 S) r
  47.    /**从文件建立图片   
    9 i) \& s0 O; `+ |8 s9 p
  48.     * @param string $filePath 文件地址路径   
    - s; m4 f3 G" ~4 L9 m" ^
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ' F: E- f0 {  ?
  50.     * */   
    " i- D% V3 {: x  d9 t1 _
  51.    public static function createImage($filePath){    ; ~5 W+ [4 j* o  K( {* O
  52.        if(!file_exists($filePath)){ return false; }   
    - z- O% s# Y& P% n) ^
  53.    
    ( _" M( ]$ P  N. M8 I5 ]
  54.        /*判断文件类型是否可以开启*/    9 y7 c- P$ F& n+ e& `: t
  55.        $type = exif_imagetype($filePath);    : F/ X+ b$ h5 ~  u2 }7 `
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    # q! h* q+ E" c3 X1 C& j- Y$ I
  57.    
    . U" K& j  |- k# q' h$ Y
  58.        $func = self::$_createFunc[$type];    2 a# Z6 Z! N+ X: o2 B: t& U  V
  59.        if(!function_exists($func)){ return false; }   
    # _, d0 ~4 a) e: }2 @
  60.     ) r) Z" Y: ^  v1 H" }$ I
  61.        return $func($filePath);    % Y7 C9 m+ v) S7 n9 L
  62.    }    " ~" z% W% |% d+ l2 P9 ]
  63.    
    2 {. a; ], P1 m; n' V7 F
  64.    
    8 C1 R% q+ {9 _
  65.    /**hash 图片   
    2 A* E1 m( U, e7 R$ q5 C
  66.     * @param resource $src 图片 resource ID   
    0 G8 `6 p: v1 Q4 Z7 Y  k& E
  67.     * @return string 图片 hash 值,失败则是 false   
    4 [4 }  Z) H7 j; T$ A1 i
  68.     * */    4 Y# X9 L0 H4 _- g2 r- u6 _  v
  69.    public static function hashImage($src){   
    $ x% x4 G! Z: n
  70.        if(!$src){ return false; }    : B9 b- Z1 U# _4 O) t% [4 P5 @
  71.    
    % E# d! K* C7 a; |! L
  72.        /*缩小图片尺寸*/    . O! V9 L# W1 U7 @
  73.        $delta = 8 * self::$rate;   
      a* n0 h7 B. t* j1 o
  74.        $img = imageCreateTrueColor($delta,$delta);    3 q5 q$ B& P/ v6 H- _3 L$ z$ _  P& Q. C
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    3 x8 P. l6 F- G- q! l' Y  O
  76.    
    ) m4 D: Y  w- y% x5 l9 y6 K7 J% I
  77.        /*计算图片灰阶值*/    " O7 P8 u, p" H& s" b8 V) K
  78.        $grayArray = array();    5 }0 c- Y6 Q& }; T$ q
  79.        for ($y=0; $y<$delta; $y++){   
    # L, u8 s- l5 v6 ]# I& ^
  80.            for ($x=0; $x<$delta; $x++){    - i+ G: \3 F& y# e$ U
  81.                $rgb = imagecolorat($img,$x,$y);    . S- e" }  p. S) l+ a
  82.                $col = imagecolorsforindex($img, $rgb);   
    $ ?. c% G# q9 K$ r6 x
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    1 G# C  l4 @! R. G$ P$ s
  84.    
    9 _7 E/ r4 A6 e1 W
  85.                $grayArray[] = $gray;   
    3 c- E; _$ y7 N; _
  86.            }    $ G4 n) {, h0 g- c' D
  87.        }    # i* G$ I' u$ N
  88.        imagedestroy($img);   
      s3 ^1 s4 B1 X' K; _) e
  89.     . V9 `3 i' k7 f1 k8 [& o
  90.        /*计算所有像素的灰阶平均值*/      h8 v$ W2 z4 W7 A
  91.        $average = array_sum($grayArray)/count($grayArray);   
    * f. i- d) y3 K' I
  92.    
    ! D# M5 e( K, ^7 [
  93.        /*计算 hash 值*/    1 Z/ O! P3 I8 U! \' B7 c) \$ N; G1 `
  94.        $hashStr = '';    9 Q4 q/ e! H& [1 y* {
  95.        foreach ($grayArray as $gray){   
    ' Y0 W! X3 X# Q- a
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    4 D" C$ ^& u. }
  97.        }    9 \) Y9 k: x. _+ i% B
  98.    
    9 R" ^. U* c+ Z3 t1 f% S
  99.        return $hashStr;   
    # Q8 S, z2 A+ a" m' ?
  100.    }   
    , Y3 h7 H: T) ~/ n3 h2 g4 P
  101.     ) ~! d: e" W, \  `- m
  102.     $ M4 A, O! b2 R6 _3 {/ W
  103.    /**hash 图片文件   " x8 X8 q5 G1 Z: [5 Q$ h
  104.     * @param string $filePath 文件地址路径   
    6 a& a; p$ Y1 O2 @0 ^; _- A
  105.     * @return string 图片 hash 值,失败则是 false   
      O. X" Y2 D! _1 Q/ j% s* h* u" {
  106.     * */    $ O* w3 [' w! }4 M) d
  107.    public static function hashImageFile($filePath){   
    " T, }) i! p8 Q! m
  108.        $src = self::createImage($filePath);    ' U7 i9 `0 V- H( y1 {
  109.        $hashStr = self::hashImage($src);   
    ( N" o' j' ~. B) a
  110.        imagedestroy($src);   
    $ U1 z9 N0 Q# q$ r
  111.    
    ( r% a8 J! F' h: W
  112.        return $hashStr;      z7 g; ]( z( r, Z
  113.    }    " y1 y) e$ Y( O+ m
  114.    
    * v8 k$ p; o1 s( ?" K( F$ Y, a
  115.     ' b; r, a* v1 k5 Z
  116.    /**比较两个 hash 值,是不是相似   ' G* Q+ \' E2 e+ H' S9 b3 Q4 v' s6 M
  117.     * @param string $aHash A图片的 hash 值   
    ' K% B( d0 Z, w3 T- `8 J6 H1 \- n
  118.     * @param string $bHash B图片的 hash 值   
    2 E" J$ u! ]) P, g- w8 y  Z
  119.     * @return bool 当图片相似则传递 true,否则是 false   / z9 \; g9 n6 j! q6 p, @! Y: ^
  120.     * */    ) ^- h2 l$ w7 M
  121.    public static function isHashSimilar($aHash, $bHash){    # j* J% R" Y/ S  N! o0 G( l
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    + V6 T7 y, U! m
  123.        if ($aL !== $bL){ return false; }   
    ) a' j9 [4 J( I6 K1 s0 [; t
  124.     # M: h" ^) Q/ w9 Y
  125.        /*计算容许落差的数量*/   
    0 J! C6 d: O" Z( l5 c% W8 Q
  126.        $allowGap = $aL*(100-self::$similarity)/100;    $ M' a" e; d( @8 U2 }5 k
  127.       k  T  s) W* g, Z3 W6 O) Z
  128.        /*计算两个 hash 值的汉明距离*/   
    & a9 W5 C9 i: I" U
  129.        $distance = 0;    0 C% R# ~: W& n0 f% g
  130.        for($i=0; $i<$aL; $i++){    * \7 L2 L" W% \5 U2 T
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    3 ~* f, B3 S( d
  132.        }    ) R- m' y& Q5 J! {7 W6 M5 k, n
  133.    
    5 R4 R% Y8 X# |7 B
  134.        return ($distance<=$allowGap) ? true : false;   
    . P2 s! q% D. w+ O  m7 ^3 E/ |
  135.    }   
    1 a9 A) p% I- d/ |, z* q
  136.    
    9 y0 s/ O0 W& W5 }
  137.    
    1 y4 P$ ?/ d6 G
  138.    /**比较两个图片文件,是不是相似   & ?- x; Y  n0 q% t
  139.     * @param string $aHash A图片的路径   
    * r0 h" i0 o3 A6 N
  140.     * @param string $bHash B图片的路径   
    & I. V0 q: p+ C5 t; y
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    % i& A+ y2 M, o2 j: D
  142.     * */    $ n) `  a/ O2 o9 k3 U
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    , R+ J1 x& H3 Y7 `5 i
  144.        $aHash = ImageHash::hashImageFile($aPath);    / Q; Y% L% m& o7 c* d
  145.        $bHash = ImageHash::hashImageFile($bPath);    9 E/ L& d" \# D/ N
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    # b1 I1 h8 j" d' i) O' w  V" w; C3 D& Y% B/ r
  147.    }    ' k) q1 S1 ]3 W" Y5 f
  148.     9 C8 V/ ^$ P% W. J! D  C" ^
  149. }
    5 T* b- g0 t) V: y; w& v# ~. G4 D. e! K
复制代码

8 k( \* x1 q+ ~6 d; }7 M5 U. A, a. ~$ z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:53 , Processed in 0.057838 second(s), 21 queries .

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