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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

: a% Q- s( o% S: D由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
& S5 z0 {4 I  U, ~+ }
  1. <?php   
    - U$ Q: G/ \' b! j& U6 N! e  l1 ?  I
  2. /**   
    ( r1 n: \- U: I6 |' u0 r
  3. * 图片相似度比较   9 j, z/ W2 f- T3 f6 N4 u$ h1 C
  4. *   , s  f$ M2 u9 Y5 w  S( f7 G' {* w( N, K) D
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ' W3 Y( Y# s- m5 o! p* ^% j
  6. * @author      jax.hu   
    + U. f1 P$ y6 N) {' I! |
  7. *   9 m7 N7 g0 h- V% x/ v) _5 i
  8. * <code>   
    $ u- G* I7 B- [' P( o5 ]: R
  9. *  //Sample_1   4 E7 B, _  Q0 n+ K% i
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   9 a5 Q3 B2 ~4 r1 x) K% ~. Z& W
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   " [( X6 ~" P1 q+ s4 B. S; ?8 H
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   7 O3 a! S8 L: f3 Y
  13. *   % a! s/ y  L! J$ q* I' i
  14. *  //Sample_2   $ q, i6 V) ?2 D- ^5 v3 }1 W
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   0 r; C8 O+ \6 S- i
  16. * </code>   
    5 k( O: j0 C' z7 B) d
  17. */   
    6 w4 L' E+ K. _" `3 a2 `6 y: r2 j
  18.    
    : m! J" b( p2 ?+ q
  19. class ImageHash {   
    4 R6 t: l0 K* H" }' L# V) x) V4 c
  20.     3 n0 L$ G8 S/ I- Y! s. B- `$ G9 Y4 t
  21.    /**取样倍率 1~10   
    & {4 E( R( `) P! W; i
  22.     * @access public   0 a  {) U  C& S2 y
  23.     * @staticvar int   7 g: u, p& T2 E$ k. s9 V8 j7 g# w
  24.     * */   
    % z8 w$ b! K4 E, w4 I% G
  25.    public static $rate = 2;   
    ; _6 |0 F& M5 o, w2 B
  26.     : v# ?: J9 a8 v4 h& r6 A* U
  27.    /**相似度允许值 0~64   9 y3 F5 C% P& a$ D
  28.     * @access public   # J( T. {1 T4 e
  29.     * @staticvar int   
    ! y* {, I9 `1 I
  30.     * */   
    4 }& ^" |# }: ?" Z
  31.    public static $similarity = 80;    * j; O  l; \: r
  32.     ( c1 q" d6 u5 h
  33.    /**图片类型对应的开启函数   
    ; ?$ A, l# Z1 c( g, u
  34.     * @access private   
    / `: F# t; A4 `5 S" j$ [
  35.     * @staticvar string   
    + v" o4 p8 Q+ v: |! z! J9 _; P
  36.     * */    & Y% \1 Q; l3 ]
  37.    private static $_createFunc = array(   
    2 N. r3 O* L$ W1 h
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    $ f4 N" B% s/ H
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    - E7 Y1 @" |$ ^' B, r
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    9 h$ e. s, M/ R! o5 R
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    5 U+ V2 J+ S, z7 ?
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    , n! S( P, ]6 l  c7 B3 |, }$ ]
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    9 d0 f  V; f, |& I* E
  44.    );   
    7 {9 |- O+ B4 j, L6 }
  45.    
    9 l" V1 G8 n* l$ o4 }. X
  46.    
    6 i4 e' ]+ e5 ^1 R# y; N
  47.    /**从文件建立图片   : l4 w; D% e) o+ o
  48.     * @param string $filePath 文件地址路径   ! D# ~( p" Z9 y' Z
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ( |# E8 J+ K* B4 ^4 W, ?$ F" V9 d2 G* W
  50.     * */   
    / I3 F& F6 C  Y8 S# B  h
  51.    public static function createImage($filePath){    3 [; y: b) b2 R" X/ r1 b2 Q+ y
  52.        if(!file_exists($filePath)){ return false; }   
    " I1 z- D9 P8 |, T! `
  53.     ; t1 ^: M4 _. _$ K) ]- G
  54.        /*判断文件类型是否可以开启*/    ; P. h4 X, ^$ ]$ s
  55.        $type = exif_imagetype($filePath);   
    6 i0 J+ K0 f: T) G* N
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    5 t" ?4 l# M! \9 ^- D& I
  57.    
    " L( Q! Y  g5 `* |
  58.        $func = self::$_createFunc[$type];   
    7 I$ y* H4 c1 Z
  59.        if(!function_exists($func)){ return false; }    * J; i$ O% N; `* c6 u: h
  60.    
    9 ?# C8 ~& t, L! S
  61.        return $func($filePath);   
    9 X: H2 u: y2 G- c) I5 R: w- x
  62.    }   
    6 P" M6 i& T$ a, P
  63.    
    : [: j" O6 q6 y; X; \8 M
  64.     . f9 a+ \6 l5 B
  65.    /**hash 图片   6 {6 |% k6 X/ H0 H
  66.     * @param resource $src 图片 resource ID   ' w0 p5 s8 u/ ]1 {( t
  67.     * @return string 图片 hash 值,失败则是 false   
    7 L6 `- y- z6 f, X% w3 s& C  L
  68.     * */    ; ~* o2 M0 q! e$ q8 X% `7 b
  69.    public static function hashImage($src){      Z: l2 n! o( W8 d4 @
  70.        if(!$src){ return false; }   
    - s1 U4 x/ q. A+ x6 O0 m
  71.    
    ( d. J' b  w  `1 F& q
  72.        /*缩小图片尺寸*/    , v2 y/ U1 O/ t8 s0 G
  73.        $delta = 8 * self::$rate;    ; e8 A% }& m, t
  74.        $img = imageCreateTrueColor($delta,$delta);    ( f. j# M3 @6 q% c, O3 {" b. f
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    7 e, w+ K0 ?9 d% ]3 O; L3 G2 S
  76.     5 Z) K# j* x0 _0 u( ]3 q# X. {
  77.        /*计算图片灰阶值*/    2 S7 A: x8 }9 Y1 _9 K
  78.        $grayArray = array();    . k8 W" @+ R  e. ]6 R& f
  79.        for ($y=0; $y<$delta; $y++){   
    ; B0 u$ t$ w7 \7 |
  80.            for ($x=0; $x<$delta; $x++){    * }& X: t0 t- _( A/ z* Y
  81.                $rgb = imagecolorat($img,$x,$y);    2 @) |) d  e, R& {, ^
  82.                $col = imagecolorsforindex($img, $rgb);    7 T, _/ L0 b9 U
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    7 m! s, A6 C( O4 E( i
  84.    
    # ]$ n" L. p# t
  85.                $grayArray[] = $gray;   
    4 y1 I6 ~# s( |0 C% A6 S
  86.            }   
    " E( [. l5 j$ x+ u
  87.        }    4 _$ T! e/ h2 B# b
  88.        imagedestroy($img);    ! L2 @3 t' K+ T
  89.     ) O9 M9 D( E6 v& E" A. E- L
  90.        /*计算所有像素的灰阶平均值*/    , x+ B1 ]# l8 G3 `
  91.        $average = array_sum($grayArray)/count($grayArray);    ; T6 f; W/ V) E
  92.     2 I6 c- w- J& Y7 L8 A* \  D2 h- ^
  93.        /*计算 hash 值*/    ) `9 e; T" N0 p9 L. B
  94.        $hashStr = '';   
    ) J2 u* }4 `( ]3 _+ g
  95.        foreach ($grayArray as $gray){   
    ) a, l9 J9 X% e6 ^' O* \
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    " n5 J+ F* N, W, j2 E1 a! ]( a
  97.        }    8 D5 [. o5 e% A" T1 j# F0 O- O
  98.     ! V: n8 z6 J8 F) n9 u, c  I
  99.        return $hashStr;    * d, t  E2 {# n; L0 e
  100.    }    8 t2 Y5 k! w$ R( a* w
  101.     ' A: x+ D7 I& s  r* ~9 F+ d
  102.    
    3 E5 }* p6 e2 \9 p& c' I- K
  103.    /**hash 图片文件   
      ]2 i* s8 {& x" p6 I
  104.     * @param string $filePath 文件地址路径   / Z* m. V) F4 N3 q
  105.     * @return string 图片 hash 值,失败则是 false   
    . G4 j: `- o/ _7 o. Z
  106.     * */   
      y3 ^& ^/ y4 t3 d. S3 f) K  {! D
  107.    public static function hashImageFile($filePath){    : Q* g: H; }& q. f  j$ Z
  108.        $src = self::createImage($filePath);      h  k$ S! q; H& D- A' S1 G
  109.        $hashStr = self::hashImage($src);    # g3 m) G; L. n6 z; ~& [# N  Z
  110.        imagedestroy($src);    9 S4 G7 T) [; b. Z
  111.     ( h7 O0 U  g7 A" ?! k: e
  112.        return $hashStr;    ( `  A0 Q  |) V' y6 j
  113.    }    5 T  i! r1 T( k! N
  114.    
    3 ?4 K2 I7 l5 W
  115.     1 U& J7 g( k7 r8 h' \  B5 n
  116.    /**比较两个 hash 值,是不是相似   , p6 Z* y( v( g5 K4 C8 L
  117.     * @param string $aHash A图片的 hash 值   
    2 N! \' c  b! Y6 ^* e
  118.     * @param string $bHash B图片的 hash 值   
    0 w8 b" V0 C) P  r  A
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    6 R/ x7 ]; U/ v  M" N& O
  120.     * */    2 _" d/ q. E8 a
  121.    public static function isHashSimilar($aHash, $bHash){   
    ' h5 \9 O4 x1 ?& d$ o) V
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    5 h& o. M+ N) O, `! s+ C
  123.        if ($aL !== $bL){ return false; }    # h+ l* A8 ]0 Z/ L8 ?: ]
  124.     9 G: R- W* ^3 i/ L6 u& V
  125.        /*计算容许落差的数量*/   
    ; n6 K! j6 k8 S
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    3 o- {; {- G% I; e
  127.     % w- u  S4 R! p# V, A
  128.        /*计算两个 hash 值的汉明距离*/    : e2 _2 _& G- B! d% {* h- F
  129.        $distance = 0;   
    2 N/ k1 M' H- z9 m' l0 P8 Q- x
  130.        for($i=0; $i<$aL; $i++){   
    * Y- u( v: ^. G' u# t# V  g& O
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    ' K7 R- P0 r0 W- Y; m
  132.        }    $ g+ X$ n5 P% S$ `2 K& W  @: h
  133.     ' v9 z  L  g# ?% x* W( a/ k
  134.        return ($distance<=$allowGap) ? true : false;    ! B, g( @& N. C9 ^; D
  135.    }    1 S3 r& ]& a3 j( [; x7 {
  136.    
    ; ~, U) Q3 v- T: k
  137.     : L( k0 y) D! P/ H% F% p/ D
  138.    /**比较两个图片文件,是不是相似   
    / e6 k+ h: o1 W3 W8 u6 i
  139.     * @param string $aHash A图片的路径   ! f) v2 ~! F# m
  140.     * @param string $bHash B图片的路径   1 D' b+ B& d* g5 s
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    : w& S4 R/ @( c+ p5 E9 z7 d
  142.     * */    5 q- E. ]  _4 T  _# O
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ' u; X( v: w% _4 w# m- F+ F1 L
  144.        $aHash = ImageHash::hashImageFile($aPath);    # C' {) D- v, b' x- n
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    . ~8 A; H, D% n/ Y# ~( p# S; ~+ J
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    5 P& i3 Y4 P5 h# j/ o+ y
  147.    }    ( R8 r2 N. g1 c- K$ k
  148.     2 \% l# l8 G5 R1 [+ Z( r/ |
  149. }1 m  ~2 ?5 h: j/ h7 z6 S
复制代码

+ V9 ]2 I; i3 ]' ?1 f: b
8 o( S5 |  t  L
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:42 , Processed in 0.057242 second(s), 19 queries .

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