您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11298|回复: 0
打印 上一主题 下一主题

[php学习资料] 分享一个PHP简易的图片相似度比较类

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图, D" O2 j  B( t; }$ V3 A3 t
  [3 ?0 j# i, p
: n5 i0 E/ w6 F. q% M; f# q) v6 J! p
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
4 p) v5 o" K+ g% `" v0 h8 f' x
  1. <?php    1 U: O8 S! B  L# K# K6 G0 H
  2. /**   
    # R/ P4 y7 t' s7 R  h
  3. * 图片相似度比较   % Z! g# Q2 P! b* P
  4. *   ' n* L! V1 X' H& {
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    3 _" U1 O5 o! _) s" c8 ~. r+ }' ^
  6. * @author      jax.hu   
    9 P# X5 z3 S0 [$ V$ |% \
  7. *   9 a) V& ?0 j& w6 b5 Q' C4 }7 u# c
  8. * <code>   2 o: Z0 y! N" D
  9. *  //Sample_1   # P1 x7 C. h3 `" Q, j
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   9 W. T: a1 H5 P' X1 s0 V
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   % j* r5 N, k$ F) i. V* [# S
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   % D- r* U/ ^4 J6 R
  13. *   . n! k; [% v5 y$ C; R- h+ M! t
  14. *  //Sample_2   ( k2 L/ u2 Z; M' L' a
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   2 V+ V! t! V2 s$ w6 W: E6 E
  16. * </code>   * T0 E' s/ s1 X4 u  {# S6 |, h. g9 j
  17. */    ! Q1 x$ \0 v/ ?+ T+ g% ~3 P
  18.    
    ; A) f; h/ Q5 Q% r- Z! j* A
  19. class ImageHash {   
    + O! T6 @0 }1 Q% q
  20.     1 R6 K: p- y+ v/ T# P# x" t
  21.    /**取样倍率 1~10   
    * Q) E3 i& l8 f7 |3 o2 `% ?4 e
  22.     * @access public   
    ! J8 I- I! y2 i  b' I; h5 U2 V% w
  23.     * @staticvar int   6 ]7 I) P+ I# D' V# B2 G! i
  24.     * */    1 h- r% T. l& o6 v( J5 V4 D
  25.    public static $rate = 2;   
    % l5 d- ?/ M  L
  26.     ; Z# {& O/ c( e% W* c
  27.    /**相似度允许值 0~64   
    ) [2 }, g$ k3 M/ t
  28.     * @access public   
    * R- z* J/ Z- l% r
  29.     * @staticvar int   2 \1 W; s$ B* j6 y
  30.     * */    8 i8 Z0 N% x! ^, h
  31.    public static $similarity = 80;   
    / g3 h8 U% j! D" T1 X9 R7 Y
  32.     & `1 I; ~. a. e+ O# b* K- P, N
  33.    /**图片类型对应的开启函数   ) ]7 \6 t. T1 Y& m, Z( c
  34.     * @access private   ' |4 E) m4 S0 L5 ^5 k/ n) X
  35.     * @staticvar string   
    4 i) r7 V5 R8 r7 L2 Y4 E! ]( s
  36.     * */   
    0 l  ~0 P+ D0 W% {  i2 c
  37.    private static $_createFunc = array(   
    0 }, ^$ }0 J! j0 z; T
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    3 k$ M' h5 d! H1 ?& O2 l% C2 G
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    / Z( T# k* R9 O
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
      _4 @; s, r. u& O
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    # A0 `+ u- k1 b2 x
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    0 a! _3 e3 K4 {9 R# e% C5 \
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    3 Y' M& b) C9 S" y
  44.    );    : j2 G: ]% r8 z4 [: H
  45.    
    # `; V" P- l1 i0 D5 N) U' |
  46.    
    $ v0 V$ V( L  O& Q% n5 X+ E# v
  47.    /**从文件建立图片   ' ?" ^! {* c, r0 t+ {4 F
  48.     * @param string $filePath 文件地址路径   / _, |! n( ~4 {; _, y
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    $ ^7 ]; I1 n4 K4 N* v4 c
  50.     * */   
    , n. s, Z. _0 U; q9 \8 K: G
  51.    public static function createImage($filePath){   
    # O& m* J* h# ^4 n" E
  52.        if(!file_exists($filePath)){ return false; }    / R! a3 l+ y6 a: C& \
  53.     . k7 x4 k. Q1 k( W
  54.        /*判断文件类型是否可以开启*/    & ?# j! F0 _0 Y! s
  55.        $type = exif_imagetype($filePath);    / z/ j$ y4 Y! \% A; r
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    + Z; F+ ?4 N, h/ P- k
  57.    
    : R8 [- A& B$ c1 ~
  58.        $func = self::$_createFunc[$type];   
    - D, g7 n% k* g" \3 `/ Q. o0 E3 K) b6 Z
  59.        if(!function_exists($func)){ return false; }   
    5 E$ [4 j1 o; {5 L# g$ \4 p
  60.    
    9 _) @" O8 C+ p  `! ~9 K# Y! E
  61.        return $func($filePath);      |2 V  c/ Z* U! U! X+ ~; p
  62.    }    ! O6 \4 }' n/ j# U
  63.    
    : s7 U) {4 i% o& x  u
  64.     0 i; z9 k3 @% m
  65.    /**hash 图片   
    : L5 |3 o% q8 H( y+ X$ P5 E0 l
  66.     * @param resource $src 图片 resource ID   . U$ Y3 ~# \/ J$ B$ M) q# h
  67.     * @return string 图片 hash 值,失败则是 false   
    * V  h9 G9 S: }+ [5 O! E: A6 r
  68.     * */    8 `: H6 o2 e; ~* h( O1 o
  69.    public static function hashImage($src){   
    1 y7 X5 _- l& J$ l
  70.        if(!$src){ return false; }   
    * p+ ^0 J. U5 e; S! y& m- W/ e0 w
  71.     : |  d6 j- D/ {* M/ G, w
  72.        /*缩小图片尺寸*/    : P  u8 e/ W8 u& A8 p
  73.        $delta = 8 * self::$rate;    * \9 {1 d4 x. m  L, U" T. \
  74.        $img = imageCreateTrueColor($delta,$delta);   
    # e7 _  F, J( J7 \7 N/ N
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ! M9 w( d: `% W
  76.    
    , J; N8 D+ A+ Z; i6 O9 s9 B7 f& h
  77.        /*计算图片灰阶值*/   
    0 z$ [6 P, Q6 _# `2 _$ ?; J4 x3 t" J
  78.        $grayArray = array();    3 ?* F( D* Q8 d; f. }, @
  79.        for ($y=0; $y<$delta; $y++){    , y6 K) ?6 ~0 b1 b! C
  80.            for ($x=0; $x<$delta; $x++){   
    ; p/ V% y/ ^$ U# v
  81.                $rgb = imagecolorat($img,$x,$y);    4 m* c. {) y- a& B2 B( P: e& G& L8 F
  82.                $col = imagecolorsforindex($img, $rgb);    " }/ H' {, X/ E( p4 z
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;      W3 d) q  _9 Y; {
  84.    
      a5 B$ N1 _" n7 Q8 s4 M
  85.                $grayArray[] = $gray;    9 \: E9 U" ^5 n3 S+ p1 u
  86.            }    $ a* x; z1 k8 p' E
  87.        }      C4 `( H  G) `* u7 r! r
  88.        imagedestroy($img);    , A) J5 |8 E0 k  g
  89.     : k+ ?7 D; V0 j1 k/ F' S
  90.        /*计算所有像素的灰阶平均值*/    * D# I/ ~- `( g' B0 E+ z7 P, Z+ {  z
  91.        $average = array_sum($grayArray)/count($grayArray);    9 J) _5 G* c0 E- i/ o9 I
  92.     0 v9 m3 I& a; o
  93.        /*计算 hash 值*/   
    1 Z' K1 n# Y# Z- s" P
  94.        $hashStr = '';    6 K6 h  D( h$ S- A
  95.        foreach ($grayArray as $gray){    7 R; @7 A3 j, `/ @
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    $ Z* X5 a' r3 _+ G& n) k6 w
  97.        }    . s* T& Y7 m3 L) a
  98.    
      f7 z/ i- ^- m+ L; o+ O
  99.        return $hashStr;   
    5 @8 O8 p1 p% A; S& w
  100.    }    ) j. K! Q* Y1 W. O5 D; o
  101.    
    . ?4 D0 S, y: `, F) e% W2 U
  102.     $ v; x# P' D) ?9 {& b+ M
  103.    /**hash 图片文件     D& h, T' L& \% A2 u: a, _9 V$ i
  104.     * @param string $filePath 文件地址路径   4 x' `) S+ H2 I* N# K& B  Q
  105.     * @return string 图片 hash 值,失败则是 false   
    / z, \2 w, {) H+ U" J4 e/ C
  106.     * */   
    ) d  S3 A' p; c1 z+ ~- G
  107.    public static function hashImageFile($filePath){   
    0 c/ t8 M2 ?* V6 k
  108.        $src = self::createImage($filePath);   
    3 ]' ^/ ]8 x. b, f
  109.        $hashStr = self::hashImage($src);    " }: t8 {. c! U, Z" A/ q
  110.        imagedestroy($src);    4 q9 E4 O) [* A
  111.    
    ! L7 V8 |& t# l& T8 M
  112.        return $hashStr;   
    % \! c8 G2 ^/ ~( I
  113.    }    3 K/ k0 S* ]; e* m- {
  114.     : C, Z) z# V- M) Z
  115.    
    ( t7 m( M/ m0 z4 a
  116.    /**比较两个 hash 值,是不是相似   3 l3 B! F! x9 y: {' ^
  117.     * @param string $aHash A图片的 hash 值   
    + {* J2 F; ^8 Y( x: N
  118.     * @param string $bHash B图片的 hash 值   / m& Y# V, V" J
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    . r7 n" J6 }( q
  120.     * */   
    ; s% \$ x0 |& o( v: f
  121.    public static function isHashSimilar($aHash, $bHash){   
    " O8 [2 G* V/ W: q& R0 `9 u- q
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    : c. R7 q: n3 S' B5 }
  123.        if ($aL !== $bL){ return false; }   
    " X8 C2 \6 X5 ?, o! m3 \7 w* X% m
  124.    
    + _5 ]$ i6 ^1 q+ b
  125.        /*计算容许落差的数量*/   
    3 K/ C) ~8 W! _
  126.        $allowGap = $aL*(100-self::$similarity)/100;    0 l+ |+ n8 _0 z2 b) n5 G
  127.    
    3 j% P3 W" O7 _- U) i9 f
  128.        /*计算两个 hash 值的汉明距离*/   
    + @" u: b8 ]4 g- F5 s$ O
  129.        $distance = 0;   
    ) I3 I+ t7 _) u3 k5 R3 A' g
  130.        for($i=0; $i<$aL; $i++){    & j8 _  C2 N3 O& S4 [/ B6 }* A" X' Q
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    * E0 O1 N5 J! L; b8 ?; m
  132.        }    & H- g5 D2 X( S3 Y
  133.     + I) ?3 J9 b! J# K! o6 B$ [0 [
  134.        return ($distance<=$allowGap) ? true : false;    + D& n7 u% r0 x; @
  135.    }   
    , \/ V/ w: ~: w+ R( r7 m( b, ]
  136.    
    ) m! @7 o' v) S4 T1 ^5 i
  137.     % r, e; `  p6 ?
  138.    /**比较两个图片文件,是不是相似   # S) W7 N& q' n  k( n( B
  139.     * @param string $aHash A图片的路径   + J/ U' h" g, U. l, O
  140.     * @param string $bHash B图片的路径   
    2 Q. ?* w7 D+ `$ y+ }8 N& `
  141.     * @return bool 当图片相似则传递 true,否则是 false   ) w7 d. W& S# A7 ?4 y
  142.     * */   
    2 K5 Y+ M7 U. a& a, ]" X% p3 k# z
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    # q) t$ c2 e. K( @
  144.        $aHash = ImageHash::hashImageFile($aPath);   
      Z, Q/ M' ^- `! O7 Z5 P! @! r
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    . @, X/ _0 {) X( E0 H
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    . e) l' K: b/ Y8 i, f
  147.    }    ! ~4 M: U# m. d7 |& f
  148.    
    , I, \* b& v  N1 g2 y9 i
  149. }
    ! B: {2 }- {4 P. T0 F6 C0 h
复制代码
$ ?) Z/ Z! g3 M$ D" m

1 X! B/ h# q. J# k5 |* h1 b: Q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 00:50 , Processed in 0.121575 second(s), 20 queries .

Copyright © 2001-2024 Powered by cncml! X3.2. Theme By cncml!