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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

0 j# l$ c& L* Z9 e6 b. K1 H由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

6 I- v. p1 L& I+ W6 X* k
  1. <?php   
    2 ?# u* v- v- b+ u
  2. /**   5 S# ]9 n. H* U+ \6 O
  3. * 图片相似度比较   8 o* n5 L- y/ v% U) Q
  4. *   
    3 e: ~  N6 L6 W2 t4 R6 @' }; m
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ) S3 T- @* S. F- N2 N% j1 X4 t
  6. * @author      jax.hu   
    5 J% ^1 F6 x2 p) z% R5 Q
  7. *   
      V6 C) X  `$ X- V9 }
  8. * <code>   
    / p2 R7 w& q! j! i
  9. *  //Sample_1   
    ( J: W; I' }' L! G  Q
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    * p. p0 ?; g5 y5 A0 l  I4 q
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    . G$ L( t$ G" k( r! |% p
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    & m" D- Q; q. E0 s% d7 H
  13. *   + Y6 R7 ^9 N2 z
  14. *  //Sample_2   
    % Q* m9 d# h: Q" L
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    8 t* H$ g: v9 J' b# ~( G) r, ~! g
  16. * </code>   + h! x: \+ L+ C8 G
  17. */   
    ! @/ U: w$ b4 ?6 e/ O- s3 w2 y. D
  18.     6 @+ W* s6 {4 u9 p& F
  19. class ImageHash {   
    7 ~: o  M3 |3 ]) G8 u
  20.    
    4 ]# |& u* D% @/ i; [4 I; Z1 x
  21.    /**取样倍率 1~10   1 e  A4 q# J" z
  22.     * @access public   
    9 S2 a( {" v+ u3 u3 U; A
  23.     * @staticvar int   * u+ Z0 S" O% |
  24.     * */   
    - |8 V( Y4 h, a8 H  j% G, c
  25.    public static $rate = 2;    , _4 R. [) H5 }* D5 I( F
  26.    
    3 l% D: R$ V' X' g8 A, S
  27.    /**相似度允许值 0~64   : {+ F' P$ m  Q2 U# n$ \7 g5 E
  28.     * @access public   " G6 q* R' e3 `  v  h+ K$ C  _# Z
  29.     * @staticvar int   
    5 [9 t, ^' e' Q" \# J2 W+ E
  30.     * */   
    * s9 s4 r4 Z2 k4 N6 l- W
  31.    public static $similarity = 80;    - N" n% O% Z( O
  32.     2 T- M3 `# R6 }8 G& Y
  33.    /**图片类型对应的开启函数   
      f2 C, t' b. m% s) k9 `6 a! p* a
  34.     * @access private   ; W5 _' U, w( l4 _! |# z
  35.     * @staticvar string   
    # K% p+ \% Z5 W0 i$ X; r+ M
  36.     * */   
    " `2 I- v" k3 V7 o) O6 X% [/ j
  37.    private static $_createFunc = array(    8 \& _; `0 H; r7 h1 F& f! D
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ' u* b0 B" s# r; N; a$ ]
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    1 l8 U3 {4 c# h* O6 o) P
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ! C! M( A1 ]1 O6 i8 u8 s6 g$ |
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    4 j' @5 m. u. C" f4 f3 o
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    2 s& e: k% q3 E/ n0 o0 H+ @
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ) Y1 Q, {  ^4 s& E" R+ \; ^9 S
  44.    );    0 P. N& m, q" M6 m  t9 \/ ?
  45.    
    " k, M- t. g. N; [2 |/ ~+ X
  46.    
    4 ~; z8 q) P5 c/ x: ~
  47.    /**从文件建立图片   
    " y; r/ i. Z3 S9 c0 Y' m1 M2 o
  48.     * @param string $filePath 文件地址路径   ) E, T/ J9 D# L& E9 G$ j" l5 g
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   . Q6 @! q. Y; U
  50.     * */   
    " r$ X" p7 w/ \) ]6 z7 V
  51.    public static function createImage($filePath){   
    6 }  J: Y' \2 `) W* }& a% `6 w0 l
  52.        if(!file_exists($filePath)){ return false; }    : `# v# H% L- H, B3 g4 Q
  53.     1 c; x4 D: ?$ _8 o: S
  54.        /*判断文件类型是否可以开启*/    / Z- C% a- E3 ?4 v/ g5 W
  55.        $type = exif_imagetype($filePath);   
    ; p) v/ L) C+ y9 i6 l% i
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    " }+ y) W, w1 {$ \  |
  57.    
    2 a& Q  s* M1 `( W$ R  \/ R
  58.        $func = self::$_createFunc[$type];    . p8 g& }8 f0 c3 \
  59.        if(!function_exists($func)){ return false; }    / s; g* Y; p/ `7 M
  60.     ( r1 E4 z: Q# R2 m! F  u$ }# ^% S
  61.        return $func($filePath);   
    ' x1 _! R' j; N8 c) h9 J9 f- }. x$ \0 d
  62.    }    & H5 E3 A, c8 F* [  v' o4 x9 L) P
  63.     2 S. o% }: K6 r9 ^3 v! `# {
  64.    
    4 z0 v/ A$ J, G$ n9 v  z
  65.    /**hash 图片   2 K3 ?3 Q- ~# Y
  66.     * @param resource $src 图片 resource ID   9 q5 w& x* M! z/ U/ Q; l
  67.     * @return string 图片 hash 值,失败则是 false   ; T1 w4 Q$ \& n/ a! r
  68.     * */   
    , [' n' t. l3 B
  69.    public static function hashImage($src){    . z2 h: C' R7 d$ q0 |) {! K
  70.        if(!$src){ return false; }   
    & C: W$ q0 `4 ^& T2 J0 h$ n" @$ Z
  71.       W5 p$ P- l) c( E
  72.        /*缩小图片尺寸*/   
    1 M1 h( r8 k, H* |* \
  73.        $delta = 8 * self::$rate;    $ Z8 |) u0 W8 V, m
  74.        $img = imageCreateTrueColor($delta,$delta);   
    * @8 g' h. o  `6 o( @( |& O
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    " c$ f3 C8 Q% X* M. i( C/ x
  76.    
    9 g! e6 p2 _5 k) d" a' j: d
  77.        /*计算图片灰阶值*/    9 l$ F* ~' d) Z8 {
  78.        $grayArray = array();   
    0 S* O8 m/ F5 `8 R( m4 y
  79.        for ($y=0; $y<$delta; $y++){    4 {- O0 R$ \6 n( P3 H
  80.            for ($x=0; $x<$delta; $x++){   
    , k! I( D9 }4 |' N1 W% [
  81.                $rgb = imagecolorat($img,$x,$y);    ) A' `: M9 s% W, _, H
  82.                $col = imagecolorsforindex($img, $rgb);    ; [1 D' k* X4 M2 P
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    . M" H' w$ w0 [8 p, A
  84.    
    2 b$ U/ }( B2 F( Z
  85.                $grayArray[] = $gray;    5 {0 r- E( y* ?6 M# ~6 \
  86.            }   
    : Q1 i1 ^4 I3 T) Q7 s& B# y" t
  87.        }   
    6 z) f0 g7 t. M/ e5 N" r* z
  88.        imagedestroy($img);    + s: Y: ]8 S! U  E  w+ u7 \# M
  89.    
    ; }, d/ ?4 G2 [0 u7 ^
  90.        /*计算所有像素的灰阶平均值*/   
      Z& U0 I; J2 {
  91.        $average = array_sum($grayArray)/count($grayArray);    8 B7 g, _0 l; Z
  92.    
    9 n1 U$ _* `+ X. d
  93.        /*计算 hash 值*/    4 n7 d2 Z" N/ a' u3 K* R
  94.        $hashStr = '';   
    9 p& d9 n/ Q$ H6 ~. F# B/ [. N
  95.        foreach ($grayArray as $gray){   
    2 k" |, f1 U* f3 P6 n
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    / t; v9 w( H7 z3 [3 {) q
  97.        }    * U7 h. e' m9 e" a' e' e8 g
  98.    
    0 j. F# h% _2 T  Y4 U
  99.        return $hashStr;    " w: N+ h8 T; D+ A- x- R
  100.    }    / N5 Q0 s3 g! _: P5 k! }
  101.     $ C# a. r1 o( w) Q
  102.     * I& R" f$ c/ T& D- g2 _
  103.    /**hash 图片文件   
    ' d: n! s+ q1 g& K' u$ L- P" R# c
  104.     * @param string $filePath 文件地址路径   . n( v9 q6 Y! q, J, [
  105.     * @return string 图片 hash 值,失败则是 false   
    7 R8 U& Y3 X4 _' X
  106.     * */   
    5 Y8 X6 L  Z, ?2 j9 ?
  107.    public static function hashImageFile($filePath){   
    ; _. b- w  w( [
  108.        $src = self::createImage($filePath);    3 m1 a8 w$ h6 e% ~2 {( E  G+ j/ B
  109.        $hashStr = self::hashImage($src);   
    ) }' s0 w1 H* g
  110.        imagedestroy($src);   
    . G( D! I7 M# l; f. T
  111.    
    ! r1 e7 @, r% w& x: H% j7 K
  112.        return $hashStr;   
    0 W0 }# C# V2 T! N( j
  113.    }   
      j" I: A* M3 m1 O
  114.    
    4 {- t+ s' E5 P9 \6 E9 Y9 J, H
  115.    
    * I6 z0 Z$ b8 T/ _
  116.    /**比较两个 hash 值,是不是相似   
    1 `9 ]- }9 X6 H, @, v+ k5 @! N
  117.     * @param string $aHash A图片的 hash 值   ; F# D9 e+ x9 _2 P9 n
  118.     * @param string $bHash B图片的 hash 值   7 \! P- a* ]; [; C7 r. u) V
  119.     * @return bool 当图片相似则传递 true,否则是 false   5 x! D+ N6 F( d% [
  120.     * */   
    % ^: b. n% ~" Z) e0 F
  121.    public static function isHashSimilar($aHash, $bHash){   
    # Q9 @4 l* ?8 @9 d$ j6 m
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    ! e8 k$ ?- q! ?7 N7 H9 W8 A- q# `) E
  123.        if ($aL !== $bL){ return false; }   
    : \8 y7 `( n6 V! f8 _% K; \; E3 o
  124.     - {; X+ x3 J" s4 @1 i
  125.        /*计算容许落差的数量*/    ; g$ a/ @! u" v2 z# t- t, ^3 T0 s7 ^
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    9 m8 v  d! X; P2 a2 i, R* g
  127.    
    6 K1 ?, y6 O; x- C6 ]
  128.        /*计算两个 hash 值的汉明距离*/    # G" p7 \8 [- W6 H: ]4 F
  129.        $distance = 0;   
    & J. y3 M+ ^7 f2 k2 `* o5 r7 _
  130.        for($i=0; $i<$aL; $i++){   
    ) Z' \6 Z$ L7 E9 p( J
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    9 a/ C  ]7 M: w& K$ F2 \
  132.        }   
    % F) v: q2 d9 R% d& u
  133.     1 g& i% x/ g# l& R  Z: }' q% L0 Y
  134.        return ($distance<=$allowGap) ? true : false;   
    , e, ?# o6 H; ?# B+ A# B0 E: O
  135.    }    * @( G8 P& K4 @
  136.     ( w5 v! c, {- z, E: q
  137.    
    0 b6 t0 a1 m* G' e6 \
  138.    /**比较两个图片文件,是不是相似   - \+ \/ K) f3 C, H4 ~
  139.     * @param string $aHash A图片的路径   
    , t5 R* x- K  Z/ n* k7 I9 W/ K
  140.     * @param string $bHash B图片的路径   
    8 ~7 Y2 T7 j- V) D
  141.     * @return bool 当图片相似则传递 true,否则是 false   1 }! L4 y9 O7 K% \6 u
  142.     * */   
    ! [  J' K7 T/ T8 }$ I- O
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    $ j' y3 o/ Z$ k5 U+ d
  144.        $aHash = ImageHash::hashImageFile($aPath);    & X+ i. w, u1 a1 f
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    $ G) [5 B' ~" ~$ L  N8 P; M! B
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    5 q) k, G3 \3 i2 F: @( Q
  147.    }    4 P9 L' z2 b% J
  148.     3 }1 H2 p- o/ I$ Z9 C3 n3 g+ m
  149. }
    , U- ^* N$ y/ h, P' V8 C
复制代码
3 W  Z% a, V+ F0 ~' L

& X1 h2 ~) f) N, ~. r. z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 04:14 , Processed in 0.065812 second(s), 19 queries .

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