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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图# O1 m6 R0 R0 L1 S. h1 T
' a5 g  E5 Z: ~- y" K
. [( c# \) h/ ?9 g+ G
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

7 w- k7 O$ a* p" D9 ~/ \* B: u0 E: \
  1. <?php   
    8 i: z+ k( K) _0 [
  2. /**   
    / u+ Z/ u. [' H, O
  3. * 图片相似度比较   : ~% Q. ?$ T( Z2 {
  4. *   
    2 B. }2 ?+ f1 m# ]) H( ?" N
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    0 P( a: L; R  @6 [( q- M
  6. * @author      jax.hu   3 c. E) U5 N+ y3 J; J" s9 r
  7. *   
    : Z% U! A0 X* K4 h
  8. * <code>   
    $ N  W9 `! p' S5 h
  9. *  //Sample_1   6 K3 g2 I: v. m- s/ D
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    * y% ~6 a: l: k- j
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    $ o4 j% ~9 H! \( n7 Z
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    . @' w6 s6 N/ z' v
  13. *   " F4 \; S3 _6 m' b& h
  14. *  //Sample_2   
    $ Q" c$ @/ B+ ^; B/ K: d
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ! {$ T! `( Y: V  C7 h
  16. * </code>   0 @; R1 A+ X$ {* {: {2 @
  17. */   
    * A; t: ?% G8 s  E  k1 g" w
  18.     ; |' k9 A& I! T& A9 X* t
  19. class ImageHash {    4 n7 k2 `# s; _& I3 w
  20.     ) o8 H* W, l- T" B  [$ v& z
  21.    /**取样倍率 1~10   
    % o" _4 c- ~8 e3 V
  22.     * @access public   % G- J/ w, a4 u4 j+ k
  23.     * @staticvar int   & c; D! J/ ~0 @! Z+ R  i
  24.     * */   
    % i) _6 D& V) K
  25.    public static $rate = 2;   
    - a6 F$ h5 e& ?3 J6 Q% ~1 V0 H
  26.    
    ( V$ \- k4 [; @4 P% D; k1 P. a
  27.    /**相似度允许值 0~64   
    4 e$ ~  d. I# ]5 e+ c
  28.     * @access public   $ u5 {- t7 S) N9 I6 u
  29.     * @staticvar int   
    2 S2 m2 J6 M0 |# @
  30.     * */   
    $ Q* R% u5 e' d; i) v) ?
  31.    public static $similarity = 80;   
    2 n, d! c; k; r% H% T1 Y
  32.     & _7 }9 L; @* s# H' n8 u2 H
  33.    /**图片类型对应的开启函数   
    " X) E9 l4 o- q3 I; h) Q1 n9 b
  34.     * @access private   - C/ H0 k' V0 S7 Y9 k0 Y
  35.     * @staticvar string   
    & O- K( B! d- ^( x
  36.     * */   
    1 W8 q- z7 D( B( v) _9 b
  37.    private static $_createFunc = array(   
    . M: u+ |1 r6 z/ m0 O, ^
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    , o6 I3 q" b$ l$ }" O2 N9 E
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    3 X/ N$ y2 s$ R- l4 N5 @. s$ R6 @
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ; l/ e# C0 ^3 @$ u
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ) o! q. S8 \# ?: U
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    0 q, Z% q# W5 k+ v
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    0 e6 E7 m6 T, h: [) D
  44.    );   
    - x( X1 }% X" X  Z: H7 K- q3 j8 p
  45.    
    % }1 Z; q5 E4 c9 U" R! R1 e9 {+ D1 e4 q
  46.    
    / H2 q1 R: n/ Q% b1 ?" }; W2 }8 `* x
  47.    /**从文件建立图片   
    ! U4 }# S0 I, k7 V+ N6 k
  48.     * @param string $filePath 文件地址路径   
    % ?0 M( B% G/ s8 @" P$ x
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ' v* a% L( O  a  n) G' E4 p, U
  50.     * */    ( s$ I* j* E3 \( @: \
  51.    public static function createImage($filePath){   
    9 k7 _, r5 R6 F7 ^+ f! ^1 q2 X
  52.        if(!file_exists($filePath)){ return false; }   
    " T6 q! @# o4 m: W
  53.     + o2 Z$ ~, v5 q0 Z6 c: [8 ^1 ]
  54.        /*判断文件类型是否可以开启*/    , n! C' r; ?" W1 k% \
  55.        $type = exif_imagetype($filePath);   
    4 d6 P6 T/ b& ?: |# P) l6 |
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    - i" P# i) S6 b8 ?9 ]7 t4 e: W" ~: I7 n
  57.    
    2 \( q) ^5 s4 |' a( X$ a+ ?
  58.        $func = self::$_createFunc[$type];    4 i  k* z& A8 C) ~
  59.        if(!function_exists($func)){ return false; }   
    / P% \& M% \+ L4 ]
  60.    
    , s5 P+ B3 n2 z. h8 y. U
  61.        return $func($filePath);   
    5 [2 w' u8 _, u. t! w
  62.    }    : U0 Y1 }' z- B& x! {4 l4 q
  63.     . O5 S1 D  {& o/ {
  64.     0 G: W. m7 V% S+ N2 ~) Y) z+ b
  65.    /**hash 图片   ; B6 b" q( v! X# S& Z+ b7 R5 B" B
  66.     * @param resource $src 图片 resource ID   3 z3 O  v; t. J8 ~2 {, a
  67.     * @return string 图片 hash 值,失败则是 false   
    4 o8 |  J: _/ i' t  B5 C
  68.     * */    : T" L( g3 y& `
  69.    public static function hashImage($src){   
    ' G* V! T! m2 Q# Z" e
  70.        if(!$src){ return false; }    . M2 q0 i6 Q8 o( [  `
  71.    
    # \' [# O' y4 _9 }) ~
  72.        /*缩小图片尺寸*/   
    / u3 X& b. Z) A. r5 U; ?; ^2 K* n* ?9 |0 @
  73.        $delta = 8 * self::$rate;    : C6 O6 Q1 u8 R# y2 |  ^8 W
  74.        $img = imageCreateTrueColor($delta,$delta);    + j! H& j9 [7 N
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    8 H4 |/ i8 Q# s0 w8 d3 b
  76.    
    2 E) \+ d$ ]1 j$ `. |+ a( {, w1 x$ _
  77.        /*计算图片灰阶值*/    2 s- K' j5 v# o2 N5 Q
  78.        $grayArray = array();    9 S5 T  y9 S. U
  79.        for ($y=0; $y<$delta; $y++){    7 t1 l# ^3 i: F2 s2 u5 O
  80.            for ($x=0; $x<$delta; $x++){   
    6 f4 r/ _6 y- t& ~3 m! z
  81.                $rgb = imagecolorat($img,$x,$y);    1 H- o1 v6 l; k
  82.                $col = imagecolorsforindex($img, $rgb);    / a. ^' X1 O5 U/ m1 Y' X
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    7 U! [7 ^" `# K5 ]
  84.    
      u% S# x% v' m
  85.                $grayArray[] = $gray;    8 X9 _/ l2 }$ g% P/ i/ Z
  86.            }    + `# k1 D# U/ [8 H
  87.        }    7 e/ H; E9 f! ^) H
  88.        imagedestroy($img);   
    * o2 j; V7 \! O$ }, u
  89.    
    - r6 |- d0 J: p) L' O
  90.        /*计算所有像素的灰阶平均值*/    % w* L% b2 X8 P& G5 E1 }2 y6 D
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ) z4 A$ |4 M9 O/ u6 C, O
  92.    
    5 J8 v+ d! B0 E' Q+ X7 Z
  93.        /*计算 hash 值*/    ! j" O' V3 m( J- j  \, S
  94.        $hashStr = '';   
    2 ^# w% N; S! a( V" k7 n
  95.        foreach ($grayArray as $gray){   
    ( H+ T6 m. k( {
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    2 Q3 T: [. t" d) e7 V
  97.        }   
    $ g) s3 ?/ m. x
  98.     6 f8 G* I( p8 G5 A+ F& b( W
  99.        return $hashStr;   
    # T0 u* T5 o: x
  100.    }   
    - {; s3 y  d# F4 e" s! i
  101.    
    ) `# D7 H5 K5 K- ?
  102.    
    2 ]% G& B) [4 J: A
  103.    /**hash 图片文件   # x; q. R+ l6 x5 W9 Z2 W
  104.     * @param string $filePath 文件地址路径   
    ' i1 \) A% N1 T% t
  105.     * @return string 图片 hash 值,失败则是 false   $ O1 m- G) I% x0 F; v. K
  106.     * */   
      H7 ~3 V( O1 p# f
  107.    public static function hashImageFile($filePath){   
    8 V- e: [/ `; {6 b+ S* ]8 o; t
  108.        $src = self::createImage($filePath);    - e5 I4 L3 G, g& c/ a; d
  109.        $hashStr = self::hashImage($src);    5 X% E6 l# q  l9 t
  110.        imagedestroy($src);   
    / e. |1 E: N  o4 V) e& J9 [
  111.     2 u! a5 F5 U: Z1 ]/ N
  112.        return $hashStr;    $ t0 C0 P+ k; F. N6 z4 e. G
  113.    }    $ {! U; X8 p7 n! t# O! @* U7 j
  114.     # U6 N& K& L5 w6 P* i9 V' Y
  115.     9 w3 A5 B0 b7 Y- [  ?7 _
  116.    /**比较两个 hash 值,是不是相似   
    + b* A- I4 y- `4 t  v5 L
  117.     * @param string $aHash A图片的 hash 值   : \- O) `% c+ F6 U  j) k6 s
  118.     * @param string $bHash B图片的 hash 值   1 Y- y  [; P8 V$ H9 z; ~
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    0 L2 ~0 E8 n) ^
  120.     * */    % ^* \. H' I, V% ~* r! [' U( G
  121.    public static function isHashSimilar($aHash, $bHash){    4 O) N" ?! ~) Y  c" c
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    1 S$ u1 _- M1 [. u* G) G9 k
  123.        if ($aL !== $bL){ return false; }    5 A; N4 M# ?+ O. @
  124.    
    7 Q6 a  i* b; D- c5 h1 A1 M4 X
  125.        /*计算容许落差的数量*/   
    9 f2 r( g0 k/ g4 e" ?1 R
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    - E; r& R& W! Q2 n9 b
  127.    
    ( c" X7 L9 r, v, K! E% c
  128.        /*计算两个 hash 值的汉明距离*/   
    # t4 l, g& c2 Z
  129.        $distance = 0;   
    : Y, O# }" i- K$ q% G/ o5 D1 M& s: b
  130.        for($i=0; $i<$aL; $i++){   
    2 v8 o& Q5 F' A8 E& _! {- u
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    , F" H! E6 k6 g* i7 X
  132.        }    . ?) o+ a- R$ T9 X
  133.    
    - d8 t4 U& i+ ~0 g; j% y1 r5 P
  134.        return ($distance<=$allowGap) ? true : false;    8 e; C/ ], F* J, h/ `+ ]
  135.    }    4 Q1 l6 x: v; H0 p% X. R0 }5 \: r' d' F
  136.    
    # A2 J) o& B+ V5 y: u
  137.    
    ' B* m( C7 p* k" X$ R) _/ S
  138.    /**比较两个图片文件,是不是相似   8 }  h- L" q# w1 R
  139.     * @param string $aHash A图片的路径   
    ! V& ]) N: g! u2 I
  140.     * @param string $bHash B图片的路径   3 l$ {+ V" W; H; h
  141.     * @return bool 当图片相似则传递 true,否则是 false   : b9 M# h4 L9 o
  142.     * */    4 b! L1 ^" z% d6 B2 C# E
  143.    public static function isImageFileSimilar($aPath, $bPath){    , j5 [$ ?, y% K- G4 W- Z7 I5 S
  144.        $aHash = ImageHash::hashImageFile($aPath);    # K* d+ v$ w# Q- s9 O
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    - @5 G' \# g  }9 e
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    % m; q# b( k8 B0 I2 T  h: O
  147.    }   
    & V* ^. U% I* Z, T1 g0 F# B3 j
  148.     % @  P$ n8 M$ u4 X
  149. }2 }' b" k& C( d3 ^0 U( X2 n% s
复制代码

. a, p& Z8 B1 [
: \6 J; Y6 P2 `
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-4 12:59 , Processed in 0.074416 second(s), 19 queries .

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