cncml手绘网

标题: 分享一个PHP简易的图片相似度比较类 [打印本页]

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图/ \! X( `% J0 K

9 j/ }0 E: G3 c1 m( c  n
4 K; |: X; f" {. k. u' _
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

+ v+ z2 l% ~9 H0 }( j
  1. <?php   
    , U+ ^- O  Y: L3 @" T2 ~# G( Y+ w
  2. /**   
    2 M; u: _* o1 M3 ~6 J% m
  3. * 图片相似度比较   0 o: y# G: `* A2 u# x
  4. *   8 _3 m; ?" d/ r+ u
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    * d; j% y  G* }: O
  6. * @author      jax.hu   ( Y4 g, B1 s! B7 F# L
  7. *   # E& p) `) A: c* V
  8. * <code>   ! B4 X& x$ X: t% {2 b
  9. *  //Sample_1   : W2 ~. R# [6 J: T% G* I
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   8 }* \; |1 C" }
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    9 ~( T3 J' G7 t
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ; P% P  M5 w+ L8 k% v- b
  13. *   $ m6 t4 r4 h+ \9 m' X
  14. *  //Sample_2   . J" j% B6 }$ g; S; T0 j9 {, g! w
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ' p0 B% F. g+ U! [9 ^, M4 O1 Y& X2 R
  16. * </code>   5 i# _* I# F$ ?# e. R
  17. */    " T( P; S% K& v3 r3 K% Z
  18.     ! a& g; ~9 F7 w8 M" F/ m
  19. class ImageHash {   
    3 E( S$ |* u+ I* \- T  v
  20.     , e/ D7 o/ _. ~5 G$ ?6 S3 D
  21.    /**取样倍率 1~10   
    1 m) N( i" s6 ?3 f! F
  22.     * @access public   & O: J- S) C$ u
  23.     * @staticvar int   9 }+ D; b6 @6 Q* k1 J. e
  24.     * */   
    $ b' w# Z7 f/ X' u
  25.    public static $rate = 2;   
    ) c: P* V* R* o6 N
  26.    
    - }2 P' b5 W4 X2 n2 K7 @
  27.    /**相似度允许值 0~64   % R1 @& l0 h4 \
  28.     * @access public   
    6 w8 Y! `' {& l+ j5 ~, g6 P
  29.     * @staticvar int   ' s- J' r# [* ~$ B
  30.     * */    + W8 J) _( o1 g+ f6 f+ V/ Z" u
  31.    public static $similarity = 80;   
    & ]4 H- e0 D4 y; m- D& L  P
  32.    
    ' R( N- \2 X# q' a- \& Q! M
  33.    /**图片类型对应的开启函数   
    , h  S! P3 j& R% |5 r  t0 u+ k
  34.     * @access private   
    : p) j0 c: `# d/ I/ v  E
  35.     * @staticvar string   
    6 u& Z3 e. u- ^7 k
  36.     * */   
    : l2 T. ?9 ^! d
  37.    private static $_createFunc = array(   
    , `' f7 x9 e, H3 j! _; r
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    & ?+ ~- _% ?# D& c0 |& n) k
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    " E6 e4 K# \% N; E/ R
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    " u0 ~" [! V6 e$ G/ E
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    7 M, P- C1 S2 O4 L5 ?- S) o
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    ' w) z, [) [  e# Y# A+ G
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    $ z: @6 P% Z7 L& T4 i9 J) q
  44.    );    7 ~% T' [+ Q$ d9 t) X* f
  45.     ; u/ {8 \$ I& `  b+ |% Z, f8 F
  46.    
    , G! M: M# b0 A6 ^
  47.    /**从文件建立图片   2 |$ P2 v) e/ v
  48.     * @param string $filePath 文件地址路径   
    ' a/ B$ O* U4 j
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ( Q4 m3 F6 {" O( O9 Q; Q9 f
  50.     * */   
    0 q+ V  \& y! ~- ]
  51.    public static function createImage($filePath){    # |. P5 }% h( e9 m
  52.        if(!file_exists($filePath)){ return false; }    2 n3 D, g1 h4 V9 E: u, \( N
  53.     * V  k" C, F! }9 @
  54.        /*判断文件类型是否可以开启*/   
    # f# a" L8 F/ t2 H8 T
  55.        $type = exif_imagetype($filePath);      C2 G) Y3 r3 y. {' w
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    8 T3 V, K, }# j) i  g- i2 E6 {
  57.    
    9 t' w, U: q8 |2 L/ @: I. d7 S
  58.        $func = self::$_createFunc[$type];   
    $ B9 C( p6 Q! X, m; s0 \. l
  59.        if(!function_exists($func)){ return false; }    4 X9 p2 J( D' L: c" U% i
  60.     0 R8 n; `5 F% M  j1 B9 P' w
  61.        return $func($filePath);    , v* ~3 K1 ~0 q: z# L
  62.    }   
    % n2 k7 a" k! C* w, ^
  63.     3 `$ D, [0 F1 }( c, t* O( g
  64.    
    . Q4 [, X5 I, R/ [5 l
  65.    /**hash 图片   9 k) I7 z, F( N+ \8 R. W* y0 W- _) u2 t, u
  66.     * @param resource $src 图片 resource ID   
    * K! u  ~' G8 T+ Y. q( ~6 R
  67.     * @return string 图片 hash 值,失败则是 false   
    & E6 L, C6 j9 A( T( D. N
  68.     * */    6 V- ~7 n' @& o: m( l9 ^
  69.    public static function hashImage($src){    # ~7 ^8 Y2 B4 H1 `5 J! B/ e  ?
  70.        if(!$src){ return false; }    2 U0 o6 f# I- w
  71.    
    4 E+ T+ e0 e) I3 }2 C, X1 q
  72.        /*缩小图片尺寸*/    * _/ I# X1 P9 N2 k( Q; ^7 [1 g
  73.        $delta = 8 * self::$rate;   
    + c# \; C" O* F0 X; E* w5 A
  74.        $img = imageCreateTrueColor($delta,$delta);   
    7 o( t1 }& D; j
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    : f* X9 S, w0 Z% q+ p
  76.    
    7 j+ O2 e* Y* |6 W% S
  77.        /*计算图片灰阶值*/    ) Y0 P( Q' J2 ?+ b# f  P
  78.        $grayArray = array();    % g8 ]& U0 k0 ^! m& E" C
  79.        for ($y=0; $y<$delta; $y++){    ) ^3 d% D7 p: {2 F- a7 E$ T
  80.            for ($x=0; $x<$delta; $x++){   
    - C8 P2 Z) G- n  \4 h
  81.                $rgb = imagecolorat($img,$x,$y);    - h4 S# i* Y3 G9 K
  82.                $col = imagecolorsforindex($img, $rgb);   
    , c6 U. x9 `8 @4 N' {1 R
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    6 |% B* V$ T. Q1 R! e! b2 F
  84.     ; N1 O0 S  e5 |6 y" f1 u' Y; A
  85.                $grayArray[] = $gray;   
    1 ^* Z& a% N8 P1 W0 Q: K% N& p
  86.            }   
    " S! N+ s$ b9 g* s
  87.        }   
    + W6 R$ v3 ^; s/ q3 V% Q0 J' C
  88.        imagedestroy($img);    ) ~1 a: C, d+ z+ o- S, ~3 s2 W
  89.     $ f1 s7 i3 H) J7 x0 I2 _
  90.        /*计算所有像素的灰阶平均值*/    ' @/ p" K8 U) a* [: C" Z  o
  91.        $average = array_sum($grayArray)/count($grayArray);    + x% @, D3 [0 |7 b7 z5 p) A
  92.     . S7 ]# j  v! s. S* Q4 O
  93.        /*计算 hash 值*/   
    + g/ a2 v* P9 N
  94.        $hashStr = '';   
    * B. h& e1 K5 C- V$ u7 N
  95.        foreach ($grayArray as $gray){   
    , D% C2 }: S# t- F/ Q* g7 I; u% E
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
      j2 ~8 R: x1 d7 k# E' i/ b7 j
  97.        }   
    3 g" r7 [7 l6 g
  98.     . h1 e% L4 M7 v0 L6 ?- J( M# Q/ N
  99.        return $hashStr;    ; o' i( i& `  l6 ^
  100.    }    , z6 }7 P2 @9 _# y( B
  101.     & F1 H1 N; Y- q  N1 s8 u- M% P  |
  102.    
    / b- Z8 ^. U+ E2 Y2 z& L; ~
  103.    /**hash 图片文件   : `$ f$ K3 v  e6 W: k
  104.     * @param string $filePath 文件地址路径   
    4 k4 k* F2 X9 \, i, E) K
  105.     * @return string 图片 hash 值,失败则是 false   8 b# s" n8 Y% S" m+ \
  106.     * */    / ?2 d. L) s; y( V  X' A
  107.    public static function hashImageFile($filePath){   
    & I7 f: I' |! Q7 O* J
  108.        $src = self::createImage($filePath);    2 v7 y6 @! K. l" H
  109.        $hashStr = self::hashImage($src);   
    8 ?' c% B  b3 }. s# S  f) p) C7 ^
  110.        imagedestroy($src);    2 T& v* C; Q% F/ o) v1 G
  111.    
    8 N; o8 {8 X* V' K
  112.        return $hashStr;    & \/ Z8 l3 a1 `( X  e" t
  113.    }   
    & O5 q8 [* a& D: ?
  114.     ' e* F7 }) `  C/ ]( ^8 ?7 S! R8 w6 ]
  115.     3 {% h1 J+ \8 J! m( {' G
  116.    /**比较两个 hash 值,是不是相似   ! A- T$ F  f' p: S) _4 q9 P
  117.     * @param string $aHash A图片的 hash 值   
    / }9 V) z, |) H  {, S7 H
  118.     * @param string $bHash B图片的 hash 值   ) m3 z3 p0 ?6 T0 p! c
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    , Y- j( b( M, K4 o! L8 F$ a; m
  120.     * */    4 ]" g) J! b; p4 v
  121.    public static function isHashSimilar($aHash, $bHash){   
    4 \8 I: \4 R* V4 x- k
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    ( O) K! \! S' \
  123.        if ($aL !== $bL){ return false; }    5 _& ]9 K5 M' r, F  d* K
  124.    
    / O3 v: A' [4 J9 ?, w0 l( @8 C
  125.        /*计算容许落差的数量*/   
    . }$ U( c. p. I! C- H$ \5 {
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    8 i$ \; N' w+ m. \) j. y& s2 e
  127.    
    3 o' Z$ ?9 C* T1 N6 r) {. ^
  128.        /*计算两个 hash 值的汉明距离*/   
    ! ?- t% Q$ N% N! k
  129.        $distance = 0;    ! X5 r  m$ B" o" H- q: Z. P- N
  130.        for($i=0; $i<$aL; $i++){    # x: b8 G, y9 Q- }
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    , ]3 D3 K$ v8 H
  132.        }   
    0 V7 a$ i; b9 l
  133.     ( v5 x; E) Y; V, I- I; r, R& v
  134.        return ($distance<=$allowGap) ? true : false;   
    : F- \# w+ f7 H# K' O  M
  135.    }    # G6 |0 W6 |# }2 Q1 R
  136.     ! Y& p8 s9 E$ w0 h
  137.     % q+ Q# P( b8 {4 [9 W
  138.    /**比较两个图片文件,是不是相似   6 i: M1 O' f- r( \+ Q
  139.     * @param string $aHash A图片的路径   6 J% l5 S( Y  x# x8 f+ ]" t
  140.     * @param string $bHash B图片的路径   
    8 I0 n9 [4 m/ Y% i( n
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ( g/ e( v) K8 T6 \5 u; P4 @8 N
  142.     * */   
    ' h& \  }6 F/ A' f1 d# B0 e4 ^2 S
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    0 a) y: O+ l% _- [. ~% {
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    3 i- A$ C" w- o% X2 K& o4 \* d9 @
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    6 T* j) b! E7 u% M' @# M% M
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    & d0 w* ?) }9 `' u% U8 K
  147.    }   
    ' M' ]" h% Z6 N! u
  148.    
    ! k! n; v- i) E7 {
  149. }$ ]& ^  A4 a. G0 k3 j
复制代码
  y9 |+ a. N( t$ t- H8 b' c. h- k
# Z; u% M% B; p0 d; y9 n: U' b





欢迎光临 cncml手绘网 (http://www.cncml.com/) Powered by Discuz! X3.2