cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图0 L. v  c: E0 U" q  {+ M
, W* o7 ^: B: e$ K- M. o
1 u' l! p) J  Y, I! w
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
+ m4 l7 a2 w2 q2 Y0 \
  1. <?php    ) ~. r! ~7 g$ }. ]  l' t
  2. /**   7 A3 B% z9 B( A
  3. * 图片相似度比较   - Q$ E6 C6 ?+ P. y
  4. *   4 a! T* L1 N2 Z  r
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  . a3 f# ]0 V) Q" m! y: K
  6. * @author      jax.hu   
    ; _: q0 w" ^0 g) b8 g. r
  7. *   
    8 l, D1 X- W+ ~' o% N' [5 x' ^/ h
  8. * <code>   ' P" Z, B; D: }
  9. *  //Sample_1   ! u4 I* L" v0 {$ T3 t
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   + h* J3 S* {9 H1 e
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    " g. k$ Y- y2 W) N, z4 k
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   6 o8 |; m* F" k* T% ^$ g& Q( [
  13. *   8 u  ~3 f2 E3 k4 s0 C3 E
  14. *  //Sample_2   6 O: I( i( I( E% a! C* n& O  U6 W
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    9 f$ |& C  j4 g. B" e! e! I, |
  16. * </code>   
    4 f3 O! \9 S' |, i  K
  17. */   
    " N. d0 E2 l% g5 Q' [
  18.     ) J7 x8 J0 m( o9 l0 N0 G% ]; K: v, L
  19. class ImageHash {    ' a5 X4 b7 G. ^! }3 p4 A
  20.    
    - `1 a+ `% @4 u
  21.    /**取样倍率 1~10   3 \4 Y# Q! d3 Y2 Y5 f$ d& V
  22.     * @access public   1 E; q6 t6 I$ H6 D! v7 x9 m6 y1 U
  23.     * @staticvar int   
    6 o1 ~7 u; E: P  d; |7 {
  24.     * */    1 I+ \' \+ d  r) }5 M( y) D* k' }
  25.    public static $rate = 2;   
    0 x- ^- u$ r7 t/ @
  26.     $ p7 Y0 y: A9 v) }  M! q8 }
  27.    /**相似度允许值 0~64   
    " P; ~5 L9 L; C& I! D6 G
  28.     * @access public   
    * c1 m! r# ?+ ?6 o4 B
  29.     * @staticvar int   : ]* a" u# H: s( [
  30.     * */   
    7 t, S! [2 J% ]) b, L
  31.    public static $similarity = 80;    ' u* y3 M" ?/ I3 X* f
  32.     7 o0 A" E1 o( C
  33.    /**图片类型对应的开启函数     `* ?! L! |. Q; q2 P( e
  34.     * @access private   2 X# u! Y2 o) U
  35.     * @staticvar string   
    3 S9 \, H# I  {
  36.     * */    ' b3 P$ F/ m/ ^) S: y( Q
  37.    private static $_createFunc = array(    & {' I# X1 n! a9 |6 p
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    7 ^+ j. g. t- u' P! Y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    % C$ x, ?2 d% o! ^# f
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    5 l) r( V1 a, ~5 l
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    4 k+ c  u( @: t, l( P4 q: F& k! ]
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    # C# z' D+ x7 p5 E: a# S# c
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    + C* Y. Z) q1 F/ r0 r0 i; i3 t/ Z6 A) N
  44.    );   
    : u; z1 i- e5 F: n4 C9 k
  45.       V3 o% n% |8 u& k! u
  46.    
    # `8 g4 K, E$ I6 g: k+ \3 S
  47.    /**从文件建立图片   - c2 A% E5 b/ N8 _+ ?4 Z
  48.     * @param string $filePath 文件地址路径   : {  K5 s: Y- q/ f5 [
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   1 L# W4 `" J/ j! M, K) e
  50.     * */    0 k' s4 [1 T" {3 L; i; T
  51.    public static function createImage($filePath){   
    2 @. U1 h7 b4 p( B
  52.        if(!file_exists($filePath)){ return false; }   
    1 P) k6 F' ]* h, |
  53.     : s0 m6 _& I; M) G, t4 i8 J9 d, @0 ?
  54.        /*判断文件类型是否可以开启*/   
    % X' [8 m! ]5 L4 L0 m7 s( j
  55.        $type = exif_imagetype($filePath);    5 y( S/ q+ F3 E8 h# g6 t
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    / E1 C, z6 j2 }1 u
  57.    
    . Y) K' s9 m3 U; A7 W
  58.        $func = self::$_createFunc[$type];   
    ' v& m8 C1 p  n# ?
  59.        if(!function_exists($func)){ return false; }    : ^; [0 ?% u: j* M5 A
  60.       |+ k: U" G) P5 d
  61.        return $func($filePath);   
    3 s1 q. O' c3 o
  62.    }   
    ' F* W" n9 `8 ?5 K9 f$ Y, R& D
  63.     - g' K& K4 Y: ]% t. n6 r
  64.     7 R$ @2 H# v8 u; q
  65.    /**hash 图片   
    ( C3 P% j- h: u6 m
  66.     * @param resource $src 图片 resource ID   
    ! M0 F' D; c; W  f2 d% _
  67.     * @return string 图片 hash 值,失败则是 false   , d" w4 Z; j" k% S4 w$ X2 d
  68.     * */    - u" U+ J- F1 Y& z
  69.    public static function hashImage($src){   
    + [. [% |8 `6 K3 i1 i( k
  70.        if(!$src){ return false; }    # k, j' b9 X# f2 D4 e! ]$ l
  71.    
    0 y! @3 ^5 H0 W1 q. W6 m/ _8 [
  72.        /*缩小图片尺寸*/   
    0 ]9 ^3 f+ ?5 [9 H" @4 G# D
  73.        $delta = 8 * self::$rate;    ' ]; o6 {5 _+ H4 R. z7 `
  74.        $img = imageCreateTrueColor($delta,$delta);    3 q; i& b: x, ?2 `+ G0 x
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ! i5 i6 G) B: }" k1 ^- s
  76.     6 r. w( Z( d: i( q, L
  77.        /*计算图片灰阶值*/    ; I" m8 @$ `  t* I; i8 F. m
  78.        $grayArray = array();   
    4 b$ k: W/ B( N( a
  79.        for ($y=0; $y<$delta; $y++){    ! k2 H, W/ F  d7 O
  80.            for ($x=0; $x<$delta; $x++){    7 I# b0 l. W# R) j: t
  81.                $rgb = imagecolorat($img,$x,$y);   
    , _4 ^( g6 {! g9 l) h
  82.                $col = imagecolorsforindex($img, $rgb);   
    . N* D. o2 ~' t2 X
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    0 F! Q3 p8 a+ _: c' Z
  84.     ' d- h/ |3 F5 p
  85.                $grayArray[] = $gray;   
    9 K8 x7 t* h6 g" ^1 j" T# v
  86.            }    * W9 g: i" @# U$ Q' O$ h
  87.        }   
      k7 W: W$ x, u
  88.        imagedestroy($img);    6 V$ Z2 R8 l$ o% }( [/ w: _
  89.     $ Y( M  a5 E3 S) K* ~6 {
  90.        /*计算所有像素的灰阶平均值*/   
    3 {2 K  P8 X7 [. f( J
  91.        $average = array_sum($grayArray)/count($grayArray);    , {% L$ c) }% y- g  e5 m. ?4 ^% x
  92.    
    9 A0 r7 h, v1 }' d9 {0 z& H
  93.        /*计算 hash 值*/    / ^( s2 m' T+ \- X
  94.        $hashStr = '';    / l9 ~7 r8 x* J: n
  95.        foreach ($grayArray as $gray){    . k8 _) L9 d2 w1 v" c& u% V- m
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    1 @$ L  C% |- t2 ~* v
  97.        }    6 E+ X( |/ l) @( t) u
  98.     % Q; o( Y- L: r7 g8 q8 |. K
  99.        return $hashStr;    / `9 W, x9 Z% J; M! c
  100.    }   
    6 F4 E6 c% f! ^9 P9 V+ o& q
  101.     3 y' s7 F2 I: e9 Q8 Z' P
  102.     + a; i0 I9 s7 w  C
  103.    /**hash 图片文件   
    " J9 o6 `, @" H: h
  104.     * @param string $filePath 文件地址路径   ) D2 n/ J6 u- u$ ]! X( Q
  105.     * @return string 图片 hash 值,失败则是 false     z. v! _% R7 K; [6 A, F, G$ q
  106.     * */   
    # E9 M  n4 q9 j. F! a5 _
  107.    public static function hashImageFile($filePath){   
    8 Z( Y1 {; S8 v  d
  108.        $src = self::createImage($filePath);   
    % p; ?4 P( _+ ?6 V1 i
  109.        $hashStr = self::hashImage($src);   
    9 m5 z0 k* i4 x6 q- Y7 C* }: [
  110.        imagedestroy($src);    / z6 k6 d; [* w4 ~9 U. a  ]" y
  111.    
    3 @3 i0 C2 I. y6 a6 H; S
  112.        return $hashStr;    6 V& l; M2 `# E$ V# l0 q. j: D
  113.    }   
    " n" Y( Y7 U) n, I* Y7 K7 q
  114.    
    ) L6 v: Y; {# E/ E: O( \
  115.    
    * n) b' ?  P8 X6 N' j
  116.    /**比较两个 hash 值,是不是相似   ) Y( [& D% V- r0 F! E( L
  117.     * @param string $aHash A图片的 hash 值   + G8 R8 q5 h* B; p3 R
  118.     * @param string $bHash B图片的 hash 值   
    5 ^  B5 m( g7 v+ ?) R& [( d
  119.     * @return bool 当图片相似则传递 true,否则是 false   , O$ A& U5 r8 j9 {! z/ s
  120.     * */   
    2 u) Q4 z5 b# w. O3 H2 b5 G" e$ e
  121.    public static function isHashSimilar($aHash, $bHash){   
    % \- O( `- b9 M, Z# D, e
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ' {0 z" x9 P. X0 }7 a) H
  123.        if ($aL !== $bL){ return false; }    % V. c3 r! ~/ ~- C. z
  124.     ; H( u; n7 s' e
  125.        /*计算容许落差的数量*/   
    8 }8 W* [" p* C* e
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    1 Z& Z; ]' q4 k
  127.     9 v1 U. W. u5 ?5 C. c' K0 r
  128.        /*计算两个 hash 值的汉明距离*/    ! S; y+ R9 ]" F5 \5 r
  129.        $distance = 0;   
    5 a( I6 e. h& f$ E
  130.        for($i=0; $i<$aL; $i++){   
    2 e9 T2 _: e2 f  l& k8 C* n
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    : @, g6 M" N: b) Z- R
  132.        }   
    & m! V4 n- w* p3 l9 Z
  133.    
    , X7 S6 \/ X0 x. l7 {5 S; s1 @! c
  134.        return ($distance<=$allowGap) ? true : false;   
    ( V( L& P$ j  N/ |  B
  135.    }    ) k" m7 X3 D! z  ^9 s6 z3 F
  136.    
    ! X( R! U& a, h) e4 ~' Y* V; K
  137.     # k  W' y4 b, o: q! Y0 \
  138.    /**比较两个图片文件,是不是相似   ; H' o( f* @0 M7 r6 x+ ^
  139.     * @param string $aHash A图片的路径   
    7 f) C, }( {/ O1 m
  140.     * @param string $bHash B图片的路径   
    0 |: Q( R8 v: K
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ; e8 ]2 N* X' v( a! }2 t
  142.     * */    # Y6 O' D2 B0 k+ M" R# q. U5 \
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ! o! `3 }" ~5 p& }8 {& R* |9 E! D
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    ' K  K& |. {6 u& A& O8 \, F
  145.        $bHash = ImageHash::hashImageFile($bPath);    ; _4 g& R0 Z$ t9 W: e! E2 F2 E
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    ( o% o( D6 \' X/ ^3 p6 P
  147.    }    + o6 H) z. M) L
  148.    
    7 w+ J0 m- \- H* a& S% J
  149. }: e: k  g$ _% \( U. t
复制代码
9 ~9 _' x+ V+ m- E! T! x+ K# S, k
% m5 k$ a& o* ]! {( r* d0 |





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