cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
  r+ B& E$ O: W% F! P6 [7 n. I/ e, Z) H" l; |3 k. q* u7 i$ p

- \6 {* d) P3 p5 }4 g( I# n) P9 D/ e8 U# Y由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
7 ^  B9 h. X) r
  1. <?php   
    : Q, C/ V$ O$ _  H
  2. /**   
    ' E) F6 d5 ]1 D# P$ o! S; A6 M
  3. * 图片相似度比较   
    9 J  q' a  S; e
  4. *   
    5 o: k7 R( Z4 q% B; X$ {3 f6 Y
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  5 X- U, U( R" ^4 }% M- r4 L
  6. * @author      jax.hu   : U$ t3 f* T7 X6 i! g0 z1 E  Z
  7. *     n" x/ A- N/ v) N# N  c' K
  8. * <code>   
    7 S. _1 O6 B  f: C% j
  9. *  //Sample_1   1 v, V1 K2 O3 ~9 s/ W+ h0 d
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
      e7 C% T% t7 x4 g0 X
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ) ^$ L+ q& Q. d/ _6 M2 m
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    1 o  h0 `5 ~) b, B/ H
  13. *   
    # f5 ?' L. Z8 T8 Z2 T
  14. *  //Sample_2   
    - J( p' c& x6 j2 x$ n
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    ' }4 U9 j: k6 @9 K. h
  16. * </code>   ; ^0 ]. P( u+ ~- x4 x: O/ y* L
  17. */    4 ?+ H; j6 _! ^
  18.     6 g$ g: P( S7 A* D5 K% c' n
  19. class ImageHash {    + J# k" {( k6 e
  20.    
    + k( _/ ~1 L& ]2 G
  21.    /**取样倍率 1~10   
    ! I: \8 u9 C  ^1 v
  22.     * @access public   5 h$ @2 P: Y4 o0 \1 e4 I
  23.     * @staticvar int     u" w& F$ P" f
  24.     * */   
    0 Z6 M# h' E6 t4 U
  25.    public static $rate = 2;      D0 G: j/ [# M4 L
  26.    
    ( V/ s# m) Z# J/ o% z
  27.    /**相似度允许值 0~64   
    0 p4 j# U  X2 r, R9 V
  28.     * @access public   
    + p1 E9 Y6 h$ d( P
  29.     * @staticvar int   
    3 m+ r. P) s0 U' ~2 E
  30.     * */    : G2 s9 y* y" z% \1 {; n, z6 I3 l6 Z
  31.    public static $similarity = 80;    # i& S) l9 S( ~7 P6 T& V0 w' ?
  32.    
    ! ~+ u8 D. ?" V2 m! c
  33.    /**图片类型对应的开启函数   ' j9 p4 {4 l3 R4 r- R
  34.     * @access private   $ H/ {7 H; I9 _5 h1 j9 \+ h
  35.     * @staticvar string   9 X8 L( }5 ^/ _) i6 G
  36.     * */   
    / ?7 R7 p3 r& M6 b2 l
  37.    private static $_createFunc = array(    9 p' ]: z; D0 F7 F, K9 v
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ; h! u6 d' [3 ]% c. w2 i5 q
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    " m, l7 U- B3 i, Z5 K
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    . v2 V! ]/ v1 k& d: _' i
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    & H3 Y" m- g, B3 v" y
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    7 e2 p/ {0 q: ~
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    ' ?% I7 R( n% U9 _
  44.    );   
    ( Q+ f$ u0 c, Y) \
  45.     ( J& q4 k1 |, f% S6 ?; J
  46.     ! h5 U0 |- a. u* A, f+ z. ~
  47.    /**从文件建立图片   * x9 f; [# w; o1 o( D; Q, r. _
  48.     * @param string $filePath 文件地址路径   
    ; q3 |( R' w' J2 u
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   " c/ q4 E9 R# {5 \& P/ R9 F
  50.     * */    # y4 m' j2 ^0 x/ j+ e: F& g
  51.    public static function createImage($filePath){   
    0 G7 C. F( D. M5 e
  52.        if(!file_exists($filePath)){ return false; }   
    8 D0 n7 u! w, s5 K$ W: r2 l
  53.    
    / h1 A2 N' [4 T- a" }! H9 |( g! Y1 ]1 v6 m
  54.        /*判断文件类型是否可以开启*/   
    ' q$ _% Y4 K6 d0 W5 j5 L9 h
  55.        $type = exif_imagetype($filePath);    ) s% }, a% X: ?# M8 `
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    3 H" C* g- M+ X+ G( D* ?6 I
  57.     4 Z' [2 k8 x* {: A0 m
  58.        $func = self::$_createFunc[$type];   
    $ @8 i5 ^6 S9 y" p1 ?6 @% I8 v% \
  59.        if(!function_exists($func)){ return false; }    ! N0 j2 x8 ^2 {2 m. }$ C
  60.     2 m% D( c! g/ |
  61.        return $func($filePath);    7 z7 a' ~! Y* v
  62.    }    4 S/ z& I) L" }
  63.     4 k" Y. P( K- ~. H
  64.    
    ; [+ t+ G5 T# j) X2 k
  65.    /**hash 图片   ) R  f/ {2 a7 m7 k
  66.     * @param resource $src 图片 resource ID   
    ! j/ V# }% n& }: _. ]  e2 ]
  67.     * @return string 图片 hash 值,失败则是 false   ( M, b9 ?' i! x  G$ A, T& z
  68.     * */    * u; i7 j; t1 S+ ~
  69.    public static function hashImage($src){   
    5 ]6 j, E+ j  ?2 [" M, X$ p& a; |
  70.        if(!$src){ return false; }    # Y: ?, Q' D6 f4 j4 c  N# Y+ D
  71.       o, U9 f: \/ z& B1 J' g- g
  72.        /*缩小图片尺寸*/   
    " b7 R7 e: Z3 \3 e) a) e$ i
  73.        $delta = 8 * self::$rate;    ( S: }' {4 v+ c: k3 h
  74.        $img = imageCreateTrueColor($delta,$delta);   
    2 Z. s3 i" W% ?6 S
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    7 A% O# s- t9 q4 p' K* A" K
  76.     ) M+ s% A3 }) y% u
  77.        /*计算图片灰阶值*/    3 ~' X; m: ~5 h* ~
  78.        $grayArray = array();    . p0 Z; P6 y0 f  o0 l
  79.        for ($y=0; $y<$delta; $y++){   
    6 f1 l$ c# {" j, j) q- ]8 S1 T
  80.            for ($x=0; $x<$delta; $x++){    ( p3 P1 N8 U3 T6 V/ ~9 O- b
  81.                $rgb = imagecolorat($img,$x,$y);    - e/ z$ l1 W, P7 i
  82.                $col = imagecolorsforindex($img, $rgb);    ) |* _1 d( Q& N
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    & W' @) ^  c) |9 C
  84.    
    5 o" R. J9 @$ y0 G' x: p1 f
  85.                $grayArray[] = $gray;    $ j4 p% q- h/ R0 p1 ^
  86.            }   
    * m1 \5 A4 V, }  A: [
  87.        }    ( I* G1 l! {' Z" @6 y/ h
  88.        imagedestroy($img);   
    ! ^& R, G& Y5 |' K
  89.     . n* x0 ?% b, A& ]" @( u
  90.        /*计算所有像素的灰阶平均值*/    . E0 u8 b4 |7 G3 H7 E+ M! B
  91.        $average = array_sum($grayArray)/count($grayArray);    ! N1 ^  s7 P* B4 n3 X! O
  92.    
    ; H5 L3 e$ Z' E( a, b
  93.        /*计算 hash 值*/    % h  a+ I" b6 }- i# X: r$ k  k5 p
  94.        $hashStr = '';    4 k8 o/ N  N' k/ v7 F
  95.        foreach ($grayArray as $gray){    ' U# R' s2 Z, ~- h5 R
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    & o+ W1 C/ t* i8 a% ]; Z. e( n
  97.        }   
    - o) ?9 Q1 x& r# \( q/ e% ^. n
  98.    
    ) T. Z! `  t  Q' r8 L
  99.        return $hashStr;   
    / d. J, v" \4 O5 u& R% y* s
  100.    }      m: X4 |" k; ]" [& N
  101.    
    9 F. Z) }+ n, ~1 o
  102.    
    9 U# L2 P$ w( R3 i. U
  103.    /**hash 图片文件   0 a9 t' H( e$ e
  104.     * @param string $filePath 文件地址路径   6 ~) c" c0 V3 b+ S
  105.     * @return string 图片 hash 值,失败则是 false   & s2 ]7 S7 w; E
  106.     * */   
    + U/ e- h; Q! x/ Q& q6 n* p- f* r+ r  I
  107.    public static function hashImageFile($filePath){    & b5 {  N7 J- i6 [$ R' K
  108.        $src = self::createImage($filePath);    " L7 i7 U0 T  N6 F& A7 }
  109.        $hashStr = self::hashImage($src);   
    . F% D  \0 D$ G7 H# R
  110.        imagedestroy($src);   
    & |$ l, o5 X) \! y% x. Y
  111.     9 [# W  o6 z' \0 q. m  Q9 Q0 A
  112.        return $hashStr;    ' z4 [, T( o1 ]. j! \& N
  113.    }    + N) @) C4 t5 j# Y
  114.    
    " Z# e, M* g. s! ^6 b
  115.     + K! q% o  r9 l
  116.    /**比较两个 hash 值,是不是相似   7 O( |3 A# F4 W$ n
  117.     * @param string $aHash A图片的 hash 值   
      Y, _1 J9 j# j3 M, J! r1 k' C
  118.     * @param string $bHash B图片的 hash 值   7 \" c6 f* ]7 E3 ]
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    + k. Z3 u4 w0 T6 I3 a, Q
  120.     * */    - O+ b9 F. M0 c: Y: Q/ j  w
  121.    public static function isHashSimilar($aHash, $bHash){   
    1 c! K7 T, N8 U
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    * Q. r/ U, a9 z2 l  ^4 S1 T
  123.        if ($aL !== $bL){ return false; }   
    5 R& |8 s: n! e& O" `* }  H
  124.    
    $ G1 k0 ]) o" Q2 N% m+ i7 t
  125.        /*计算容许落差的数量*/    6 _; r/ s! L0 k* C; k2 w0 |
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ! G6 O) J) O: a( r/ s  m
  127.    
    ; U6 W" q' h% A% U8 x
  128.        /*计算两个 hash 值的汉明距离*/    4 @/ u/ i( W1 \: j
  129.        $distance = 0;    - s! m& @2 U( {% h  V/ z9 Y2 [% ^
  130.        for($i=0; $i<$aL; $i++){    6 ]# O/ p4 B' c/ F# |
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    & L3 N, ?7 B6 `: {! @+ z' J
  132.        }      [  U" k: c$ O4 a9 j
  133.     1 \! U/ E$ n/ W2 O
  134.        return ($distance<=$allowGap) ? true : false;    % v$ `( e% t, P2 c( A% J" q3 J
  135.    }    , F- e. n6 C, p! l0 {* G
  136.     , b% S- k5 E6 a2 ?  A$ Y
  137.    
    ! e1 H# i  V$ i- l0 u
  138.    /**比较两个图片文件,是不是相似   
    3 x" E$ I9 A* y; {* n; M" n. [8 L
  139.     * @param string $aHash A图片的路径   
    * }8 J% s8 D, f7 V
  140.     * @param string $bHash B图片的路径   
    - u; I3 X2 f$ a( \0 f2 C' S' v8 E
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ( ]! k& N3 l9 ?
  142.     * */   
    # u: ?" R: u5 }5 S; m
  143.    public static function isImageFileSimilar($aPath, $bPath){    ; h: i) \' V6 I3 V! c! _
  144.        $aHash = ImageHash::hashImageFile($aPath);    ( r; N2 Z) \9 s1 s7 P' ?. g
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    - a9 V) e% B- ^* J
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    # S) _9 d4 x1 ^+ a% e1 u
  147.    }   
    ; @# D9 d8 `% R, K. F* G) C* k: Y! l+ l& D
  148.     ! d# A, L' O( {! Y  o4 s3 R! [
  149. }# [) \3 C& C+ L! L. t0 ^) c1 \
复制代码

( d. p8 D: {5 V" Z8 ]/ I0 }; K% Y/ Z8 [
& A7 h; i3 Z' R6 h; n




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