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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

( Q  k' C' s& v7 ^6 l% z6 s
. u+ G6 U) [+ F* s
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

+ _* \3 N/ Q& [0 v
  1. <?php    % j5 h( s+ }/ M/ @
  2. /**   
    6 ?% m1 Z% }2 i
  3. * 图片相似度比较   9 u+ z& l( v8 w4 _5 H, h
  4. *   
    . h4 L% G! }$ X8 L3 W" g2 Z% }
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  7 r8 }: c% Y% O# I9 ]9 V. |
  6. * @author      jax.hu   6 i  \: J+ T: ]* N8 {
  7. *   
    " j6 q; W: N. w& S# o4 \
  8. * <code>   
    ! h6 @6 m1 r' A- }0 c0 @6 A
  9. *  //Sample_1   
    . |& b! I- J$ Q) m$ F6 b/ D
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   + v! ^4 A8 X' N$ l
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    7 @0 f7 V& f9 ]% |
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   # o6 p; t' Y! g/ ?2 U" d
  13. *   ' ^, E* Z( [2 \$ G& X7 @
  14. *  //Sample_2   , r7 ^' H  G  r5 K5 \0 e$ p( _# E4 B& n
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   $ @5 j% W3 w6 V' e( E% f/ k) T* k
  16. * </code>   
    % G! _  o/ _5 j% L9 i
  17. */    & h& ]2 }+ k* O0 {
  18.     9 Y3 v+ L2 W$ g
  19. class ImageHash {   
    , ^; _/ `: W" }. ?& X" I
  20.     ) w9 U6 f1 \$ ~. P. u
  21.    /**取样倍率 1~10   
    2 y% s' P& C! B" M! B3 v/ F) p
  22.     * @access public   . K4 ]# |& z; _; V2 v
  23.     * @staticvar int   , n3 I" T1 L0 k  n5 y
  24.     * */    ( h- X9 |0 d) |5 Q" q& \0 j
  25.    public static $rate = 2;      `0 u( V* \5 N  `) n8 K
  26.       Y( P5 C. A7 E) b; H4 S
  27.    /**相似度允许值 0~64   
    / a7 Q; x; {! Y% Y3 m, x
  28.     * @access public   
    & R3 x5 v6 i$ `1 i* N: a
  29.     * @staticvar int   
    % E( ?& J* ~5 o9 c
  30.     * */    . n8 j4 d7 g6 s, Y+ D5 d
  31.    public static $similarity = 80;    + j2 ]4 h4 T) u2 H5 I$ C
  32.    
    ! ?) s3 E5 c% {
  33.    /**图片类型对应的开启函数   
    ! g* K: H( L  \, B3 \8 U9 P9 T
  34.     * @access private   
    * _; ?  e5 _4 S) Y
  35.     * @staticvar string   ) W( k1 c8 i9 t  Z: [. D9 C
  36.     * */    # T/ }6 J: x2 q
  37.    private static $_createFunc = array(    ( J* o  }$ r: ]& i1 L
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    * c7 U" E0 a# }7 x  ^& t) d
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    5 S+ O; R2 @+ |: K3 i
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    8 P  X/ Z* `3 ~, W
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ; o6 u, U! K# [: N' C: g, |
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    3 d$ t$ G5 y* @0 Z9 F7 d( u
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    7 g# [  p- M7 y, J4 x* j
  44.    );   
    ! P1 o$ k6 q. d7 w/ U' y
  45.     ' c9 h4 U/ T4 ?" B% t
  46.    
    " W+ s/ J! ?0 s3 o
  47.    /**从文件建立图片   
    9 k; _7 [  P# Z
  48.     * @param string $filePath 文件地址路径   1 h: `! Q9 W9 N' i  l" n& F, s$ V
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ) k/ B5 I$ k3 F6 N8 _, K( l
  50.     * */   
    9 Z" z. }" h7 A/ P( Z6 X. k
  51.    public static function createImage($filePath){   
    / j8 J& }$ D& v7 h0 z5 x
  52.        if(!file_exists($filePath)){ return false; }   
    6 r: |9 V% p5 T8 s1 q$ N- X* H
  53.    
    5 V: Y5 U0 J7 p. M0 i+ I/ H
  54.        /*判断文件类型是否可以开启*/   
    * p" L& Q. A) P1 I& O% x* O0 J; m
  55.        $type = exif_imagetype($filePath);   
    & i% g0 c9 p" I$ q; H" ]' d; ^
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    : d0 @4 V4 ~7 V
  57.    
    7 y8 y% d9 H4 G' h, g) O
  58.        $func = self::$_createFunc[$type];    + C# [( n+ y# C9 e
  59.        if(!function_exists($func)){ return false; }    : q* |* r2 T: Q+ |& o1 R3 w
  60.     . I; O/ _- M% ^9 x# s$ _6 B) p9 K: [
  61.        return $func($filePath);    3 K% b6 U* X4 P# Y
  62.    }   
    0 m& U  p# K! H8 O0 {
  63.     4 M1 _9 F! s' e6 }$ U* m8 Y+ a
  64.    
    ; r$ D8 N% J" B* J
  65.    /**hash 图片   $ U0 c# p+ \- n' [# ^, H
  66.     * @param resource $src 图片 resource ID   ( o2 @# u$ Y. k9 B* w5 C8 ~
  67.     * @return string 图片 hash 值,失败则是 false   
    - V" Z6 N5 s5 q9 I8 g
  68.     * */   
    9 W; }- v9 B' U% j" Y0 x
  69.    public static function hashImage($src){    $ _3 L' h1 r, z9 F. A
  70.        if(!$src){ return false; }   
    3 a2 i1 w$ W2 |) t0 c  O4 w
  71.     8 S9 U; n! v5 }* O5 [
  72.        /*缩小图片尺寸*/   
    , \/ J3 ]( B; m! j
  73.        $delta = 8 * self::$rate;    4 o9 b4 K* Z% _, k
  74.        $img = imageCreateTrueColor($delta,$delta);   
    - H; g0 q( x4 g6 E
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    . m- Y- F9 m1 ~# Z( A, k
  76.    
    # L) N% P( }8 |" ?4 x' T
  77.        /*计算图片灰阶值*/   
    # q! B( c) ^" ~8 s
  78.        $grayArray = array();    # J7 z, O& [( z* |8 D8 Z5 d& R
  79.        for ($y=0; $y<$delta; $y++){   
    & [0 I% G' j( k4 U+ a- G
  80.            for ($x=0; $x<$delta; $x++){    0 a& _+ I/ s4 W; E7 X
  81.                $rgb = imagecolorat($img,$x,$y);   
    % s6 c+ F0 {/ b% [" g& A
  82.                $col = imagecolorsforindex($img, $rgb);    2 R# v# z# b  G) [5 H
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    & e' X& b, F2 Z
  84.    
    % A+ p3 k( A' w" D1 w2 i
  85.                $grayArray[] = $gray;    . N% l- s4 M$ E/ i9 q, l3 N- k& h# t
  86.            }   
    4 L2 ~$ b; H! a- w0 H
  87.        }    2 k2 Z. {! p9 d1 ^4 x5 X
  88.        imagedestroy($img);    , V6 m3 ^7 T- t& c+ u1 \3 t8 c
  89.     $ L; p& X; a9 n4 `3 V
  90.        /*计算所有像素的灰阶平均值*/    ; B% ?* X% I* N/ k8 {! Y  S. H0 s
  91.        $average = array_sum($grayArray)/count($grayArray);   
    5 l9 n2 m% t+ _: w, e. R) @
  92.     ( }1 k7 t- C: H( p3 D& J
  93.        /*计算 hash 值*/   
    : |3 |/ Y! u) \; e- j* k* Z
  94.        $hashStr = '';   
    1 h2 N; W5 v! k1 e
  95.        foreach ($grayArray as $gray){   
    & D0 c; U; a4 F9 k5 u2 s
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    * f& h' t4 M; x$ e
  97.        }   
    " F$ }0 ~7 g" Y3 h6 Z4 \" c
  98.    
    ( m- w8 e- R, A$ m
  99.        return $hashStr;   
    ) |. @; i2 g4 V: a7 s; g* n! A
  100.    }    # }  n; e& {' E8 V  v7 }' _. S
  101.     2 p+ L' W: p% o+ ]/ y
  102.    
    4 T* d. q" c4 `* s6 r) ~
  103.    /**hash 图片文件   : ~# [3 D: V& `+ P- E$ h0 b
  104.     * @param string $filePath 文件地址路径   
      p8 N9 n9 G, k* N
  105.     * @return string 图片 hash 值,失败则是 false   
    " W, S4 f1 Y. n5 ]1 c9 a
  106.     * */   
    7 q. l5 F0 i' K8 Q. y- z# K/ C0 _- x
  107.    public static function hashImageFile($filePath){    8 T2 P$ J& L) e4 `7 M( s
  108.        $src = self::createImage($filePath);    ; L) G7 {' _. A, T
  109.        $hashStr = self::hashImage($src);   
    ) b+ ?2 \! d$ V! g9 `5 ^6 w. m
  110.        imagedestroy($src);   
    + t/ ?/ j, [! O: ^0 K/ H3 b, `2 ]
  111.     0 A) V% }! ^# T
  112.        return $hashStr;   
    ) G: e( D& R' ^, r6 v: u- z
  113.    }    + |8 v  A: d- A" s: z0 g0 B2 E
  114.    
    3 C& X+ R/ Q; `# x" N
  115.     $ {9 u2 L+ \. v- g- z
  116.    /**比较两个 hash 值,是不是相似   
    6 g4 j" v8 }. l2 |$ f7 k
  117.     * @param string $aHash A图片的 hash 值   2 P; \1 u3 x' z: Y. U) m3 s4 o% Q. E3 X
  118.     * @param string $bHash B图片的 hash 值   
    , b1 a- d" o# s6 ]( M1 e
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    5 C% c) d7 P& k7 T9 D2 }5 S
  120.     * */    6 b% q" _) Z/ }2 e$ p
  121.    public static function isHashSimilar($aHash, $bHash){   
    2 ~0 t8 o; M- n$ F3 Y* w
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    ( |% h3 z: b3 A; ]" N! t" W
  123.        if ($aL !== $bL){ return false; }   
    * o/ L, s  a6 \  }
  124.     % d5 c9 A3 v4 g0 I; o& r. j5 C
  125.        /*计算容许落差的数量*/    1 X; m2 {/ t# x6 ~5 P/ q6 y7 G
  126.        $allowGap = $aL*(100-self::$similarity)/100;    - q7 \: v, r8 d' h; S
  127.     ' J9 ?; K* o: Z2 x; i
  128.        /*计算两个 hash 值的汉明距离*/    8 \6 K& g9 a9 w6 L; e
  129.        $distance = 0;    : G% Z7 N% |; D  i% X3 O
  130.        for($i=0; $i<$aL; $i++){    & ~; P4 U" m. \8 _
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    ( `* B2 H( v  |; ^! N; K% F7 W
  132.        }   
    9 b2 u( Y8 I3 _2 R2 M+ V# V
  133.     + z6 ~/ p& ^% {( u8 L) J
  134.        return ($distance<=$allowGap) ? true : false;    4 \; p/ s6 r/ `5 [/ @& k3 i# d
  135.    }   
    3 Y. f5 t: s4 q
  136.     1 e# Y0 J& A$ `' I) _' P
  137.     ' V# C; @: W, Q7 \5 @7 t( w
  138.    /**比较两个图片文件,是不是相似   
    ) p( l+ w, i7 v7 }1 ?
  139.     * @param string $aHash A图片的路径   # X! q1 i$ J+ }8 t
  140.     * @param string $bHash B图片的路径   
    $ o/ [8 M* w" R( A' |6 H( {! X
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    $ v! ]' n; q. F% ^% `: u. L$ n
  142.     * */   
    & Q4 R  `2 P3 a. Q
  143.    public static function isImageFileSimilar($aPath, $bPath){    / q. U6 }9 ]& x1 |$ D2 j
  144.        $aHash = ImageHash::hashImageFile($aPath);    : ^3 p( [  ^: k! @) Q, w- n( D  a8 V& u! _
  145.        $bHash = ImageHash::hashImageFile($bPath);    5 q) g$ @" M; L( W( x
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    & C; H, a; J$ p$ D4 w9 `- G
  147.    }   
    6 |% H1 q) E4 \1 O: T; w9 H- T
  148.    
    0 r9 R( N% T4 S/ |( Q8 E
  149. }
    : b6 \+ f1 K, X% U0 Z: \
复制代码

* |$ C6 x% m" Z) H9 ]2 e5 J5 \9 S/ _9 B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:12 , Processed in 0.069148 second(s), 19 queries .

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