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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

# S9 G. m9 O+ x7 X1 y由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

9 K3 A! K8 o8 n9 N# l9 D
  1. <?php    % L& d% d$ C9 M, \
  2. /**   
    1 s' R& _2 S9 X5 v9 p2 X6 e
  3. * 图片相似度比较   
    & n0 z) r$ f: I) g
  4. *   - a1 ~' t' w" [. H) Q+ T3 Y
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ( u  L: k1 N  y5 h, q% ]) @( \/ T
  6. * @author      jax.hu   , F# _5 W4 p% _
  7. *   
    ( j5 Y' s2 c3 t0 m1 }
  8. * <code>   
    7 T, p9 u3 q4 x2 G2 x0 v
  9. *  //Sample_1   ' g7 i1 S8 I( [
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   8 H& X' Q. }7 D( P& G
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   # P6 d  ~" X: p6 G4 P; K
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    4 f7 b0 U8 ~: Q8 r+ h. R
  13. *   8 f1 Y* M& W* }+ [  S# `/ h
  14. *  //Sample_2   
    ) L9 s4 Z+ x9 n9 y5 p) y
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   8 d+ n9 y2 ^+ R9 [# f" f2 X2 z
  16. * </code>   
    / J5 q: ^! l6 U4 g3 x
  17. */    6 [! ]( P4 ]9 S9 I' W
  18.    
    & q- Y* C8 d9 }
  19. class ImageHash {    8 K+ }1 @  O0 _/ h+ M
  20.    
    * x8 a/ W) Q& T- p7 {
  21.    /**取样倍率 1~10   
    ) r/ v6 @  W0 R5 n8 }
  22.     * @access public   9 B9 i, h, q, e0 Q
  23.     * @staticvar int   
    6 o0 ?- r$ x% B4 O0 {
  24.     * */    # ^$ A/ ~! [( M9 o( [0 g: N
  25.    public static $rate = 2;   
    3 A2 ?7 o2 A" W
  26.     4 H6 V. |/ y  w" }- s; L( q
  27.    /**相似度允许值 0~64   ) F0 z+ Y, ~- m
  28.     * @access public   
    ) J1 d; D: J% I7 r9 @) Q7 S( l
  29.     * @staticvar int   
    ) m% y4 e  Y$ \! `* s5 o, S
  30.     * */   
    3 U& p$ L$ q( V
  31.    public static $similarity = 80;    2 `, F, h/ M6 a
  32.     ; O2 q4 N# u/ ]+ [/ p, @) m
  33.    /**图片类型对应的开启函数   6 ]! [% {2 t1 o
  34.     * @access private   ' Y3 B3 Q1 L4 _7 g- W6 }3 _
  35.     * @staticvar string   , l/ t3 n# M/ i. B
  36.     * */    ! e+ l2 L) q, ?
  37.    private static $_createFunc = array(   
    ; b) P' l# ^$ N7 C/ m4 l
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ! B, Q, G  N: O2 ~
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    1 c# Q# v  g+ m! f3 m, g
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    - k4 a: I7 B4 K1 V9 u
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    5 H! i$ S& \: N) n8 t2 ]/ U
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    * s* S. U% D3 D2 g- B; c$ E: {( u
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    7 n$ w. n' V3 ]. @) k
  44.    );    : X8 E$ M6 Q5 R4 b$ K
  45.     ! c" m' @1 [: {% A- f
  46.     / r9 t$ M- Y0 S) k' d4 c& I" ~) D
  47.    /**从文件建立图片   : d  `. o. g# p3 b& c3 H. f: U
  48.     * @param string $filePath 文件地址路径   
    " O! @- G/ u) O0 q5 c
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false     R7 |# N% [9 j' E1 z3 f/ d
  50.     * */   
      Y! `! D2 r" N
  51.    public static function createImage($filePath){   
    ( r& Y3 I5 Z! i) Q/ l9 @
  52.        if(!file_exists($filePath)){ return false; }   
      f+ E) }, T, F) F
  53.    
    ; Q8 c$ W* Q/ L' c) k! I* e
  54.        /*判断文件类型是否可以开启*/   
    9 G. j" q, E8 P' x
  55.        $type = exif_imagetype($filePath);   
    ) \# c! v/ U& z" p
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    ( Y) C8 ?4 Z$ ~4 V2 F# c2 l
  57.    
    8 u5 |. t' v$ J: u; h7 ]
  58.        $func = self::$_createFunc[$type];    + I" N! v; [- \/ R. ?  K" ^
  59.        if(!function_exists($func)){ return false; }   
    4 V2 p3 O2 E- Q) V
  60.    
    , Q, N+ V# l, q$ {! F2 f  r* \
  61.        return $func($filePath);   
    - P+ k* A' d- _+ |7 |1 G
  62.    }   
    * S- q! N' }8 g
  63.    
    # M3 e+ v1 H3 a+ u: o5 a
  64.     1 Q8 {) P8 U8 j6 j# o
  65.    /**hash 图片   
      x4 [  a9 \0 i4 s2 L# i( n
  66.     * @param resource $src 图片 resource ID   3 l' B0 [6 Q5 Q- `4 _7 x) C
  67.     * @return string 图片 hash 值,失败则是 false   8 |" t/ I2 f& F, @
  68.     * */   
    9 Z9 J, r  e; \* n% `
  69.    public static function hashImage($src){   
    5 N) [; H  v6 r1 m' I. N
  70.        if(!$src){ return false; }    $ x% A' P& J2 e" C6 }/ @
  71.    
    . Z$ ]0 x) g! B' w1 J- A- Q
  72.        /*缩小图片尺寸*/    / W: j- p( O0 W9 Q) r7 G
  73.        $delta = 8 * self::$rate;    # F8 ?! Y3 u( z
  74.        $img = imageCreateTrueColor($delta,$delta);    : k, R7 F2 r1 F, h
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ! \% S- ?4 u' {7 o! \& O# V
  76.     " J, r" w7 q; |+ P# ]& p' v
  77.        /*计算图片灰阶值*/   
    % ^( h( p' F" x/ ~3 l+ ^: u$ w1 n5 S
  78.        $grayArray = array();    8 z2 x7 p4 s- A! L1 {0 V! a+ z
  79.        for ($y=0; $y<$delta; $y++){   
    0 ~2 m8 ^; f* G* r
  80.            for ($x=0; $x<$delta; $x++){    ! K. \. @9 ]) y/ b" v# i
  81.                $rgb = imagecolorat($img,$x,$y);   
    ) v# y2 @  H9 k1 ^; w) W
  82.                $col = imagecolorsforindex($img, $rgb);   
    3 D5 {8 y. h" r, k5 f, E6 E" W
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ! t5 F* l6 Y( ]3 D0 `7 K7 O: f# x5 n
  84.     4 D9 r# Q: ?3 Q3 b. Y6 t
  85.                $grayArray[] = $gray;   
    & G) U* F5 E  u( D4 z, y
  86.            }   
    1 R5 d: P9 \% V8 y
  87.        }    8 p1 _4 ]& R( k6 l  |4 d- @1 \
  88.        imagedestroy($img);    0 ^& [* ?, s* V+ h' p: Z6 w7 U" Z
  89.    
    3 F5 S1 A( _; ~% [3 v3 Y
  90.        /*计算所有像素的灰阶平均值*/    & K% i) A2 j* O. ]) x- J
  91.        $average = array_sum($grayArray)/count($grayArray);    3 K( k' K" @  f
  92.     4 c3 v% n( N! W# b) ?' @. ]
  93.        /*计算 hash 值*/   
    , i# J$ `1 S/ L0 I- X
  94.        $hashStr = '';    5 g0 a) r& _9 o; S- c) Z2 N- [
  95.        foreach ($grayArray as $gray){   
    # M% R7 l) l% M1 q1 z8 w& C% w
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ' m6 m8 O+ K- Q( z% v! a
  97.        }    5 ?  ~/ N' ^# d. }
  98.    
    ; G$ R! L0 f$ k0 O) Z
  99.        return $hashStr;   
    . ~3 W; D) l* F  b3 L: `& b
  100.    }    ! R% S! b$ d9 v
  101.    
    + K) \! e2 F" Y# N& K( P
  102.     0 K  Q: S0 z/ X
  103.    /**hash 图片文件   4 F. u. l0 W: i
  104.     * @param string $filePath 文件地址路径   
    3 B+ H9 H% P& z( i5 Z
  105.     * @return string 图片 hash 值,失败则是 false   ! B3 c3 _& S3 L# W+ m/ }# b8 b
  106.     * */   
    1 W8 U! x+ ], L$ }+ w3 V: Z. Z
  107.    public static function hashImageFile($filePath){   
    $ V" h9 R7 o- _* y$ u7 R' k
  108.        $src = self::createImage($filePath);    " o$ L. ~6 E3 o( G) f( {) {
  109.        $hashStr = self::hashImage($src);    ! ~0 K% p& b! y3 T9 w" y) j7 x
  110.        imagedestroy($src);   
    5 {) h- J8 ]6 e, r0 g
  111.     + Y7 R% G& o6 d
  112.        return $hashStr;      n( `) I$ l2 n$ r
  113.    }    - d/ k+ l; `0 C% T, \" p* O
  114.    
    ( w% R1 G5 O: G. h& F2 @
  115.     & q+ |/ m% Z, H: N. Q0 x/ `) X0 e
  116.    /**比较两个 hash 值,是不是相似   ' C, T8 ^2 N$ {* U* u3 m2 l+ U
  117.     * @param string $aHash A图片的 hash 值   ( Q* \" H% D" T( `
  118.     * @param string $bHash B图片的 hash 值   * T! f# I/ n0 o) Z3 C/ y2 ?  ^3 r
  119.     * @return bool 当图片相似则传递 true,否则是 false   , ^" O+ ~. m3 U+ ]6 d0 C/ P* J( i
  120.     * */    6 l- F' ]7 F( T% h
  121.    public static function isHashSimilar($aHash, $bHash){    + b/ i3 t: B- l" ^
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    - \/ b$ x  ^1 X( K0 r/ X
  123.        if ($aL !== $bL){ return false; }    " A% h: P, M6 A2 L0 j
  124.     5 O* e4 P$ d  B. S+ Y6 v
  125.        /*计算容许落差的数量*/   
    # ~& Q) _0 u! {# i4 Q
  126.        $allowGap = $aL*(100-self::$similarity)/100;    / {! o/ C. N3 U/ E9 n; |
  127.     $ a+ d$ J) w* m
  128.        /*计算两个 hash 值的汉明距离*/    2 Z# |! ?, a: m0 p5 ]! @
  129.        $distance = 0;   
    ) o% z; Y1 F' C9 f' S) j
  130.        for($i=0; $i<$aL; $i++){    ; K2 g) Q" W2 d; Z0 n1 M; }+ u7 T
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ) w7 a! o- y$ R& t
  132.        }    / u# |) a$ M& j; F! r2 {$ K
  133.    
    4 }4 D) O! Q- V: G" a
  134.        return ($distance<=$allowGap) ? true : false;    8 \& V& g, j3 F) [, H" [
  135.    }   
    7 Y0 l# P0 H$ S9 c! K: O" S* i
  136.    
    ! z8 u5 v9 {4 e9 Y
  137.     2 [7 r8 I, I( h
  138.    /**比较两个图片文件,是不是相似   
    ! X8 J- p7 q  f
  139.     * @param string $aHash A图片的路径   3 r# Q& H- |1 K1 i1 C3 a2 Z
  140.     * @param string $bHash B图片的路径   
    . J! C- b; K/ \6 `
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    7 H5 E9 p6 t# T9 r
  142.     * */    6 s3 u, o. f5 u* G9 C$ i9 T
  143.    public static function isImageFileSimilar($aPath, $bPath){      U7 A# ]- u' x' ?/ z, k
  144.        $aHash = ImageHash::hashImageFile($aPath);    - k  f; x1 j) h% Y9 E. H
  145.        $bHash = ImageHash::hashImageFile($bPath);      U' `' s; I- w0 ?8 d+ N; s
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    " h2 r8 x5 |) N+ c
  147.    }   
    5 x+ m7 O' ], |3 P
  148.     4 y6 P& t& [8 r* q4 A
  149. }' |5 {" y: B# u2 _) i6 h7 w
复制代码

/ c" F" v- m9 _; j2 B8 T7 V: M! q4 j1 e
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-6-18 19:24 , Processed in 0.137738 second(s), 20 queries .

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