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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" X) S& `9 F8 ~. m) I. r由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
9 Q) b5 b( `( O) A1 B; V8 @% Y7 h0 R
  1. <?php   
    4 ~1 r2 x7 n6 m/ n4 Z
  2. /**   
    6 T4 F$ a  v) P4 `. y
  3. * 图片相似度比较   0 t+ d  A# f; ?8 R; S- `
  4. *   2 D: U; [8 I- w4 B1 ?7 V; |( V
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ) B8 c- _9 c7 U& q; Y( S3 h* o/ \
  6. * @author      jax.hu   
    % H: D( U6 Q. x/ p- X7 v
  7. *   
    ) A, W. E6 M! X5 I' H5 b/ l& F
  8. * <code>   
      q& ^/ e* H- ^9 o
  9. *  //Sample_1   & E  k, \. w; M8 |2 W" V
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   , W( o5 W+ M, `
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   : A! G. m: {7 ~9 N! ~
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ) _% m$ u4 g# {( Q% y/ f. z
  13. *   
    8 b. D3 @$ o/ h) c3 P1 A
  14. *  //Sample_2   5 p/ ?1 ^7 B* G" m: M
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   # n( n4 @4 E. a2 b" J8 n' K
  16. * </code>   8 P6 D: ^  @; j" u2 C
  17. */    + e$ I7 v) e3 }/ b+ |1 ]
  18.     1 W8 Q6 w. B( j4 t
  19. class ImageHash {    % j1 n& h7 ]) R; u- f
  20.     1 q/ ^0 \# _7 Y& l' J; g
  21.    /**取样倍率 1~10   
    ( C% A# T) P0 u+ [8 b" l0 b
  22.     * @access public   ) d: k/ K! S6 G3 S% G
  23.     * @staticvar int   ; ]8 i5 E; V9 T
  24.     * */   
    6 d- Q! K4 F; w2 Z( N8 n1 g2 L) ?
  25.    public static $rate = 2;    6 {, T1 w  K2 j0 C7 b
  26.    
    . f; w+ a9 l* V- s8 @" S% b
  27.    /**相似度允许值 0~64   
    % Y: L' B  c9 X9 S$ Z
  28.     * @access public   . x" m+ a) h0 U1 g* n) }
  29.     * @staticvar int   
    8 G- W! T( `7 N  B( }* U- s' Y  t( w
  30.     * */    - q. t$ w% x8 F+ ~$ K. d- v4 T
  31.    public static $similarity = 80;   
    2 T* y/ ~3 c5 y8 O1 H
  32.     9 M6 ~& P8 J6 N7 S3 e; @
  33.    /**图片类型对应的开启函数   
    ! P6 L1 d% K$ @2 g# c
  34.     * @access private   
    % i9 L" Z( V6 T" m8 J! Q
  35.     * @staticvar string   
    ' S- h+ ], L6 Y0 d, ~3 d
  36.     * */   
    6 f3 e- [* K, t; p9 t1 U; O
  37.    private static $_createFunc = array(    : l% U! Y: v+ @6 |9 Z* y, y
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    % n. L6 n& K: l
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    2 D* D1 }, M8 r( g% z, e" F0 X, z
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    2 l8 {3 g+ U- w: Z- {: X1 ~; k
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    4 Q& j8 l9 H. @& t% O3 \
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    $ U; F% ?. U( f1 N$ S9 }
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    * f! X: @: i. c) r# r
  44.    );    $ a$ X7 z5 b6 J8 A( |7 H
  45.    
    " P  Y, d; D+ x) z3 J1 l
  46.     * X% U+ M0 _( T8 I0 @
  47.    /**从文件建立图片   
    ( X2 ?0 Q! C; k
  48.     * @param string $filePath 文件地址路径   $ @  E( i/ v. f  \
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    8 d6 y( m1 }: s5 z
  50.     * */    ! Z8 x6 x6 Z: I! p  X3 n0 {5 O
  51.    public static function createImage($filePath){   
    8 M0 s2 H, k# k7 u" t
  52.        if(!file_exists($filePath)){ return false; }    * U" Z* \8 F/ T# J- V# Q) f3 e/ L" T
  53.     3 L# y* S% L6 L4 d% I
  54.        /*判断文件类型是否可以开启*/    9 V$ a7 \8 z2 F
  55.        $type = exif_imagetype($filePath);    6 E) C0 z- A4 @3 |
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    8 S: R3 c; y% z4 o) w6 ?$ ]
  57.    
    7 \* @: @2 Y$ O0 e7 o7 R9 H
  58.        $func = self::$_createFunc[$type];    8 R) ^5 l4 X4 }! r
  59.        if(!function_exists($func)){ return false; }   
    + w$ a( X7 j6 ^7 X; V6 X5 v) d: S
  60.     0 ~4 s" t+ d2 L! |7 k* ]7 A' L
  61.        return $func($filePath);    5 m& q+ f1 s) ?$ d5 t. y$ u
  62.    }   
    3 q7 G1 _0 h' J8 u3 P
  63.       h5 d& M. l5 S$ J/ g
  64.     ' F# r' y" a7 i+ T8 H
  65.    /**hash 图片   
    + Y/ G: Z) H9 u0 @: Q8 k. c* u& H6 |4 E
  66.     * @param resource $src 图片 resource ID   
      {1 E! f8 m; Z& h9 t9 \
  67.     * @return string 图片 hash 值,失败则是 false   ( W  u+ {, Q$ s- n7 `
  68.     * */    9 t6 K2 E/ j2 p1 ?
  69.    public static function hashImage($src){   
    1 u' L6 Y4 P7 T# R' {* B
  70.        if(!$src){ return false; }      }! p2 q; K8 _. h8 F- ]3 z. _
  71.     1 c! W1 Y3 H, E9 Z$ ^" [) u8 ?; \
  72.        /*缩小图片尺寸*/    5 U# l+ ?1 _8 b6 y1 j, }5 ~
  73.        $delta = 8 * self::$rate;    ( f( R+ R7 y3 n, B3 ]% {2 \  i
  74.        $img = imageCreateTrueColor($delta,$delta);    - [& k, O1 @% H
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));      M/ v; L7 E% Q* A& t% ]$ I
  76.     4 R, X) B& K7 _& n4 v2 }: a
  77.        /*计算图片灰阶值*/   
    $ d" I1 b, x5 a, L/ g. E* ?
  78.        $grayArray = array();   
    & @7 o$ \! t  R4 e: x, A5 x
  79.        for ($y=0; $y<$delta; $y++){    : r; i* P( c. K8 p) V+ n' S
  80.            for ($x=0; $x<$delta; $x++){    , Y$ T2 d. a! G! P- y; L
  81.                $rgb = imagecolorat($img,$x,$y);    / b' s, i  @2 _0 R/ t
  82.                $col = imagecolorsforindex($img, $rgb);    ' s: V% N% L9 D9 ^4 \- Y8 a
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    , ?3 G( U3 t6 O; C1 }
  84.     4 T- D' j4 G; j$ R
  85.                $grayArray[] = $gray;   
    4 A  e8 C6 y3 `5 D, W! M
  86.            }    4 _9 W: }* t' {* z5 l- b
  87.        }   
    + p6 W5 j* m6 i5 N
  88.        imagedestroy($img);    2 o  q+ r& i/ v$ @
  89.     3 o7 ^- J- q* T. G/ z/ m  N2 T
  90.        /*计算所有像素的灰阶平均值*/    2 Y$ V9 }/ i5 r8 i
  91.        $average = array_sum($grayArray)/count($grayArray);   
    * W  i1 X5 [  [% c% ?+ k
  92.    
    - e: G6 x1 y1 R- L1 j. q
  93.        /*计算 hash 值*/   
    5 J, o' X2 W$ B2 G0 A
  94.        $hashStr = '';   
    ( ^! e- L0 f0 D1 e! {9 _% i/ P0 q
  95.        foreach ($grayArray as $gray){   
    ! S6 Y, E7 J# w$ W! s$ b5 M4 O/ Y6 x
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    + B3 i6 y( v/ q2 o& Z+ \
  97.        }    3 {0 |. W. d. p. _+ ]) j
  98.    
    / r- i* A$ S- g$ O2 j
  99.        return $hashStr;    3 W0 K# A0 l8 t6 Z( H! R
  100.    }    ; \  k: f" n0 i# P, g
  101.     , F9 L9 }+ V6 Z( z0 V  Q
  102.       v* C- L% \( Z& ?% ], \
  103.    /**hash 图片文件   9 J/ A4 K) I* Y& d: F
  104.     * @param string $filePath 文件地址路径   ( l% |6 c+ r, w- D" w0 i
  105.     * @return string 图片 hash 值,失败则是 false   3 y! j( @9 g3 v/ r
  106.     * */   
    2 y! T6 ^5 z. N/ q1 f5 U' X
  107.    public static function hashImageFile($filePath){   
    # B$ g, m  Y% o' N* ^8 X, v$ w
  108.        $src = self::createImage($filePath);    ' d& {7 @! g0 `/ v% P
  109.        $hashStr = self::hashImage($src);   
    * U+ i! z! U( J; B; J
  110.        imagedestroy($src);   
    $ U: |. e6 l+ E( r+ O# `$ K
  111.     5 n- q6 t3 }# U/ M- B8 f! _
  112.        return $hashStr;   
    ; Z0 I1 V: b6 q1 E3 ^
  113.    }    + w! n" C4 j6 M% m
  114.    
    0 X" a  l$ z2 z1 w; T' V  V
  115.    
    ' v; C8 A2 C6 F
  116.    /**比较两个 hash 值,是不是相似   ( \+ X6 H/ @- R9 N2 _; Q
  117.     * @param string $aHash A图片的 hash 值   
    # j- L6 O( |/ y" \
  118.     * @param string $bHash B图片的 hash 值   , W$ ^& O" Z8 `6 B% h+ r
  119.     * @return bool 当图片相似则传递 true,否则是 false   ! A* M3 |' r( q6 b
  120.     * */   
    # S/ q6 U* }4 o6 f7 C3 ?( [
  121.    public static function isHashSimilar($aHash, $bHash){   
    9 {( b. v; [) p3 Y- |) \
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    % M4 I  D/ ^  P2 D1 O
  123.        if ($aL !== $bL){ return false; }   
    0 E8 f9 t  G* j& n. N, s7 ?/ \$ e% |/ \! r
  124.     2 a! u5 j  r% k( n$ ^* W+ j
  125.        /*计算容许落差的数量*/    7 m0 N3 ^, ]$ H( d) H5 z
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    : G% x: G/ C* y% ]7 W' s; `, q
  127.    
    % I  s+ [5 C- n' q* _, r% O
  128.        /*计算两个 hash 值的汉明距离*/    0 o) [& e$ [- v' k3 c7 u
  129.        $distance = 0;   
    1 I7 m' W/ v- z4 q, s$ q  v6 C
  130.        for($i=0; $i<$aL; $i++){   
    2 Q6 W$ W$ m( c5 W4 K" B6 M; p
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ) @+ G5 F% Q- r' {4 k7 I
  132.        }    + d: \( B: C; z# c1 g4 H0 |% I5 m, G
  133.    
    ; M9 L* q9 w- l  x, o% v" `
  134.        return ($distance<=$allowGap) ? true : false;   
    ! p; f' r% o7 U
  135.    }   
    - `- o, t6 i- c
  136.    
    . v" X+ F, z  J! M$ {+ ^7 {
  137.    
    7 x8 u2 o: G* W/ }0 B; b; R* @
  138.    /**比较两个图片文件,是不是相似   4 n! h5 g: @0 o! v. H: ]+ u$ W
  139.     * @param string $aHash A图片的路径   
    + N' z! W4 A8 y
  140.     * @param string $bHash B图片的路径   . X, G7 O3 Y8 k: Z6 l! d- b2 t; f
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    # Q9 q6 [% H4 \2 O
  142.     * */   
    2 l! d7 S+ @/ t- x# R5 E0 {- N
  143.    public static function isImageFileSimilar($aPath, $bPath){    ; X& i0 S& d! ]: t
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    4 ^- l: I8 n) A8 `0 K2 w
  145.        $bHash = ImageHash::hashImageFile($bPath);    ( z' m+ X, Z9 a  ]; ]+ W* s- ]
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    / i7 v9 g# k- Q5 h! q7 ^! m5 [
  147.    }    4 v1 X; `4 e( [$ Q' a! ]3 v  H
  148.     6 w- b) `& G0 D& j
  149. }
    . [: j" ]8 X) p7 I- e6 S6 J
复制代码
1 G, Q9 t* c  S  v

1 _! c. V2 c' @& `
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 15:49 , Processed in 0.067283 second(s), 22 queries .

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