cncml手绘网

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

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

( j; }# k* f  z: n- f
% f5 i; A& R# e; p. }1 L, C8 y
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

4 w% a! y: ]" I; a, Y% y, {
  1. <?php      J9 R" J+ r$ m* D9 j/ J9 p6 P
  2. /**   8 x7 ?. \: h0 A# e, I
  3. * 图片相似度比较   
    - N3 @4 o% j0 S$ J0 Q
  4. *   $ m6 W8 @% N6 p
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    0 P) J9 S% n, u( z, Y/ o
  6. * @author      jax.hu   7 i( k+ n9 t) r; M
  7. *   + p& ~3 m& d' ~, y2 P, n+ Z3 v
  8. * <code>   3 E. H: u9 a0 ~( B3 j  B! V* c8 h
  9. *  //Sample_1   * y. |: ^& Y! B- K
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
      M" D7 M; ]/ S7 E
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ! W. ~1 R# L$ B/ w
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    , v7 D; f: N% t
  13. *   
    2 E0 t( ~; ?6 U6 u
  14. *  //Sample_2   ' g5 O( l/ s3 C: H# C" C
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    9 C4 I% r+ M, f; ]/ w( }6 e
  16. * </code>   1 i. h8 G9 k. p1 w: Y, w5 s* S
  17. */      f( r1 E9 Z8 a: c
  18.    
    ! T2 e! K! e" [' E( m- {4 c' c
  19. class ImageHash {   
    5 _4 [- S5 [+ L+ q. A
  20.    
    2 O3 }1 s) C% K( H$ \7 @
  21.    /**取样倍率 1~10   
      |1 t* P0 j* p
  22.     * @access public   ' e* V( D! x; d8 l' A
  23.     * @staticvar int   + M" d& D' ?' E8 }
  24.     * */    + m$ Z( }' q/ l7 C0 ~: z, k: n) D0 y
  25.    public static $rate = 2;   
    ! ~4 U; ^4 h- n# s) E* a
  26.    
    / [6 K6 F9 M* T. `5 h" j: M1 g
  27.    /**相似度允许值 0~64   . b+ v( y& f$ \& _; N  H9 ^1 ?
  28.     * @access public   
    # i- Y& B. G2 c# h9 [" I' u2 k
  29.     * @staticvar int   ) S& n5 y0 \5 k+ F
  30.     * */    ; O/ o  y: I" k3 r, H" Q% B
  31.    public static $similarity = 80;   
    9 I' p: t( [5 K
  32.     + Z. S' X! a' @2 [
  33.    /**图片类型对应的开启函数   
    ) c8 R4 y; x3 u+ [4 @
  34.     * @access private   
    # T6 l$ E) D6 [7 X( T/ a4 I% \
  35.     * @staticvar string   
    & j0 V* |) s7 Y
  36.     * */   
      a  C$ B( q  _# V
  37.    private static $_createFunc = array(   
    7 w/ E% H( l( @/ O5 k* c, U
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    8 k7 W8 W% j, b3 T
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    : \0 l, |1 e2 M( }$ u  b
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    ) u3 ~+ Q* m" _0 C5 J, `
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    , _8 f! w& x. u
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    - m. Y9 S9 B: n; O: K, ]( Q
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ( E- N9 d0 D, r+ O. z* B/ P
  44.    );   
    ' b: u- V4 I1 U" t
  45.    
    $ }$ C1 L) T, \% D( g" x
  46.     " f, b, ?, v  n$ ?2 s/ h
  47.    /**从文件建立图片   - ~0 ]  v. {4 Y7 @5 }% y
  48.     * @param string $filePath 文件地址路径   7 l9 Q7 W) A7 b: }2 j' {5 E, r  K
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   # h( k. y1 F. E3 _
  50.     * */    8 f' J- Q* c3 c
  51.    public static function createImage($filePath){    ( F: E- @9 J' k3 x2 }/ B8 j
  52.        if(!file_exists($filePath)){ return false; }    ; y7 s8 d* ^" J% N
  53.     8 X$ ~0 P  a: j
  54.        /*判断文件类型是否可以开启*/   
    + N9 ]2 m! g& A, Q, a
  55.        $type = exif_imagetype($filePath);    8 u, n- A' x: H" m* [
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    : N5 A! V+ c. L# Z% Q0 C
  57.     2 g) s& R6 B' P) s3 V! N7 E
  58.        $func = self::$_createFunc[$type];   
    ' p  j" Z& m4 N( V3 k/ t/ @) `% F4 H
  59.        if(!function_exists($func)){ return false; }    8 _* V. g# H8 ^( q0 E
  60.    
    6 _& n$ i9 Y+ f8 T
  61.        return $func($filePath);   
    % Z! N1 B( {* `0 G8 ]* P% W
  62.    }    ' N# y5 \# w  J7 z2 V
  63.     1 H2 `0 H: O, R5 |3 D% i0 H: y$ y
  64.    
    ; ^+ Z, }1 q7 i/ w: h9 H! J+ g
  65.    /**hash 图片   
    ( f2 u0 m1 N2 l  ^& Q4 k; |& }
  66.     * @param resource $src 图片 resource ID   
    ! e* D/ P; w' {) {
  67.     * @return string 图片 hash 值,失败则是 false   + k1 [" u! q5 a) M3 r/ H
  68.     * */   
    , ?& F6 h' R3 }' k  J
  69.    public static function hashImage($src){      q0 \0 N' O1 B# n+ w- N
  70.        if(!$src){ return false; }   
    $ S/ \: N" l% B
  71.    
    - f& e  m7 y$ U# J6 N
  72.        /*缩小图片尺寸*/    , f. u7 }( V. Q
  73.        $delta = 8 * self::$rate;    8 b1 y! X, Q" p0 {" A( D! D
  74.        $img = imageCreateTrueColor($delta,$delta);   
    $ e6 ]& |* `1 q) t" W* ]8 f
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ) M9 F$ Q$ }/ H
  76.    
    0 x, _) Q9 I5 G4 M' W$ |3 @5 M
  77.        /*计算图片灰阶值*/   
    0 I" B  d  ^$ q3 |+ l
  78.        $grayArray = array();   
    6 {" P% V( E" T
  79.        for ($y=0; $y<$delta; $y++){    ! {% }% R  d3 C. f+ Y& y( M) ]
  80.            for ($x=0; $x<$delta; $x++){   
    - F$ C+ C$ K* J9 k3 A) ]  u4 \4 L; F
  81.                $rgb = imagecolorat($img,$x,$y);   
    8 o8 z3 Q; l' v) n! U0 N
  82.                $col = imagecolorsforindex($img, $rgb);   
    # O6 ~$ L3 }* T& i( I# n1 U
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ! O$ t# N  K: _) V: E' q+ `
  84.    
    * a" I7 g4 o2 K7 s% X/ I
  85.                $grayArray[] = $gray;   
    ; G- i4 M5 @: n9 O9 x; g8 i
  86.            }    5 @% m# |, g! w6 h8 t
  87.        }   
    , @% M# p2 a4 S
  88.        imagedestroy($img);   
    % w7 ^  g. r/ |  J
  89.    
    ; Y4 S; [9 ^5 V; |$ v0 ~
  90.        /*计算所有像素的灰阶平均值*/    ; Y# B! @) C  e! S* ]6 H
  91.        $average = array_sum($grayArray)/count($grayArray);   
    8 W) U7 z+ x; r1 z* w; w
  92.     ) T" _7 {, h. m, C9 p& F; d
  93.        /*计算 hash 值*/    + F5 K  \0 e3 C# F+ P, O
  94.        $hashStr = '';    ' }- D& s0 ^' t# W
  95.        foreach ($grayArray as $gray){   
    3 Z' U& ~3 d  y0 h- c; C( W
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    + q& Q' R6 I4 V6 n" j+ D& `5 V
  97.        }    % h' p8 D! o4 r" q; m
  98.     ! z" k7 v% _3 H' e' w8 u0 H9 A( \
  99.        return $hashStr;    : O( N& s8 z- [
  100.    }   
    % r8 Y% U( I& e4 r2 _
  101.    
    9 q5 B1 r. L' p8 G- |
  102.    
    7 V$ J6 Z# r  z8 f$ Z3 Q2 D8 L/ C
  103.    /**hash 图片文件   
    2 g$ M' d: _; z; m" w
  104.     * @param string $filePath 文件地址路径   
    3 L9 u' N" s& i
  105.     * @return string 图片 hash 值,失败则是 false   
    # y) e1 e7 L2 O: E6 p: ]; r( F
  106.     * */    : N3 B0 R2 i1 x6 U
  107.    public static function hashImageFile($filePath){   
    # W2 ?8 J$ s( I- A
  108.        $src = self::createImage($filePath);   
    ! r1 G- W8 U1 T8 V1 s: m" ^
  109.        $hashStr = self::hashImage($src);   
    ' E9 {- A" ^1 ^  D: p
  110.        imagedestroy($src);   
    5 c3 q" A$ X) k* S) G( Y
  111.    
    * t, N8 D) ^. m( A3 s3 g
  112.        return $hashStr;   
    4 _6 l. R0 r% l6 `5 r
  113.    }   
    8 b/ z" A3 ^. ]# L
  114.     # @3 j) Z7 z( y" y' r" D
  115.     4 j5 [6 z$ c" L- ?" A
  116.    /**比较两个 hash 值,是不是相似   . S$ z- ^8 O" H# J3 Q
  117.     * @param string $aHash A图片的 hash 值   
    ( F4 G% V* g+ v4 I
  118.     * @param string $bHash B图片的 hash 值   % Z# J! v# P6 S; G0 N6 _* [3 z
  119.     * @return bool 当图片相似则传递 true,否则是 false   2 Z( l, Y# M$ U% R% w( n( T
  120.     * */   
    " |: n1 g  A" g' X3 S: ]! c( w
  121.    public static function isHashSimilar($aHash, $bHash){   
    ; p/ e- q& l' o. |7 E! M
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    . q: Q3 p7 W1 W4 @: o* g
  123.        if ($aL !== $bL){ return false; }   
    ' x" p+ J( a. P
  124.     ! o$ ^9 j! G" X7 D/ r: T' y
  125.        /*计算容许落差的数量*/    % V; C* y# p- q; m# d# Z6 z
  126.        $allowGap = $aL*(100-self::$similarity)/100;    8 Q6 R' ?# M( y
  127.    
      }5 V) A( q4 k& b
  128.        /*计算两个 hash 值的汉明距离*/    $ d& _" C" D6 K% F' C
  129.        $distance = 0;    # m6 F3 U( l; l3 S0 S
  130.        for($i=0; $i<$aL; $i++){   
    , @5 N' H! j  X; g  h' l
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    9 B% [9 g0 N1 Z2 X) ]
  132.        }   
    , e% _% ~$ v! x1 x& J* z2 j
  133.    
    ; @+ q6 n* H0 \/ y
  134.        return ($distance<=$allowGap) ? true : false;   
    6 o3 e3 b- i: s9 [
  135.    }   
    ) y! E4 e& b% f0 a  s
  136.     5 D" ^& l5 _2 u' A, r2 {: o
  137.    
    # i1 R5 s  f- N' g1 b+ G
  138.    /**比较两个图片文件,是不是相似   
    + i8 J4 D/ K& t
  139.     * @param string $aHash A图片的路径   
    ) }8 W% b! t! P6 H
  140.     * @param string $bHash B图片的路径   - Q' `  l1 v  z6 c
  141.     * @return bool 当图片相似则传递 true,否则是 false   
      r  \. X+ R& m% W2 I. t6 }
  142.     * */    7 n6 H3 `7 E6 S6 G2 P* K
  143.    public static function isImageFileSimilar($aPath, $bPath){    % @1 t- I$ a! Z: T+ m* |
  144.        $aHash = ImageHash::hashImageFile($aPath);    & a8 S5 r2 B2 B5 W4 k% n
  145.        $bHash = ImageHash::hashImageFile($bPath);    - c0 a, x& o+ e( i2 g/ v( f
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    $ S% k9 T+ A0 M
  147.    }   
    ( z& @: u% J) s  N
  148.     4 Z3 n* T' Y, F2 V
  149. }
    6 Q4 _/ l2 c4 i2 N
复制代码

/ D3 _9 G- N! W( r. M; f" V1 {
/ r0 x, A) a* n0 u! L* R




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