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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" K5 e" c$ y  P

5 [" v/ a% L  @7 i* N由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
. M& C8 b9 v' P+ ^9 `9 u4 J
  1. <?php   
    8 @1 R: j) f1 \' d7 l. A5 ~0 j
  2. /**   - j1 E( L6 s, U; I: m- T; U1 f& E
  3. * 图片相似度比较   
    " b6 a* Z6 H9 M/ k! B8 I; {9 k8 i
  4. *   
    1 ]8 D% L; J6 [1 K
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  1 d$ a' A  @# {0 K3 N
  6. * @author      jax.hu   2 G$ T% g6 R# h) z$ g% v
  7. *   
    6 D! {% x- i: v
  8. * <code>   " I& K; d/ q* n% u2 k' F1 T5 _
  9. *  //Sample_1   
    1 d/ p) `2 _+ A2 w9 T, V
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    5 _0 |3 ^) b: n( b  A8 b3 U3 c
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    . D3 K! W# W  B, S+ O4 q
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    3 `, S) d$ U% M/ ^
  13. *   0 Q( o( V0 h6 c3 W% N% q. I# i
  14. *  //Sample_2   
    ! L7 t6 u2 |+ R7 D9 h9 E- ?
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   % M1 I3 a2 l0 m: H/ f+ s
  16. * </code>   
    7 N* _4 P9 K, x2 K7 i
  17. */   
    % p2 r2 z# B+ ]  V! E0 o2 I% T
  18.    
    * U+ [$ ^- L, A* k
  19. class ImageHash {    % X& H' Y6 B* @
  20.       c$ I- K- e& Y  }( q0 x' j/ ^
  21.    /**取样倍率 1~10   
    . J% _* y* q# ~% J7 I( R
  22.     * @access public   
    " }. X; f: d$ K, D$ v
  23.     * @staticvar int   
    # d5 Z* g7 D  G7 ]* Y* S
  24.     * */   
    ; V  m8 |! s* @! U) i
  25.    public static $rate = 2;    0 m+ R# R6 U( }8 ^1 ^. F
  26.     8 T; F2 \; L3 \9 u: [: \* D
  27.    /**相似度允许值 0~64   
    1 H7 t, i; I: T6 g( e( E: G% m; b' T
  28.     * @access public   
    4 z) x; e+ w+ @; a
  29.     * @staticvar int   5 f, U* `/ a) m
  30.     * */   
    ; a! Q6 g' H3 z/ x: z- j: J
  31.    public static $similarity = 80;    6 \& `% j2 O; X  }5 f) M
  32.     , \! f# v: p5 c# ^) ^; Y
  33.    /**图片类型对应的开启函数   % v; a8 p" \% O) X+ }1 y1 W8 d# E
  34.     * @access private   
    ) y7 U! U- T: S
  35.     * @staticvar string   ) f  y: H% |4 E/ P% C! M
  36.     * */    & M3 H5 B) l& E! ~
  37.    private static $_createFunc = array(    3 E5 v6 m8 G% ^! \8 S- `! P) |
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    - X7 \; i# R% L" U
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    " ?: {% @& s8 U
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    % D4 W' L( L7 A  O+ [
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    . l, `  v1 E; t2 B+ G* a% O" r
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    4 t' h. A- @+ K$ {+ t
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    ) F4 c2 D! k) X1 A
  44.    );    7 J4 A% Y* p( \0 \2 O4 g
  45.     5 S7 d' T. H5 L1 R% i' `
  46.     2 S, d( P+ y# D2 D8 h, o
  47.    /**从文件建立图片   2 r# k& m; t6 ~8 Z$ C
  48.     * @param string $filePath 文件地址路径   
      \2 ^) t5 u7 H; x4 a
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ' H4 A7 L" ?0 d; T4 `. z, q. X9 {
  50.     * */   
    $ N7 E- W. C; x( Y4 _
  51.    public static function createImage($filePath){    ! _3 j3 m) E* Q: h. f
  52.        if(!file_exists($filePath)){ return false; }    : F8 ?' Y* e$ A% q/ B: W
  53.     5 x0 K! P5 U) {; _, U# C9 D$ a
  54.        /*判断文件类型是否可以开启*/    + e" O2 A; a4 \3 r* u# B' P
  55.        $type = exif_imagetype($filePath);   
    8 o: h$ @, h% _. ^% x9 m# p* ^5 i
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    % G2 Q) }$ `3 O
  57.    
    / k( p; N) Z3 i5 t" W
  58.        $func = self::$_createFunc[$type];   
    & [% z0 q: b6 S# B
  59.        if(!function_exists($func)){ return false; }   
    * p4 d/ C* a& [, s; a2 t, T
  60.    
    * H; o! H! P" P
  61.        return $func($filePath);   
    & q0 @9 J8 x- i& s
  62.    }   
    . m: V" H6 z, c+ ~8 D( l; |
  63.    
    ( [! Z( _- Q  m# }$ Y& I, \8 x
  64.    
    ' t) C' J) e0 t7 F5 i
  65.    /**hash 图片   3 D# \$ I( R' L
  66.     * @param resource $src 图片 resource ID   9 G' C3 G' X+ s% O! P
  67.     * @return string 图片 hash 值,失败则是 false   + {( b! e  i8 q7 n+ p# X$ u
  68.     * */      C2 `, I. [: W. B, ~
  69.    public static function hashImage($src){   
    ( D- n( }- T4 V
  70.        if(!$src){ return false; }   
    & u. I) A1 O. y8 Q
  71.    
    / s- [  t) V  J, U+ z
  72.        /*缩小图片尺寸*/    ( I# K  L3 s$ q  n+ b9 g+ s1 P
  73.        $delta = 8 * self::$rate;    3 H  k) i/ t/ y% ^' B/ ^5 t# M* q
  74.        $img = imageCreateTrueColor($delta,$delta);    ; ^9 p9 e3 I; o" J! E' X1 Y' M
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    8 N8 n5 _8 v0 L1 ]) `( s
  76.     9 W. q0 ?! b1 W5 _; [! ~2 @
  77.        /*计算图片灰阶值*/   
    & D0 `  g9 [: S, K7 A% P
  78.        $grayArray = array();   
      ~' m/ e; F) n) n1 S% N
  79.        for ($y=0; $y<$delta; $y++){    1 P2 L) u! H3 ^. L6 l; B# [  g
  80.            for ($x=0; $x<$delta; $x++){   
    5 k2 j/ o. T# z9 g9 N# ^
  81.                $rgb = imagecolorat($img,$x,$y);    , ^: I$ o# r! n; o- L; I& g
  82.                $col = imagecolorsforindex($img, $rgb);   
    . r, c) j4 `$ p% w6 D" z
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    3 a5 K, E0 R$ |# n! b+ g
  84.     : ~8 Z( X4 O( g$ P% t/ ?
  85.                $grayArray[] = $gray;    ' ^2 X$ K/ }" P, M- O9 s) _
  86.            }    % a6 o( F# u& e8 C! a8 i. |
  87.        }    ( w& l& s- V6 Y/ w" \
  88.        imagedestroy($img);   
    2 @4 [( [2 {2 ]. _( ^! s
  89.     6 w) ~- w, V0 L* M
  90.        /*计算所有像素的灰阶平均值*/   
    ' h$ o0 h9 B. L; O/ B* y( h
  91.        $average = array_sum($grayArray)/count($grayArray);    5 o% l. f4 J. q8 |+ Q/ L. }$ P
  92.     * N  }/ x# i8 L% L9 s
  93.        /*计算 hash 值*/    1 J! |9 ?4 f- z# }7 ^2 l
  94.        $hashStr = '';   
    4 v* f" m5 s1 W# Q
  95.        foreach ($grayArray as $gray){    4 p8 Z7 s3 y0 i# B6 v
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    2 M5 _( i1 x8 ?9 e$ ^
  97.        }   
    / e, d( N. B! v. Y4 O4 k8 Q
  98.    
    3 Z/ Z1 D* Q; B: w5 N0 H4 g
  99.        return $hashStr;    ! f1 H% o4 Q0 }; L# _  T2 S
  100.    }    # z5 R# g% p/ L, j6 z
  101.     9 `  B/ |8 ^$ r! l
  102.    
    3 Q) O% |% ?6 y7 M9 q0 `
  103.    /**hash 图片文件   
    7 w5 F# Z* i! ]& }& i
  104.     * @param string $filePath 文件地址路径   
    5 b$ ~) |2 W  u/ E# u, K
  105.     * @return string 图片 hash 值,失败则是 false   . \% @9 \1 u" {' W# O" D1 a
  106.     * */    . \2 G$ V* P  r& h
  107.    public static function hashImageFile($filePath){    $ _0 ~) b2 w- [- b8 y4 q2 i! \+ N% P
  108.        $src = self::createImage($filePath);   
    ! b4 b1 d0 O$ z: K, z
  109.        $hashStr = self::hashImage($src);    ; {9 k# T9 m9 D2 M$ t) @9 [8 V
  110.        imagedestroy($src);   
    ( [: N4 ~: `/ E, y% I+ M% J
  111.    
    + H  r1 W: _1 f5 u/ j# \# s- T3 P+ J& V
  112.        return $hashStr;   
    0 s% L% @) z4 y4 {0 U
  113.    }    " \% Q# @8 b& C6 n  H
  114.    
    , y9 @* g3 @. a; r0 k0 r
  115.    
    & p6 l2 y2 \# M4 K3 x1 O
  116.    /**比较两个 hash 值,是不是相似   
    / Q: R  i6 v5 k: q! h" t
  117.     * @param string $aHash A图片的 hash 值   4 i" D7 U" B* _- |/ ~7 ^" M4 Y
  118.     * @param string $bHash B图片的 hash 值   
    - {  O& S- ~$ h- K& C7 O# I$ p
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    5 F" _3 ?$ s$ M' t  b  h
  120.     * */   
    * q! D. ~! L: P+ Y, s; P  v
  121.    public static function isHashSimilar($aHash, $bHash){   
    1 n6 `8 Y; B3 Z9 a" X1 R# E. j: H
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    & c3 `( n2 U& `/ b. J( }3 y
  123.        if ($aL !== $bL){ return false; }    # _7 |0 |& o" H0 M
  124.     # [& c  P0 I6 ?
  125.        /*计算容许落差的数量*/    7 G: |4 O8 x8 X& m
  126.        $allowGap = $aL*(100-self::$similarity)/100;    % [/ H( f3 F& c0 `% \6 ?- J/ Y
  127.     6 m# }7 ]# m5 k2 r
  128.        /*计算两个 hash 值的汉明距离*/   
    5 R$ x  f+ g) ?+ X7 l- d& Z6 G
  129.        $distance = 0;    % W9 r; Z2 ?) ?' x, p
  130.        for($i=0; $i<$aL; $i++){    ' o+ ~9 d0 W0 Y0 J4 Q, E! e& a' z. Y
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    / ^8 w+ `  `. e( E( X
  132.        }   
    3 `+ }. [0 Y8 }  e. [0 Z
  133.     ( @9 ?9 B% R  u0 I
  134.        return ($distance<=$allowGap) ? true : false;    ; A- ~+ G, D, \6 S* v
  135.    }    2 J& v. k6 v$ B  Z2 ^  I
  136.     5 Y: s7 f$ n  s( k
  137.    
    $ T2 i6 A9 |1 i7 L/ _7 ?, d! C
  138.    /**比较两个图片文件,是不是相似   : [! U4 U6 I+ L0 N0 O$ y
  139.     * @param string $aHash A图片的路径   
    2 t; B* H& R6 p: }
  140.     * @param string $bHash B图片的路径   # W  m. T0 E, A% V7 G6 X+ v- G
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    / A& p, u# E% a& R  C5 `# ^
  142.     * */    : |6 _! w1 O2 E; e  u0 }1 `" h
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    / I* g' I6 W3 x" W8 K) W, h) {
  144.        $aHash = ImageHash::hashImageFile($aPath);    5 e! _, v) _# ?% _  c. J8 E
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ; h7 J; t6 A+ a( o# n; R
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    5 d- |+ N  J! ]2 _. V( ]( C
  147.    }   
    0 C2 A7 a& q, y/ h, a. p, p% q
  148.    
    - R  {9 c% Y3 o% f# u
  149. }
    ! f# C- E4 W/ U# x
复制代码

1 L2 q9 f/ o( |! C1 s$ c/ ?" M* \, V: W" R! I. K. |: _& L
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:10 , Processed in 0.056897 second(s), 20 queries .

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