cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
3 s3 A  O8 Y4 \' m
, B3 h9 d* A0 |- A$ n
2 _0 `# a' }9 R, ^+ \3 v
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
. S" F. p; y* S  m; d& F
  1. <?php    ! U' M9 Q9 {* m+ {1 R
  2. /**     P: S% ?  z: P9 n
  3. * 图片相似度比较   
    ( ^- a1 |8 U# }8 v# W
  4. *   
    ( S+ V. U8 h' D( ^, Q
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  % Z4 d9 c5 V7 C$ I8 b
  6. * @author      jax.hu   8 _9 N0 d6 n4 ~4 w# l
  7. *   
    " L- z) p% g0 d! E: A4 J  M: @* L; c
  8. * <code>   " k; _6 B# U9 \: o% p
  9. *  //Sample_1   
    9 F9 [: t* o& O* J
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   & f4 G' V' B1 Q/ t
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   / [2 Z: @* ?2 T$ w7 x
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ( Y" i9 ?" ^1 U: ^* a
  13. *   
    " D( V( b2 w1 y, `
  14. *  //Sample_2   
    ( `3 C( j" q5 i; a
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    1 V/ p7 w- U; m$ e; X
  16. * </code>   4 T) t1 N, _4 }, e) w: n
  17. */    7 ^( l2 Y. a  q: H- s0 X
  18.     ! P  x& L: E3 n3 c" Z0 h+ }. U
  19. class ImageHash {    & o' ^! x# q0 g5 `) o+ a# e1 _
  20.     ! C% L8 s8 A) C1 B
  21.    /**取样倍率 1~10   
    , }$ H+ _  T% L9 ]
  22.     * @access public   
    # w; z$ F1 x4 v; j8 g* Q9 `
  23.     * @staticvar int   * ^1 V1 y* [  a
  24.     * */   
    " }5 u* J' S  Z6 P
  25.    public static $rate = 2;    & q$ d# @) i1 P1 {6 l7 ^9 n3 n
  26.    
    % q3 {9 t8 T( u
  27.    /**相似度允许值 0~64   
    ! b4 y& b( j; `( b8 J* w
  28.     * @access public   
    0 _$ f. C5 I/ a8 W- x1 U$ a0 }3 o
  29.     * @staticvar int   
    : I9 B4 H0 p1 P  S  ?8 X  K
  30.     * */    ! x. m& p! ^6 N: f4 ]+ L* f3 q
  31.    public static $similarity = 80;   
    8 v- A; Y- L4 I0 j
  32.    
    , Z( G- X; n. g5 {; x
  33.    /**图片类型对应的开启函数   & f( |' z" [/ |0 x0 w/ J/ N* b& n
  34.     * @access private   
    2 I7 A  k1 ]/ m0 n
  35.     * @staticvar string   
    # E" H. s/ @1 c0 g  F& C
  36.     * */   
      P- A' f! M3 x: u5 c, ?3 d
  37.    private static $_createFunc = array(    ' h8 U. K3 i- Q) z* F, C2 \
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    7 C) Q6 r, m9 |$ l: P% r
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    0 N) }" k4 k. d
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    3 S: m4 }( o+ _5 Y
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    * \( F- _& z* {; p! @! j
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    % E6 v/ G& ?1 p  @: m
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    ) h/ s3 v( f4 f  Y! ?8 f  ^
  44.    );    . J) B9 `9 a, n0 U- M
  45.     3 h$ }7 @" V/ m. f3 C
  46.     9 p- l; [) D# m* o
  47.    /**从文件建立图片   # o' [; k8 E% L$ `" @  x
  48.     * @param string $filePath 文件地址路径   ( x) h1 o' g3 p% ?/ q
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   , M! D+ K+ K% J* Y5 c; h" s
  50.     * */    # `! S8 F" P+ F8 [' o/ ]
  51.    public static function createImage($filePath){    0 @4 d! c) u7 ~1 q5 Z0 w/ p  n3 G) n
  52.        if(!file_exists($filePath)){ return false; }    2 O1 l  [3 \5 l: t: Q# o) D4 \
  53.     & ?- V8 S2 x+ S' R9 R4 S9 N
  54.        /*判断文件类型是否可以开启*/    * J! Z% X( M1 P, b5 e
  55.        $type = exif_imagetype($filePath);   
    7 O1 n5 k# A2 F9 _; s2 S, F0 ]
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    % K4 J" m2 a7 ^+ P! p0 u) h0 s
  57.    
    ( g0 s# _* u+ U6 J3 W
  58.        $func = self::$_createFunc[$type];   
    : h9 r; |- `( e. ~5 t
  59.        if(!function_exists($func)){ return false; }   
    ' v; X$ N8 G0 H% N& m
  60.    
    0 I5 x( Q8 D. h
  61.        return $func($filePath);   
    . _0 Z/ r6 `" r7 X  u4 u$ A
  62.    }    6 N$ z; ]2 @; D* N0 t0 C8 e
  63.     3 N( l; m9 m. _5 V$ O
  64.     " J4 x9 f3 T( y0 c7 k( m* Z
  65.    /**hash 图片   
    / V! `8 d% _  s- U/ P
  66.     * @param resource $src 图片 resource ID   
    - R7 q7 B/ S7 t
  67.     * @return string 图片 hash 值,失败则是 false   
    9 R# i) I4 G+ w  D+ B8 Q
  68.     * */   
    - a% F) S* q4 J# F1 G
  69.    public static function hashImage($src){    # f9 X! g+ Z  `9 C4 R" G$ B
  70.        if(!$src){ return false; }   
    ) b  r/ K5 B' Z: `. \1 T
  71.     : W9 r3 ~% h7 {  X2 ^- u" ~
  72.        /*缩小图片尺寸*/    2 B- {* P. h6 m  Y2 ?9 M0 c( U3 Z
  73.        $delta = 8 * self::$rate;    . k4 D6 i. Q# k8 O# G$ L$ z5 {
  74.        $img = imageCreateTrueColor($delta,$delta);    " h. d/ ]3 Q5 S' p
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    2 O* _# o3 l/ E6 ?& k- [
  76.    
    : E, b+ F9 n; w! b' {" B7 Y3 @
  77.        /*计算图片灰阶值*/    # e1 S4 i) H! c% A1 a6 r! O
  78.        $grayArray = array();   
    ' m# I. d8 s4 X; Z& k
  79.        for ($y=0; $y<$delta; $y++){    ! z, S/ z5 L2 y: k, P3 z
  80.            for ($x=0; $x<$delta; $x++){   
    6 a& C& p" X- T4 g2 R3 w% ~
  81.                $rgb = imagecolorat($img,$x,$y);    9 o3 B9 H; n0 a, t' X8 M
  82.                $col = imagecolorsforindex($img, $rgb);    : Y, q! V3 h. V2 P
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    7 ]8 P7 |' p, j( ]8 L
  84.     % V% G% ~5 p; n: q. U
  85.                $grayArray[] = $gray;   
    * P9 G  {/ F* Z$ d
  86.            }   
    4 H* y6 W% g- j9 U. x4 y
  87.        }    3 m* h6 @/ z  p( l+ \
  88.        imagedestroy($img);    7 |; m  s8 l8 j5 G( Y
  89.     : R4 ^3 m1 Q; ?
  90.        /*计算所有像素的灰阶平均值*/    % f, M( e; T9 D1 A7 s: B
  91.        $average = array_sum($grayArray)/count($grayArray);   
    - F2 k- K' ?8 {* {1 `* F; y
  92.     $ `: J3 O9 Y" J" W' ?9 v
  93.        /*计算 hash 值*/   
    % o2 f1 l4 Z2 w& P
  94.        $hashStr = '';   
    % ~+ m) W- n* H2 f/ @, k- }
  95.        foreach ($grayArray as $gray){    0 U& _! P4 a% E" z% P' L/ m2 |
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    0 K8 m0 \1 A: r3 c# i) n9 g" S" \
  97.        }   
    ! @" o# X9 i2 F2 E7 t, U
  98.     3 q4 S8 P$ {( G; n5 u
  99.        return $hashStr;   
    & l! E$ a5 n  U, n( U
  100.    }   
    : f% B2 t! a. Y2 r8 @
  101.    
    0 m& U# L- t8 ?; T
  102.     ) m' z  N- ~) z
  103.    /**hash 图片文件   4 K3 Q9 n9 I6 P6 q2 H
  104.     * @param string $filePath 文件地址路径   
    3 x3 e. j1 V! R" x9 b
  105.     * @return string 图片 hash 值,失败则是 false   9 i0 U( d. e" x
  106.     * */   
    9 C8 D+ N9 ]7 V# r
  107.    public static function hashImageFile($filePath){   
    ; J- y% R- \& P3 l& m
  108.        $src = self::createImage($filePath);   
    5 g4 z  P9 h( ~
  109.        $hashStr = self::hashImage($src);   
    # R8 D+ z7 j2 H0 J7 U$ e
  110.        imagedestroy($src);   
    % Y" y6 z6 D( W# b9 R
  111.     # \. }" n; h: w) A" c; b9 [! {# N4 I
  112.        return $hashStr;    3 t" k. ~, c. \. Z
  113.    }    0 t& o% Z1 |& e" z# q, a% A" q; Z
  114.    
    2 A" V& w) a  C5 W/ e9 R
  115.    
    ' h3 O* W! m/ s* \8 i9 R
  116.    /**比较两个 hash 值,是不是相似   
    . X  s6 z" t9 g+ L, W
  117.     * @param string $aHash A图片的 hash 值     X& ^3 ^# ~$ _6 i& _! N
  118.     * @param string $bHash B图片的 hash 值   
    1 H8 D8 y9 [" ?( G
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    $ }2 H4 c# }/ I' m9 y
  120.     * */   
    * P9 q. p( S) c3 P0 I) S
  121.    public static function isHashSimilar($aHash, $bHash){    4 Q2 i# ]9 J+ `! H. b0 i, ?
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    5 R( H) D3 L' M, z: A. _
  123.        if ($aL !== $bL){ return false; }   
    3 g9 J8 [" W2 J5 O
  124.     $ }! C/ T& K; |& }4 y1 S" ~2 l
  125.        /*计算容许落差的数量*/   
    7 O/ I3 V- |, o0 }
  126.        $allowGap = $aL*(100-self::$similarity)/100;    * q- q" Z* u5 K3 X4 I: W+ u1 t
  127.    
    # }. d3 z/ A1 b- i: l* }9 x& O
  128.        /*计算两个 hash 值的汉明距离*/    + Q, w* ~+ A" m( [7 O) H5 j
  129.        $distance = 0;   
    1 }  I; W; L3 J% h3 b% {4 I( \
  130.        for($i=0; $i<$aL; $i++){   
      H  I) W8 Q9 J0 o9 f0 t
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    3 E8 a& H- j* T4 B4 ]5 v1 q9 L: C
  132.        }    % x/ ~  T6 o5 n1 f7 X) ~2 d
  133.    
      t9 ~/ b+ A. v2 Y4 J
  134.        return ($distance<=$allowGap) ? true : false;    : s5 g: b' m1 m, e2 M' \2 q! d# S! T- P
  135.    }   
    + C) Q2 I; ^& U2 w0 T/ c
  136.     ( c) ~0 F9 W0 |' t: N7 B) H% N
  137.     % k& i- i5 B7 H
  138.    /**比较两个图片文件,是不是相似   
    * O* H3 A( R: ]  j
  139.     * @param string $aHash A图片的路径   
    # L& m# a9 k  U/ n" X
  140.     * @param string $bHash B图片的路径   
    ) P7 ^/ j7 O) f# O- }9 c" r1 O* }
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    # i( M* x0 l* R1 o+ B# M% w
  142.     * */      P4 R7 L) G0 M. t; C  {1 b
  143.    public static function isImageFileSimilar($aPath, $bPath){    1 E- T: c7 D3 k4 W7 A
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    - V9 g, A$ X& S- D  h1 c6 j, S
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    3 ?; V9 t: x& D3 o+ s( \
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    - ]6 k) R) U7 y0 u! g
  147.    }   
    6 E. V# e0 a- T' y+ ~5 a$ x
  148.     - q/ e& }) K. H9 H. {( z+ T# r
  149. }' B( J+ \; C6 V" {4 H+ e% c) ?( E
复制代码
% ^, O6 }2 y, {) \. w, {
% V8 O. p: e" a/ O5 E





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