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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

1 ~1 ~  [6 k! E2 n  {
3 q2 C5 ^) h& J% j# ^0 T
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

! v, v4 a' ^/ n9 a) M
  1. <?php    4 F7 X, Y7 Z+ d
  2. /**   
    % y+ Q  ~* x, [# y  `% k+ ^3 k( y
  3. * 图片相似度比较   + s; _5 P& ~8 a8 g" K6 g6 y
  4. *   9 D. ^0 O0 R) k8 E  I
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  & ^$ g! E, F+ Z/ T/ M9 N/ \) O* p6 ^
  6. * @author      jax.hu   : u8 }( B" B% t* s3 n2 x! K
  7. *   
    . B' [  }8 N! u4 w2 ~6 Z
  8. * <code>   . N3 p) G# }+ ^5 v
  9. *  //Sample_1   0 O5 j& B) ?; d1 V
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    3 C$ M/ g. k% U) n7 P
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ) B6 s3 ^4 V+ D: H+ Q0 ~
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    8 Q5 ^7 D# t2 ^
  13. *   
    $ u1 I5 _1 Z& V& d  b0 D) C0 u0 h' U
  14. *  //Sample_2   
    8 C" ~$ O2 _. A: n$ w
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ( |/ U( P+ ~. t# c; _7 c1 ~
  16. * </code>   7 }0 i* W: Q/ W1 f& x# w! a4 d
  17. */    ) m8 ?/ w/ z2 J
  18.    
    1 b' v# ?. I3 r$ o
  19. class ImageHash {    ( y/ X$ R, p) w& B  r, r" b
  20.     1 F5 l- T5 K% b" e# z! \0 _; N
  21.    /**取样倍率 1~10   
    " i0 b# M8 ?2 P# P; M- @
  22.     * @access public   ! F4 d0 a8 k- }7 E! b
  23.     * @staticvar int   
    $ u7 ]: a( x# h9 i3 h
  24.     * */   
    - M( T% \8 L3 g9 G2 ^/ o: q
  25.    public static $rate = 2;   
    6 o7 {5 z6 N" W
  26.     2 @! H% q& C0 d0 z: z+ F: B
  27.    /**相似度允许值 0~64   7 R1 g6 J) e- o% Q# u5 }$ q: d# r
  28.     * @access public   2 K. X' f( f' z/ u  |/ k  w& d
  29.     * @staticvar int   ) p; h# Q8 V% J) ?
  30.     * */   
    + B& W, x  Z, g2 n5 i
  31.    public static $similarity = 80;   
    0 N$ D1 {1 G2 {6 l
  32.     ) U/ d6 G* K  `7 W/ j
  33.    /**图片类型对应的开启函数   
    # O3 N& [$ w. U' \
  34.     * @access private   
    5 L; b3 d% e( l8 i9 J
  35.     * @staticvar string   0 `9 q4 G- r$ h' r' _1 L
  36.     * */   
    * E4 l, @4 l0 Y# i& k& _' f' K% J, u
  37.    private static $_createFunc = array(   
    % b( D  F' v$ |: j0 Z
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    7 N8 Q7 b- ]& x) ?' x" P+ [: M8 s$ e' B
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    $ m# V/ t6 B- |. _" D) a
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    ' g1 |- u* e+ l
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    / y/ x) V# P- x! y: E" L+ |. Q
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    5 T  X, e; v. ], ^: Q8 t
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    2 ?3 c6 k7 \; {) }. i7 |) A
  44.    );   
    " G9 U) e1 e# u  o" a2 b3 t( G0 i
  45.     9 w# P# D* X! J# I6 w  B
  46.     2 v7 a5 i6 R9 |% y
  47.    /**从文件建立图片   
    9 l+ N/ o; Z. D0 p
  48.     * @param string $filePath 文件地址路径   % V+ r3 r& J; W
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    " j7 t8 e5 X1 a# @! s0 T+ @/ ?
  50.     * */   
    . {2 K& X# g* ], u( p  n0 z3 l8 ~" g
  51.    public static function createImage($filePath){    & o( W( P# L5 V( w8 V# h0 v# y
  52.        if(!file_exists($filePath)){ return false; }    6 R1 U$ g& N* @' _9 ^
  53.     / J8 F" r9 s4 @( c* d" ~
  54.        /*判断文件类型是否可以开启*/   
    8 a& o& \) q4 ?, X% i
  55.        $type = exif_imagetype($filePath);   
    5 J/ H. n! \) x. V$ H0 A
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    , {; d& b; ?7 M
  57.     6 a" G7 |1 b; p; S- e% l) K% b) [
  58.        $func = self::$_createFunc[$type];    ; T$ `+ d5 m: w! l
  59.        if(!function_exists($func)){ return false; }    # Y0 b4 W) ]$ ^  a, P2 C" L
  60.     ( e2 D7 a' s7 _; ^6 o, @
  61.        return $func($filePath);   
    ( B: {4 t" ^! y6 h  _: F' J9 m9 s
  62.    }   
    ( L7 R7 }$ z9 @% I6 A( n- i
  63.    
    4 E$ g$ w, V8 ?7 |0 Y
  64.    
    2 `% K" o- U7 A4 \8 ^7 g! B
  65.    /**hash 图片   
    , {  _% v/ p9 _/ N3 P, q
  66.     * @param resource $src 图片 resource ID   
    , M3 {0 A# N9 Q5 B
  67.     * @return string 图片 hash 值,失败则是 false   ( z7 h/ t' c' N* Y: [9 y% A7 V, P6 f
  68.     * */    " K' p( u. h0 l5 d
  69.    public static function hashImage($src){   
    2 x9 {' p4 K" f. D1 Q
  70.        if(!$src){ return false; }    8 c7 q1 B+ \, H6 ^) Q
  71.    
    ; b( Y2 y# E* x6 {( b( l- _
  72.        /*缩小图片尺寸*/   
    - x" q  P+ F8 ~2 {
  73.        $delta = 8 * self::$rate;   
    " ]  }- k6 R5 U% h2 ]7 B* q4 c& J
  74.        $img = imageCreateTrueColor($delta,$delta);    1 t3 d3 [9 D* S, [5 m' a
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ; o) G  C5 X" `  i* `+ l
  76.     7 k4 x( p2 [, W6 U
  77.        /*计算图片灰阶值*/    % f4 U# O+ u6 C2 d9 O6 A( v
  78.        $grayArray = array();   
    ; k0 E2 m' f2 H) z
  79.        for ($y=0; $y<$delta; $y++){    % B: Z3 t. x. E+ Q' ?- A' n9 ]  h6 P
  80.            for ($x=0; $x<$delta; $x++){   
    1 l5 A- z0 k$ y" W! z) [$ q$ u
  81.                $rgb = imagecolorat($img,$x,$y);    ; X" o* k4 e6 U
  82.                $col = imagecolorsforindex($img, $rgb);    ! a- u* r6 G! \6 L
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    2 u- ?* E/ o7 x& d0 i
  84.    
    0 v) S2 k3 e3 b8 g+ q
  85.                $grayArray[] = $gray;    + @4 d1 J! y& s
  86.            }    $ z  S* o  \" Z0 d" e
  87.        }   
    # {/ B/ n1 R5 w. b% R4 y
  88.        imagedestroy($img);    7 P2 z( y& E' H3 a
  89.    
    ! U! ?# I( {0 V* D4 ^( U% |! r
  90.        /*计算所有像素的灰阶平均值*/   
    / g- M9 E* y) ~! y0 }
  91.        $average = array_sum($grayArray)/count($grayArray);    + `: H$ {4 ?' n1 ^
  92.    
    2 {$ d0 b' `* b* h9 _% v
  93.        /*计算 hash 值*/   
    ; b) }8 k& `: O# I: ^, G
  94.        $hashStr = '';    8 W  d) H/ ?/ O5 k, s  ~4 i
  95.        foreach ($grayArray as $gray){   
    4 m+ l; {/ L1 ^, a( G9 J+ `; B& @7 e
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    2 T4 E" x) j: J2 o! U
  97.        }    ! l; |$ B# E" d9 D  a) G+ B% U$ M
  98.     4 r" u. q- a# C& m  n
  99.        return $hashStr;   
    - Q/ [7 ^3 k: y0 `9 ]/ O; n2 w
  100.    }   
    ) A/ t1 C/ `4 l  n! e* g
  101.    
    % w8 ~$ x" H7 E/ j
  102.    
    9 c: {5 D3 D. E2 |. p8 E" H
  103.    /**hash 图片文件   0 x- G) Z# a$ q5 X: [5 x- z5 c
  104.     * @param string $filePath 文件地址路径   2 G! X0 H! X! B3 z1 w- J
  105.     * @return string 图片 hash 值,失败则是 false   
    1 R" B# g7 f4 E% j. P$ t) Z  Y
  106.     * */   
    : U: _9 ~1 _) m/ p3 |8 l
  107.    public static function hashImageFile($filePath){   
    ; B3 ~. I8 _1 D7 _6 h2 E
  108.        $src = self::createImage($filePath);    + S# ~1 h" Y/ a: m) N
  109.        $hashStr = self::hashImage($src);   
    ! r& E# ~! K2 S7 x+ O% M8 p! _
  110.        imagedestroy($src);   
    9 @) ?  c9 ]( H* V
  111.     9 I+ U8 t: e5 }; `! {
  112.        return $hashStr;   
      P+ l  x) m0 n+ S
  113.    }   
    - `4 l, m  J7 [) W: G5 x" ~6 W; O
  114.    
    0 A8 k' y! [& Z, q, \7 Z
  115.    
      ^' Q4 m8 \* ]2 K, @  [; x) q( P8 U
  116.    /**比较两个 hash 值,是不是相似   4 ?" C4 S; d1 S. I6 b( e
  117.     * @param string $aHash A图片的 hash 值   
    0 r4 a2 |/ Y8 k. j# p  w1 `
  118.     * @param string $bHash B图片的 hash 值   
    $ B# y! u- s, @* \
  119.     * @return bool 当图片相似则传递 true,否则是 false   8 B  P. Q1 z. R8 H- i0 ]1 S" M, W. }
  120.     * */   
    5 ?2 [1 U, v9 y2 o5 S. d9 ]& R
  121.    public static function isHashSimilar($aHash, $bHash){   
    6 d' c' Y. P2 C
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    . j4 D# {  ^  ?4 |/ v( H
  123.        if ($aL !== $bL){ return false; }   
    ( w/ G  T9 u- F. C) U0 G3 v
  124.     , F% }, V3 S. p. F& f/ G
  125.        /*计算容许落差的数量*/   
    9 W( W. q' J/ c2 s7 X8 @. u0 G
  126.        $allowGap = $aL*(100-self::$similarity)/100;    2 ?4 w4 e7 s7 l8 q3 o! s. X. t
  127.    
    9 U8 \' b: ?# L/ C# y# s
  128.        /*计算两个 hash 值的汉明距离*/   
    1 Q$ G5 `4 U' k& j' M5 N( H
  129.        $distance = 0;   
    % I4 K- k3 M2 t' e$ i/ G
  130.        for($i=0; $i<$aL; $i++){   
    9 b" i( W1 E. _& \& N6 D, q- j+ p$ N
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    0 g6 P* S* s. V+ D
  132.        }    ) b+ N2 s% ]5 g  U; J; m. I6 l
  133.     ' E8 H# [+ q- L" ~/ f1 D; r
  134.        return ($distance<=$allowGap) ? true : false;    ) e& ]/ z4 ~+ @" D+ c
  135.    }    / d# a" f& |' C1 ?- Y8 S; k0 C
  136.     ; P6 Y* p: b8 e& P
  137.    
    1 y: O+ Y6 G- |1 q% R" e
  138.    /**比较两个图片文件,是不是相似   $ j0 Q( r0 G( u+ d
  139.     * @param string $aHash A图片的路径   
    * T* d# e, r* Q4 |( O# D
  140.     * @param string $bHash B图片的路径   1 X5 X4 G2 l0 u6 I: K; O
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    4 B0 y& L# K( z4 i0 h! z$ L
  142.     * */   
    5 f* Y: e3 X; k
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ; {2 \0 g  c2 j: Z
  144.        $aHash = ImageHash::hashImageFile($aPath);    & z5 F) h- _0 Z; M
  145.        $bHash = ImageHash::hashImageFile($bPath);    2 @# y4 {2 A: q( |
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    ' G; x% Y% ?& `  Q1 [& H) A1 _% w
  147.    }    ; I* e$ u* G. ^
  148.     ' |5 i% l. J& p
  149. }8 M) `- i. [+ K2 Q: L' q+ h& ^
复制代码

. `& e: j4 p* ^% \6 |0 ?5 R$ q8 C. m
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 22:44 , Processed in 0.061299 second(s), 20 queries .

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