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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图: A3 N+ p, l) z9 Q9 Z/ F

3 j9 T0 N; |. D2 u& z1 o9 K, K; _

( e% {8 D/ O6 ?0 \& w; N由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
; k$ k& I  D8 u8 T& z7 {
  1. <?php   
    1 l- w4 t5 Q% C
  2. /**   6 u) A6 m. v/ ~* U
  3. * 图片相似度比较   
    7 y0 ~) v  ?3 T8 g1 j$ G' x: G
  4. *   
      f) f2 n# \- ]7 H3 m
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  $ Q! L  g1 W! i7 m7 Y$ l( b6 h
  6. * @author      jax.hu   
    9 [' W4 }% o! Q% o1 x
  7. *   0 v" L# l: Z& d
  8. * <code>   
    2 p% {" y7 D; y9 G5 z; A
  9. *  //Sample_1   5 w$ [! E3 ?5 C2 y
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    , @; p# f: E) ~5 n3 A% J
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   4 z1 J! q" E, \  j  x6 e) m
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ; S) z$ I/ ?" y( U
  13. *   # t" I! S8 j" ^" J1 \) K- i2 s
  14. *  //Sample_2   1 |7 ]: y: u3 E7 _0 v, J* L! Y% p* S/ W
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    5 d1 b. ~! p! K* z
  16. * </code>   - b7 E' Y) {1 y/ q& K2 G
  17. */   
    & z, `+ v2 D( m8 U0 g) k, ?
  18.     * a/ S. \, f. ]( Q
  19. class ImageHash {    4 m- J# \: O# f% |7 w; p* |
  20.    
    % @' L9 Y* K# E6 U/ U
  21.    /**取样倍率 1~10   * ^) c  `( {1 f. A5 E8 T( |1 d$ ~
  22.     * @access public   
    ! E2 o) E% u" a2 A2 s/ G, B
  23.     * @staticvar int   
    4 k' @! ~" \3 u) c: f
  24.     * */   
    / w" M  @% I( S" U" |1 ]
  25.    public static $rate = 2;    . w% G1 K9 a; A5 j; ?: V
  26.     " C. s! }; W/ N6 b! L
  27.    /**相似度允许值 0~64   2 f- h; V: e' O- @
  28.     * @access public   ( W  m3 i2 S, X  @  M
  29.     * @staticvar int   
    8 k' K. t2 g( w2 Z+ q9 B
  30.     * */   
    9 {5 S4 Q* \% I; i
  31.    public static $similarity = 80;    5 ~- N) s  x" F9 h% d9 e
  32.    
    4 Q1 g3 w7 j5 ]  H( Y
  33.    /**图片类型对应的开启函数   2 y0 i, K0 M- Z. `/ E* i/ K
  34.     * @access private   
    ( i1 d/ g$ F& R6 Q! S& x
  35.     * @staticvar string   8 B* I- X$ \& q8 n, O
  36.     * */    / m- s0 g2 K5 I. y
  37.    private static $_createFunc = array(   
    $ V4 O. `7 P; s1 f: N
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    7 s# x; u3 _- C* H
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    , u3 q7 H4 U2 s( q' [
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    $ Y& i) I5 A( {: H$ \* f( {9 n+ S
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    5 V5 `6 H4 |% u# {
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    ( e5 B1 {% S7 |* e
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    0 R  ^% U  y" f4 y/ X/ Y1 j% W
  44.    );    0 Q: P1 b0 F. e" S# m3 V
  45.     : Q- ^" _; h6 e# P6 S% Z
  46.     : j1 i7 A) n* R6 h  b2 j. ~
  47.    /**从文件建立图片   . `  G, o. k' q; q
  48.     * @param string $filePath 文件地址路径   
    & i" }, n5 y  K0 a
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    * Z3 Z* @) w/ T% V- X
  50.     * */   
    ) [2 u' _+ n) v; s& s! a
  51.    public static function createImage($filePath){   
    ; R! D6 u' n  ]' `3 l
  52.        if(!file_exists($filePath)){ return false; }   
    0 a. F! y! S4 X( S, b& _9 _, ]6 x( f
  53.    
    - z( e4 [& \- L& h
  54.        /*判断文件类型是否可以开启*/   
    5 a# O5 N$ E# y* o7 w
  55.        $type = exif_imagetype($filePath);   
    & {: [/ X: M$ Z0 d6 R" y
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    5 A8 s; E) j0 a- D, g  P2 }
  57.     ( R1 |. P$ x. T: W! ]) o
  58.        $func = self::$_createFunc[$type];    ( {; x8 e2 ~% `/ D+ I7 g
  59.        if(!function_exists($func)){ return false; }    8 ~. N5 J4 ?( h7 v. ]6 j8 o, r
  60.     " p, V: {( M1 h+ G! `. I7 `: D
  61.        return $func($filePath);   
    2 w; S, G- `# X9 ~& g
  62.    }   
    ( |& ^0 O$ _/ L( J9 ?  q, C1 F0 R
  63.     0 W' f8 r5 d2 g' b" D+ }- a
  64.    
    7 F; K! N- s. t1 b0 S2 g
  65.    /**hash 图片   4 v$ O! v5 Y) \# _+ \7 @
  66.     * @param resource $src 图片 resource ID   
    ' G" Q8 _3 i1 N; l0 [& |; T; H4 I
  67.     * @return string 图片 hash 值,失败则是 false   
    5 i5 ?' b1 N' W. `
  68.     * */   
    ( u2 V) u! g/ D* y6 P
  69.    public static function hashImage($src){    * s4 ^- Y; r- A% I3 `# C. R6 C# b
  70.        if(!$src){ return false; }    2 f. x2 w/ S9 I) |  c& |
  71.     4 F4 U. t- }% K5 E7 ^% s. `4 I' p
  72.        /*缩小图片尺寸*/   
    # \, `* S, {7 }) W) X' [# H+ S
  73.        $delta = 8 * self::$rate;   
    . k" X0 f: d" }& s
  74.        $img = imageCreateTrueColor($delta,$delta);    ' X) e- G9 w1 _. f3 H' a( b7 c
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ! O9 u' p$ c0 ^2 ^+ J$ |9 v
  76.    
    " a4 H0 X( C% `; ?; u1 g7 Y9 R( p
  77.        /*计算图片灰阶值*/    7 `6 {0 E6 i' _5 M: P8 Y- t; k1 _# z
  78.        $grayArray = array();   
    7 J4 {2 b3 Y, I
  79.        for ($y=0; $y<$delta; $y++){   
    " y. Y' q. l9 x+ m! a% Q/ z: \: b
  80.            for ($x=0; $x<$delta; $x++){    # E) P2 U* h" d) I( y
  81.                $rgb = imagecolorat($img,$x,$y);    * e( \3 i4 E3 ~8 A; e1 a
  82.                $col = imagecolorsforindex($img, $rgb);   
    # K% c1 A5 {; @6 o) V
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    , g$ I* U: ~" e
  84.     . R& U% C1 K8 N$ V- E' v
  85.                $grayArray[] = $gray;    / \2 u8 o) i! U% c0 H! W$ l" Q% s8 \3 T" D/ m
  86.            }   
    . G0 [5 _7 x- m, }' H! v
  87.        }   
    7 K& ~: i" T2 k& O. f9 o4 O- m
  88.        imagedestroy($img);    & i5 ^6 u" }" X; u: w$ d
  89.     * f: E% t3 G: \% [
  90.        /*计算所有像素的灰阶平均值*/    $ a" R; G7 ^( ?, Q
  91.        $average = array_sum($grayArray)/count($grayArray);    7 N- g4 j' Z" t: S( C
  92.     3 m; Q0 B# d6 t% D. M: K
  93.        /*计算 hash 值*/   
    . D5 p) g% Q. {/ w4 j8 q
  94.        $hashStr = '';   
    & S0 a3 E+ O5 s# ]6 K  i' X
  95.        foreach ($grayArray as $gray){   
    % H! Y( m6 O6 O+ q; i$ |, U7 y  H
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    1 F( X) f# r8 F/ \0 v3 e- j
  97.        }    7 w% }4 Q) D! b& @
  98.     / B$ G# R! D! X+ d$ ?# g. m
  99.        return $hashStr;   
    4 a& w' S- G, E7 X( p  b" z; D
  100.    }   
    ; y) ^+ S# m. z8 V4 k
  101.     2 K% }% B* Y( T, h! W. x9 `( D
  102.     0 F2 S, y; K! w! U, r, q. K& J
  103.    /**hash 图片文件   
    " p8 E; V- o4 c3 m! Q
  104.     * @param string $filePath 文件地址路径   ! R+ d5 a: P9 ?0 ~: i1 R  A4 y( v4 k
  105.     * @return string 图片 hash 值,失败则是 false   
    ; h/ K$ l* T0 F( J- ~8 }% r& ^
  106.     * */   
    ' |/ U# t' J/ b. m( H5 Q
  107.    public static function hashImageFile($filePath){    / g3 m+ q& v; w% z  x0 K8 J
  108.        $src = self::createImage($filePath);    # r. `1 j$ c% U2 h: R2 g; l! @! g
  109.        $hashStr = self::hashImage($src);    6 c0 a* v- Y6 F
  110.        imagedestroy($src);   
    8 Z% L1 E% q; c/ a3 u) W& M
  111.    
    * O4 A# G) r8 g1 \1 ~% Q( ~0 H
  112.        return $hashStr;   
    8 K9 |% V. Q( l, Q- D" N, K/ Y
  113.    }   
    1 O# Z4 t. C8 k, x
  114.    
    ' K5 J7 @+ n; G: {7 G# \
  115.    
    * H- q' p* z0 I# M  N0 c% r
  116.    /**比较两个 hash 值,是不是相似   
    0 E* u5 v7 B7 X/ p0 a0 m' c3 Y
  117.     * @param string $aHash A图片的 hash 值   
    " G9 Y* P6 F. D. @7 e/ J- w6 X
  118.     * @param string $bHash B图片的 hash 值   ' y0 ?7 \7 F" [4 ~9 h- p
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    + K  _2 _; h( v9 J( \% p; I+ R
  120.     * */    , w0 M9 B3 u) [: n5 y4 V8 }
  121.    public static function isHashSimilar($aHash, $bHash){   
    7 {- H1 Z3 w, ]& l
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    9 b$ M  g5 k5 D8 _- J) z' h
  123.        if ($aL !== $bL){ return false; }   
    5 o; u0 A+ j1 G% c" W
  124.     - `0 j3 _) F, i% W
  125.        /*计算容许落差的数量*/    / t+ q  `" m7 h' c' n
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    $ ?1 s) T( O8 c
  127.    
    3 _* z" p$ E# h) f0 m
  128.        /*计算两个 hash 值的汉明距离*/   
      y. f' F) T+ G! ?4 n! Y* E7 ]
  129.        $distance = 0;    & Q$ E' x, W$ k$ {; I  [& a
  130.        for($i=0; $i<$aL; $i++){   
    0 v- v5 r# k  n! k
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    / ~* E$ z6 O4 T) o6 D* e) o- j
  132.        }   
    , ?$ N& Y, a1 d8 [* X2 _
  133.     ) p8 ^. a; e: O# @7 Y
  134.        return ($distance<=$allowGap) ? true : false;    3 |( C$ b0 E8 ]2 N' x& R
  135.    }   
    & P& F* A; T+ k! M* ~" h' k7 ~
  136.     1 E) q* v" o. D" Y+ m
  137.    
    5 {& f) f9 g- e8 [' _- W; H2 T
  138.    /**比较两个图片文件,是不是相似   
    5 h0 ~5 j: }% a
  139.     * @param string $aHash A图片的路径     l, |& s, W# ^. G+ i
  140.     * @param string $bHash B图片的路径   
    * H5 `% N1 j) Q) J- h
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    8 O' q. r5 Y+ u  y- x' Z- l5 T
  142.     * */   
    # ^' m9 O1 P1 [" o) s0 k
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ( e0 M8 N0 t5 V% L2 r6 v, \
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    - C3 ~$ y, O# N2 q0 {
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    3 @2 U# c+ O/ l! P5 I. [
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    6 @/ Y' u/ j/ |+ Y1 ]5 ]2 N
  147.    }   
    0 V9 g/ q4 F  {0 j' m
  148.    
    ( Q- T0 k% s: p/ O8 R4 a5 |1 g% M
  149. }. H" A% u8 ]/ W( k4 b8 I1 k$ ~
复制代码

8 R. f2 Q. V. B+ a9 ^+ p
# ~, B( Q* o. ]  m) a
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 20:21 , Processed in 0.083794 second(s), 20 queries .

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