cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图, c7 ~, M, o3 [
( i0 V* p( a% z; v5 [+ `
& K5 C* M( g5 @3 k$ b8 V
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

6 f- M$ Q: |: a. Y  h- C. z
  1. <?php   
    ' i' q1 g& ]- w: Q6 M( O0 W3 d
  2. /**   
    4 a$ U  I7 y% X% V/ R
  3. * 图片相似度比较   " s: @" c* D( k0 S4 r: ~
  4. *   9 Z# x" g( W- @$ {% c: E4 F
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    5 d* L$ V0 r" D" n% N3 C) s% {+ ?- Q5 o! Q
  6. * @author      jax.hu   % u/ ]3 L9 q) m1 N. |! R# q
  7. *   
    5 A  k) z# X6 l. C" i* z4 K, Y
  8. * <code>   3 m- E+ X3 u9 M: V* X' @
  9. *  //Sample_1   % s2 n- S' u" M" ~
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   . P4 G% ]% R  o- Z/ A0 X
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
      a$ v$ g' N3 B! Z) D* o* Z# S
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    5 l& d* j" k# O3 k3 ?7 G8 F. S: K& D
  13. *   ; K7 Z# v( l: [+ o2 f# n2 `
  14. *  //Sample_2   
    5 t6 a0 S- ^+ H+ n
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    " g8 V. L3 u0 x9 r, C' [& O
  16. * </code>   ' r, ~+ t; A3 \  P. F
  17. */   
    & _. L$ C; l. @& h
  18.     ( R& V" u  e  K# V% ]# i% f4 s9 c
  19. class ImageHash {    * B0 O: o) O3 F5 W, E. T! N
  20.    
    4 H9 V; E4 e; g
  21.    /**取样倍率 1~10   
    " c: R6 J" R2 S; P% i( R. c
  22.     * @access public   1 l. e: y" U( k
  23.     * @staticvar int   
    7 X9 |9 E4 y! }) d8 H
  24.     * */   
    # ?& e- M! v, N8 C% ?
  25.    public static $rate = 2;   
    6 x: V6 u4 m' Q
  26.     ! ]9 q6 S" ~/ j; K; J
  27.    /**相似度允许值 0~64   
    3 ?( s. n+ k1 }3 r8 F) B
  28.     * @access public   * C; s! g- k/ s$ m% o
  29.     * @staticvar int   2 V4 o: B  Y( a
  30.     * */   
    ) f( M( O8 b$ k: U
  31.    public static $similarity = 80;    , H' R- S: K1 t/ m& Z
  32.    
    1 a& d' b2 G' }  t/ w* o( q0 D
  33.    /**图片类型对应的开启函数   
    5 G( Z8 A+ g5 k' w, S+ c
  34.     * @access private   
    $ {8 s2 d: c; C# V3 [, K6 ]
  35.     * @staticvar string   
    2 c; q- V/ V$ H+ }4 \
  36.     * */    3 [, j! n/ m+ r* H' R
  37.    private static $_createFunc = array(   
    ; H/ P  J; }, e
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    * K" F1 Y  X8 M4 y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ' t$ t% c$ X6 X5 ]) P3 y* s& r; r6 y. Z
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    9 T1 L% A8 l7 I# |; t8 F2 G/ @9 |
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    , w1 Q. U. Y% Q
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    9 g7 V7 A. U" E- w5 X4 }' Q2 w
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    3 N5 e& x* z6 P- _4 `9 a
  44.    );   
    , X% f- d' s5 I! |# ]# K/ ~
  45.    
    ) d2 m, ]. G! C( \& _9 e
  46.     , P8 _6 t4 B( }: g  m( N
  47.    /**从文件建立图片   ! e" Y: {7 g. N* N& J0 r
  48.     * @param string $filePath 文件地址路径   1 `$ N' H, W' B2 D0 H7 A
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ' j" {2 h+ Z0 `3 }2 x- ]( [
  50.     * */   
    ! h  h  p# F$ e! H$ G
  51.    public static function createImage($filePath){    6 f* ?$ e! T( t" {& k
  52.        if(!file_exists($filePath)){ return false; }    / q+ z( `" \* Q( r; ~1 L# v0 y6 j& T
  53.     1 a# Z( ^* q) ?
  54.        /*判断文件类型是否可以开启*/    + J; G- C' _; T9 r! s. F! {6 J. u
  55.        $type = exif_imagetype($filePath);   
    % q8 q4 X% {# f/ k9 `* q+ V
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    9 k6 ?5 ^6 @% n3 C: c$ e) B
  57.     " h! X+ v* {7 h% C: W
  58.        $func = self::$_createFunc[$type];    ' p0 l! ?5 y7 e9 b! g7 C$ {
  59.        if(!function_exists($func)){ return false; }   
    & \- K" ^9 |. \: v8 o4 \
  60.    
    $ d# K2 R9 _1 M8 p+ u0 R8 g, k, a
  61.        return $func($filePath);   
    9 f' w  q4 }$ ?5 b7 a, d9 H
  62.    }    8 q; c/ V8 g! h) G4 I& y8 k1 G
  63.     8 T' f1 q# b# v& M
  64.    
    7 K, G- g" N  t, h! r$ O0 O3 O% y
  65.    /**hash 图片   
    , Q$ F: H, j7 P
  66.     * @param resource $src 图片 resource ID   
    % e7 O5 s6 c2 @! ?+ G4 h& j0 h( h4 Z
  67.     * @return string 图片 hash 值,失败则是 false   7 N1 B( u3 l/ l
  68.     * */   
    3 c5 S8 @( ]' w. T6 p/ R
  69.    public static function hashImage($src){    " H9 |- ~$ M& J. }) \$ T) f
  70.        if(!$src){ return false; }   
    " _) q0 \* i7 v9 J# }# @  ]
  71.    
    4 f( {8 A! h8 _1 f( _7 E. i* }
  72.        /*缩小图片尺寸*/   
    4 W3 u1 o6 M0 \) [# o
  73.        $delta = 8 * self::$rate;    " A3 R/ q2 [! u- ], {& X$ b* u
  74.        $img = imageCreateTrueColor($delta,$delta);   
    , n6 f5 v! C. g  p+ j9 C
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    2 b0 V+ e* E  l! v
  76.    
    - k9 n& w) w1 I3 |
  77.        /*计算图片灰阶值*/    - n' a6 Y- K1 _1 n6 `
  78.        $grayArray = array();   
    & {9 Y) W8 m9 `/ R
  79.        for ($y=0; $y<$delta; $y++){    3 A3 n5 E$ q& |1 E$ T: `
  80.            for ($x=0; $x<$delta; $x++){   
    : J' ^- C* U2 m! G+ o. ^' O
  81.                $rgb = imagecolorat($img,$x,$y);    * T* x- c' h" ~; i3 C! F
  82.                $col = imagecolorsforindex($img, $rgb);      I2 k5 {6 v2 O  ]) w
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    2 Z. s# ^" E0 y# R! i7 z
  84.    
    6 |. h4 H" m# H# N
  85.                $grayArray[] = $gray;    8 O& A6 }1 Q; s& g9 K# @
  86.            }    % Z; l& s1 u8 s- k# @
  87.        }   
    1 x; ~5 M9 C4 ^. q7 {+ s, H
  88.        imagedestroy($img);    ( K, [; b9 E/ ~. g% W( ~
  89.     / u( S$ Y4 c0 X* C8 x" ^
  90.        /*计算所有像素的灰阶平均值*/    8 h! p# T# o$ y# f8 {
  91.        $average = array_sum($grayArray)/count($grayArray);    ) {, V& A6 s3 @8 y  `
  92.     % |- T- x. l& A0 M: O; y, q* S
  93.        /*计算 hash 值*/    ; O# k6 d8 m: J
  94.        $hashStr = '';   
    - h4 A- w; m( `: Z9 F- z
  95.        foreach ($grayArray as $gray){   
    5 v7 r/ }9 e1 N3 j4 N/ A
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    7 o/ A, B$ r# s$ ~8 ^
  97.        }   
    7 ?/ {1 h9 j2 E! _
  98.    
    1 l  O* {0 q/ l1 l$ ^
  99.        return $hashStr;   
    8 b% o6 y- n( a8 t1 R: W3 Z
  100.    }   
    : }+ x+ t+ l9 k2 Z
  101.     2 d! T4 F  N- X+ }0 O, M
  102.     7 e# G. H: T. g$ K
  103.    /**hash 图片文件   2 Z) u$ b1 R5 E
  104.     * @param string $filePath 文件地址路径   
    - w& w2 }6 |3 ?9 K7 R
  105.     * @return string 图片 hash 值,失败则是 false   ( q# P1 k( }3 ~% Q" N9 U/ m9 X
  106.     * */   
    " ]8 N& G" ~% U! `. |! W
  107.    public static function hashImageFile($filePath){   
    . p9 S( W7 s/ R/ @! y9 [
  108.        $src = self::createImage($filePath);    / R: }- T% G- ?
  109.        $hashStr = self::hashImage($src);   
    7 z5 G+ z) X4 ^; O6 u6 A% @
  110.        imagedestroy($src);    5 ~" r! y0 h+ E/ c% d' y
  111.    
    6 s$ w; o0 ^) ]
  112.        return $hashStr;   
    2 p2 i; _/ ^1 c0 e. M
  113.    }    - s+ X, q* f# l
  114.    
    4 o  g: S3 ?/ q
  115.    
    + i3 B4 T0 N- g3 s; h
  116.    /**比较两个 hash 值,是不是相似   
    5 z) T' j; [+ {; w0 M# m# ^
  117.     * @param string $aHash A图片的 hash 值   $ ?1 n1 }4 K6 `( B' Q, X  X! ^- _
  118.     * @param string $bHash B图片的 hash 值   . _$ c- k9 |1 J$ V% `
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ( s: t. C# [  l: x& @
  120.     * */   
    9 u) L6 l- F& |/ g" d
  121.    public static function isHashSimilar($aHash, $bHash){   
    * a5 ~* T+ Q/ Y6 M: }- Z9 ?
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    8 r/ J/ r: w- M: O0 v' F# g/ U8 D
  123.        if ($aL !== $bL){ return false; }   
    9 ?' w! T7 y( z, K' v2 ]: }
  124.    
    6 D$ N' U. K$ l$ S& |
  125.        /*计算容许落差的数量*/   
      h# c$ I, F: J; |
  126.        $allowGap = $aL*(100-self::$similarity)/100;    , F; g0 \8 d3 m( C# E
  127.    
    9 G' a* q& t2 X5 [& _; q: n* ~+ x/ X
  128.        /*计算两个 hash 值的汉明距离*/    - o% M. x, \+ R, H
  129.        $distance = 0;    : J* [6 s! E6 z: s) a
  130.        for($i=0; $i<$aL; $i++){    ! y+ I: Y3 k, f# o
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    0 Q: Q1 Z" M* x! O+ c. ^2 f
  132.        }    6 N5 {$ o( F9 y) }
  133.    
    & i: \4 }5 t; T# @7 T
  134.        return ($distance<=$allowGap) ? true : false;    6 q+ J3 |( v& Y) ~
  135.    }   
    ) I2 ]* d- W( @$ Q- ^2 F0 {* L3 m
  136.    
    - ?7 Q9 M) b' e+ h7 J! J
  137.    
    . `2 O& B2 `- ?1 D2 Y: i5 Q7 q
  138.    /**比较两个图片文件,是不是相似   
    4 ?( S, R# l, C# E7 x5 f
  139.     * @param string $aHash A图片的路径   
    : w* ~$ |. [- `  B" ]' a) x" m8 c. W
  140.     * @param string $bHash B图片的路径   
    - S8 \" ~+ _9 y3 d% O# |8 t/ i
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    5 j" M* z' ~) b. W
  142.     * */   
    4 Y. n+ c4 w7 n* h4 \
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ; H9 f/ j- ^1 _+ R
  144.        $aHash = ImageHash::hashImageFile($aPath);    * C) u& R/ u. L' u. `% d
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    & ~) Z, P3 v: T! j
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    - F  V7 V4 p7 f7 ]8 B
  147.    }   
    3 q+ p+ g+ p1 s9 a* p" t
  148.     * s. E0 a* T" Q, ^
  149. }
    : B7 }& n0 D  Y) x  A3 e
复制代码

1 Z+ Y6 o& V+ w, D4 D! B
8 F+ }3 o8 E+ y; U




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