cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
+ `* ]  V/ C0 n  @1 }3 j% V# y0 l( Q: b' p9 N; z

- @& i4 i/ C! r  z& o5 V, h由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
9 r3 \& i5 _) ^3 H
  1. <?php    : k! \: g. G7 K1 o4 T3 U8 w
  2. /**   3 p7 O1 F7 E  {
  3. * 图片相似度比较   , d! k, D5 V$ h2 H9 N1 R8 K
  4. *   
    ' |4 I5 b. s7 G
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;    ?2 Y# U  i& C( J
  6. * @author      jax.hu   : O/ m* v; a& M, ^
  7. *   7 J2 B  h1 p$ ]7 N* Q8 w$ w5 F
  8. * <code>   
    7 S; G; r( t( s: Q. ^
  9. *  //Sample_1   
    : o5 T; ]4 w! B3 V  K8 ]# ?; [
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    " j' b3 r( u8 \/ O
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   1 C6 o4 n8 W- X( k% @& L
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ; R! f/ N7 K7 R0 W" I  ^) @& \
  13. *   # z0 d4 a( h, ^" m  n; f- v
  14. *  //Sample_2   % h3 p1 P9 V0 a& N
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   - d. F" ]% z4 P: [8 Y* @
  16. * </code>   
    % I. x9 V4 O# E+ ?- _
  17. */    ! y! D6 g6 l% i
  18.     . E7 T3 n  m% c8 `: f& E
  19. class ImageHash {    5 G) a3 u) H+ q$ h& B
  20.     , S% a3 r1 {6 a  J1 k+ a  ~
  21.    /**取样倍率 1~10   
    ' e0 C* b6 ~! ~0 y
  22.     * @access public   
    8 z: r3 A8 ]0 ^) {) J
  23.     * @staticvar int   1 j) z, U- Y# ^" u
  24.     * */   
    $ L$ o  Z! ?& m7 z0 m9 z
  25.    public static $rate = 2;    8 B4 g3 [/ N- \3 y: v: S6 s
  26.    
    ) y! h: [( K9 N, d( ?& K* `  H
  27.    /**相似度允许值 0~64   
    ) m2 X7 @; M8 H* s) p) {
  28.     * @access public   
    5 m  J9 W$ d6 f0 j& B
  29.     * @staticvar int   
    9 z- Z# O) a# ?0 _# P" d% x
  30.     * */   
    5 z& B6 o& G+ ]+ d# x1 E
  31.    public static $similarity = 80;    5 r. q0 i" D( b4 n8 j& t
  32.     ( z) Z" J6 B- F( s
  33.    /**图片类型对应的开启函数   
    & G; q, y$ V( e% V9 X. p
  34.     * @access private   : ^( ?  |1 W6 c3 q
  35.     * @staticvar string   " @9 V2 }) U9 W9 q8 y5 z" N
  36.     * */   
    . M8 a) N2 \1 ~# M
  37.    private static $_createFunc = array(    0 |  g2 m! {8 f  C3 [
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ' U. V7 g7 _& U% G, c$ ?
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    & \1 [% f8 k# `! ~2 n+ `
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
      l* W  i- R4 @: E$ j
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    " p: m1 Z$ i" ]( l
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    1 Y7 u/ V9 U6 }1 c/ D
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    1 e6 `, }0 s1 E  y4 `5 G) ]
  44.    );   
    . b% M  F0 P# m# g
  45.    
    2 v$ |, g# [& Q6 n. r
  46.     0 W! z# I" Q& Z  G+ w+ C5 y3 i
  47.    /**从文件建立图片   ( Z9 W& m' O' {- N2 ~! G
  48.     * @param string $filePath 文件地址路径   
    * ~% B% B3 T  U6 U
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   8 ]6 n* H% O0 t. e, ^) [  r
  50.     * */    3 P9 \3 A1 o  q; K! L- }5 B% t
  51.    public static function createImage($filePath){    4 I4 w+ U1 s  p3 r2 i
  52.        if(!file_exists($filePath)){ return false; }    # z5 X' W" k" p
  53.     ) q8 `4 P" H, X# {" q+ T
  54.        /*判断文件类型是否可以开启*/    / h/ _# N; y$ i& p) l
  55.        $type = exif_imagetype($filePath);    - P# u+ N' _/ L; ]
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    6 |7 g8 k- n, i/ }, \, i
  57.     7 ^  R" J# H0 ~( c
  58.        $func = self::$_createFunc[$type];    0 f: R; m0 X5 [, Y, i
  59.        if(!function_exists($func)){ return false; }    4 @4 s; d. |8 H' i) u: J
  60.    
    . e# O- n( [, d
  61.        return $func($filePath);    ; A, U1 _; |" B9 h0 b. l1 g
  62.    }   
    5 g& F  r: q. _4 L. |  \4 v7 }9 u( V4 I
  63.    
    # Y& R! r. T1 i: e: _, ~6 B* f8 q5 F
  64.    
    5 F! g; q( J: [& D
  65.    /**hash 图片   - H% l' N0 d( V5 D9 A6 ^8 J1 b) m
  66.     * @param resource $src 图片 resource ID   
    ( u: Z7 q4 p6 s9 [
  67.     * @return string 图片 hash 值,失败则是 false   
    3 g; d* a# \3 G3 g; \7 l/ P
  68.     * */    4 F# ?+ d8 S/ N! G
  69.    public static function hashImage($src){   
    1 F' M; k3 b4 r8 i: V
  70.        if(!$src){ return false; }    ( L0 {, @% C4 m" ]7 B( E% g! Q
  71.     + T8 |- V  h  G
  72.        /*缩小图片尺寸*/    6 |4 i/ d* h4 q
  73.        $delta = 8 * self::$rate;   
    9 B; B. M: F* X: R' g3 l
  74.        $img = imageCreateTrueColor($delta,$delta);   
    6 W5 s5 A3 S/ }7 A- |* [
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    6 q% x6 v) [7 ^* O
  76.    
    " g4 W; a9 Q- U8 Z' X8 [# z
  77.        /*计算图片灰阶值*/    $ ~6 E6 `( _, I0 U0 W1 S
  78.        $grayArray = array();    3 g, T9 g, i2 s5 p8 J' ~- v
  79.        for ($y=0; $y<$delta; $y++){   
    & a3 _0 b2 x9 R2 h  L
  80.            for ($x=0; $x<$delta; $x++){    2 ^+ a9 Y4 q" K6 v% ^+ y
  81.                $rgb = imagecolorat($img,$x,$y);    5 j. r4 A0 K  t0 ^5 [9 t3 f
  82.                $col = imagecolorsforindex($img, $rgb);   
    , Y7 l* q* Z$ c. f0 e
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    1 n/ e. |, u  X$ {. A+ ]
  84.     ( g9 i& V" |) g2 Z4 `/ H# |
  85.                $grayArray[] = $gray;    . l2 k, M" Z/ x
  86.            }   
    9 l2 @! u" }) c1 o& V5 g
  87.        }   
    6 g. x9 \3 x( i5 ]
  88.        imagedestroy($img);    0 O( c8 }2 Z0 F' f9 u! ^- x; I$ d
  89.    
    ' B# o* V# f* t& r2 f2 S
  90.        /*计算所有像素的灰阶平均值*/    + _2 [3 R1 |! p: a$ X4 P6 J) \
  91.        $average = array_sum($grayArray)/count($grayArray);    ' G1 s: a7 V/ O. t+ N7 ~4 a) [1 }2 I+ i
  92.    
    8 e3 u/ a9 ?& ?
  93.        /*计算 hash 值*/    : ?+ t2 q- R8 t) c9 ?! j  x
  94.        $hashStr = '';   
    ( u3 N' G! X& g: p0 f$ [
  95.        foreach ($grayArray as $gray){    & A* _/ R8 H9 l, m$ d) _
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    / i( d7 y: G  s+ t& Y
  97.        }    8 ~3 [) W# |! J
  98.    
    - H9 N) ^' P" e: m  z9 k8 Z
  99.        return $hashStr;   
    $ {9 j; n/ t3 K6 F$ ^1 i% k
  100.    }    : T9 A* a8 @& d2 C! G
  101.    
    / [: _+ j* O5 x# X- l' J4 x2 {* V
  102.     % K8 n0 j1 L( ^. v4 b% |
  103.    /**hash 图片文件   6 `: t# [1 u8 W. B* j& R
  104.     * @param string $filePath 文件地址路径   # u( d7 z  T: G% z. U  F
  105.     * @return string 图片 hash 值,失败则是 false   / y: O0 @/ N6 u
  106.     * */    * w2 D; u/ w8 Z8 ], @/ v
  107.    public static function hashImageFile($filePath){   
    1 D: P$ j* J, `9 B6 ~) z. x
  108.        $src = self::createImage($filePath);    8 |4 S% {+ W2 Q9 j/ h0 @
  109.        $hashStr = self::hashImage($src);   
    - |- @  L. i# |* M, b
  110.        imagedestroy($src);   
    - [; R5 ]+ x& G; z3 N
  111.     ; ]) r) \0 g7 `9 R
  112.        return $hashStr;   
    & H! Y- {8 B9 z2 s7 G% l# c
  113.    }    $ L! F6 _: L. i: B$ N" @$ b! t
  114.     8 Z: Z1 P- i8 R9 n! }! u
  115.    
    - T! J- |. F  ]/ L
  116.    /**比较两个 hash 值,是不是相似   
    7 r5 d+ R: q% q7 `" {! p/ r1 q- \
  117.     * @param string $aHash A图片的 hash 值   
    + c# [7 E" t  P1 c: f5 W& x" H
  118.     * @param string $bHash B图片的 hash 值   
    : i+ T/ c6 `# ^) c9 j3 g
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    2 Y9 B( Z' ~# Z/ y$ [2 ?
  120.     * */    ) @" U5 p( e) P- P! M  F2 J
  121.    public static function isHashSimilar($aHash, $bHash){    0 q9 _/ g4 f* [/ S. ?" c
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    " O$ l: Z/ [. A8 h3 f/ W8 Y
  123.        if ($aL !== $bL){ return false; }   
    " Z1 I5 N. H  R
  124.     & ~- }/ V: W0 X
  125.        /*计算容许落差的数量*/    0 a" E2 y- \/ U% g, A1 Y
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    : c$ ^, G# I+ r1 d
  127.    
    ) n) y# h1 k3 z/ c
  128.        /*计算两个 hash 值的汉明距离*/    - F3 G6 i  i' q( G
  129.        $distance = 0;   
    5 `: h4 [* g/ q" F5 G+ ?4 c/ `
  130.        for($i=0; $i<$aL; $i++){   
    9 x3 S1 t. a! q  r9 W6 G
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    8 P% n2 ]7 H8 u
  132.        }   
      P: ]$ ~( |/ |/ L  D+ k
  133.    
    , E: i! U% j. k# t$ E/ ?
  134.        return ($distance<=$allowGap) ? true : false;    & x; i& f, ~9 M6 E
  135.    }   
    ( X6 g8 {& p5 [0 P
  136.     ( v. S2 d2 Z/ ?# X' {. V8 ?% I* T
  137.    
    / o1 t# @" z* f: ~/ T) m
  138.    /**比较两个图片文件,是不是相似   0 F6 ?( m- u6 ~: `' j% y. S' H0 E
  139.     * @param string $aHash A图片的路径   & P1 Y! c5 r! z+ H: @- {
  140.     * @param string $bHash B图片的路径   6 X/ _: k' q. w" h
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ! D+ n, ~! u/ C, M, z+ _  I) v
  142.     * */   
    & F. T8 `$ e- V* v, o5 N! {  q
  143.    public static function isImageFileSimilar($aPath, $bPath){    8 J; _# ]' c7 A$ V& X6 p2 Z, \4 b6 L
  144.        $aHash = ImageHash::hashImageFile($aPath);    5 p/ b5 J- o; G7 ?% f) x9 E% S
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ' a6 Q  e) s9 |
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    7 a9 n+ l1 }" {& {4 K
  147.    }   
    1 s, w4 S: y% s, r' t: M
  148.    
    & K. k8 w" D9 @9 \) r; l
  149. }
    , J1 A0 y/ J! }# F  ?/ b4 z5 E
复制代码

: w+ S+ D8 g% Y4 M# S, a, ~9 T
+ y3 z+ c, F( o. K) {$ _- O: r( H$ w




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