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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

  R. Y3 U1 A( [0 v/ P* W) o由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

$ O/ s9 d( ~9 @. n3 K
  1. <?php   
    ; Q% w* M& i& W9 [6 P# S
  2. /**   
      k- [# f% v8 }0 S# O8 D
  3. * 图片相似度比较   " e9 }" t0 k$ B' B0 o* J& Y  Q
  4. *   ! E+ X. `* ^$ ?
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ! W+ D& e# D5 \- E) }
  6. * @author      jax.hu   
    : D7 s; o: [% p+ }
  7. *   
    5 x7 P# O/ _- K4 H1 R6 |$ {
  8. * <code>   
    ( Y( B+ r  c9 V5 i  z
  9. *  //Sample_1   9 j' z% e9 m2 p
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    ' L9 |' |: b: y# Q: k
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');     q# k9 j3 z6 l* |9 {
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   $ F; O0 K3 n8 m7 G# d# Q* ^* ~, ]" N
  13. *   / q* Z0 [" I  K3 n' D
  14. *  //Sample_2   " w, e/ p6 q- B* v
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    7 }  a& @, S# o) Q- {: ~# n
  16. * </code>   
    5 I  }1 R1 M, L
  17. */    : o: b! ~; z0 I; J
  18.     6 ?- Y7 p& x' a5 I: N) m
  19. class ImageHash {   
    4 X$ z2 V, Q3 s8 P: C4 y( o5 N
  20.    
    1 F( A" c1 x2 j
  21.    /**取样倍率 1~10   1 S* z" P3 P" l0 X' m0 g; a* N
  22.     * @access public   ( d) }5 t0 h# H' y
  23.     * @staticvar int   
    " a, W3 l, ^6 z7 `/ S
  24.     * */   
    7 P# P5 A1 O' J* Y
  25.    public static $rate = 2;    $ w  d' F( L, z6 S% {; C4 z
  26.     , D8 H. e. c* W5 Y) H
  27.    /**相似度允许值 0~64   
    * w  z* i; w! o7 [
  28.     * @access public   
    - ~3 _+ |" o' m: M: T8 v0 o' _: w
  29.     * @staticvar int   $ M. }- R- J9 |0 }9 y8 j$ D
  30.     * */   
    0 W2 o7 |5 z1 t; R% L! ^
  31.    public static $similarity = 80;    ( y- u' x8 g" \6 N+ y& V
  32.     # s5 O2 p3 I7 y! S& m8 f
  33.    /**图片类型对应的开启函数   ( H5 d$ k- f/ o5 o. ^2 m1 S6 ]5 _
  34.     * @access private   
    + K7 |( x0 B$ c: t) J
  35.     * @staticvar string   ) W2 T+ N. }2 _( J6 b) ?
  36.     * */   
    9 D/ k% ~3 x3 G) w- F8 ?
  37.    private static $_createFunc = array(   
    5 R$ [/ j# H% [/ ]9 [+ ~) Q
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ! V6 w+ j0 m8 s7 W# R, w
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    % H6 w/ t5 f6 ?1 \! P
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    - R  J% V# D. o8 _: R4 X* I- R
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    # d6 n; S, B5 n5 v8 ^/ p# `
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    9 u& z" J/ J6 a& N$ C
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
      n! h- i0 F- R* d
  44.    );   
    4 F/ E- n# }- S8 q/ N9 D
  45.     4 G2 y# A7 z# i% ^
  46.    
    1 i9 n6 ~9 g% A6 B1 L
  47.    /**从文件建立图片   , [" r3 @. @& f) a" \* ?
  48.     * @param string $filePath 文件地址路径   
    ! m7 v1 f8 P4 ]: o8 F; Z
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   0 h& I4 W6 h6 j' i! v
  50.     * */   
    ' U9 o% B/ `! ~  b" g  z5 y+ t
  51.    public static function createImage($filePath){   
    9 T, C! \5 f- y+ e( n
  52.        if(!file_exists($filePath)){ return false; }    ) b- T% D$ h  f0 E  h- i, k
  53.     2 ]( j. S! G, i! }
  54.        /*判断文件类型是否可以开启*/   
    6 d( |/ [$ x3 ~5 v  t+ d! e0 k
  55.        $type = exif_imagetype($filePath);    # ^+ `4 X' n0 T8 O/ y
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    % J! R9 }) e0 K0 I4 R- f
  57.     " s; t" J- H; [
  58.        $func = self::$_createFunc[$type];   
    ( T# j$ N$ b( n' g
  59.        if(!function_exists($func)){ return false; }    0 \0 f/ g+ m& s4 |6 ?3 U7 o
  60.    
    + j, m0 c! o- m; V1 @4 l
  61.        return $func($filePath);    ) V0 A: ~5 Q. [, d# o
  62.    }   
    ) Z5 H1 {+ f/ V0 v# n7 o
  63.     ! h7 b7 ~; ^  G' @1 e( i
  64.    
    & G8 e9 ]+ I6 ]8 a
  65.    /**hash 图片   
    . R" t, o/ G/ u8 Q" q
  66.     * @param resource $src 图片 resource ID   : _8 Y( ^2 ]5 y
  67.     * @return string 图片 hash 值,失败则是 false   , {" a3 P; c7 O1 e$ z
  68.     * */   
    ' `  l7 X3 s# @4 R
  69.    public static function hashImage($src){    8 p! H2 b+ f$ A- `
  70.        if(!$src){ return false; }    ) N( J' b" J+ e
  71.    
    0 U7 ]# Z9 R# T1 d% r8 v3 f
  72.        /*缩小图片尺寸*/    . z* t/ G! }9 W% z# s2 \" _
  73.        $delta = 8 * self::$rate;    ; ]$ w+ ]/ C1 w$ o8 T( Z( }, t
  74.        $img = imageCreateTrueColor($delta,$delta);    ( g, Z* b! c* y) Y9 d. o
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ) ~$ n: x2 n) {4 N2 u
  76.     ; d/ P- w8 k2 K
  77.        /*计算图片灰阶值*/   
    $ R0 E( L: A( Y. k
  78.        $grayArray = array();   
    " Y3 O' Q  [" J
  79.        for ($y=0; $y<$delta; $y++){   
    . D5 v  \# t' D$ |8 `5 e# N" C
  80.            for ($x=0; $x<$delta; $x++){   
    9 V6 ~' E- W4 ]  N. Z+ a% q$ o
  81.                $rgb = imagecolorat($img,$x,$y);   
    : A( U% m% ^1 u& A
  82.                $col = imagecolorsforindex($img, $rgb);    $ u& h2 Q2 g3 J
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    . X( b3 I' q6 Y  B( k
  84.    
    & x5 W6 X' Q( c4 i* C2 E
  85.                $grayArray[] = $gray;    / n+ a( H1 i( Q, c1 V2 }
  86.            }   
    , {9 `& \* X' E7 @% u6 }9 J: N
  87.        }   
    & _; k! G' c. A5 Z+ b( Z
  88.        imagedestroy($img);   
      v' [/ T: A3 B) {3 H) a4 i! W
  89.    
      e+ W- @' K3 u2 |
  90.        /*计算所有像素的灰阶平均值*/    ) h5 h7 \9 r1 r% Z3 ~# v
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ; U2 E' |1 o1 w( }% u
  92.     1 }3 L% Q3 Q1 c, x% s- R5 U
  93.        /*计算 hash 值*/   
    ; W( N2 c  K" A3 v
  94.        $hashStr = '';    ; F2 s; |! b0 H
  95.        foreach ($grayArray as $gray){    # ?( d: O! i& ]! r1 Q+ S4 Q: T1 ^
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';      p  B3 \. O/ I6 E+ V
  97.        }   
    * s$ J  t: U0 r5 W# p: p1 m) E
  98.    
    3 K  L: d3 t7 e0 {% u
  99.        return $hashStr;    ( M3 r" q* d& p: n) q  v/ Y
  100.    }   
    % Y) y9 _& y4 ~# _/ B2 @9 ?$ W
  101.    
    ' z! W% U- G; ~1 Q% Z
  102.     # N& i4 P' j, o
  103.    /**hash 图片文件   
    ' i' r% W9 y% M  _2 B$ ?, R
  104.     * @param string $filePath 文件地址路径   " y: l) q. R1 j! L6 s% ~
  105.     * @return string 图片 hash 值,失败则是 false   ) o& C1 h+ T4 o( i- B$ H6 O  b
  106.     * */   
    ) E4 c2 g/ W/ A
  107.    public static function hashImageFile($filePath){      ?3 J# r0 e& C% _4 V
  108.        $src = self::createImage($filePath);    * y( \0 O2 O0 j
  109.        $hashStr = self::hashImage($src);    + ^0 c# r% I  ]' _5 j
  110.        imagedestroy($src);    * N: u' _! l$ f! D) A! }
  111.     & K5 O- m' q) C2 n
  112.        return $hashStr;   
    $ w3 e( D2 O- V
  113.    }    5 {! O! t) t- G! {; S
  114.    
    1 w; p  l4 r9 D
  115.    
    / p2 X* O- w  r" y$ ?
  116.    /**比较两个 hash 值,是不是相似   , }% q# f9 t0 v% ]0 L- Y
  117.     * @param string $aHash A图片的 hash 值   
    0 C5 r! n, L! d  Q  W
  118.     * @param string $bHash B图片的 hash 值   0 I+ M9 u. S" Q: {  {& }2 p
  119.     * @return bool 当图片相似则传递 true,否则是 false   ! L, ~: ~$ P5 {& q
  120.     * */    1 \% _1 `( _0 h  t8 U# d
  121.    public static function isHashSimilar($aHash, $bHash){    $ Q  W& _: f0 w
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    : _# q, v6 ~$ N
  123.        if ($aL !== $bL){ return false; }    / F6 n0 L; M. k3 x* u7 m
  124.     % P* Y1 m8 K; R* i! |
  125.        /*计算容许落差的数量*/   
    & d1 {  @  V4 F" D
  126.        $allowGap = $aL*(100-self::$similarity)/100;      V+ f+ U# `3 k8 y$ J+ y
  127.     - x3 x* J; B2 N1 f2 Y& Z
  128.        /*计算两个 hash 值的汉明距离*/    3 k! Y: k6 c% _9 |# [7 l
  129.        $distance = 0;    7 r, l9 z5 f2 f; n1 }$ `1 w
  130.        for($i=0; $i<$aL; $i++){   
    2 Y- e! D- {$ R' P+ e) O: L
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    ( ^  h/ }! C* i4 y. ~8 ]) ~: s
  132.        }   
    6 r4 ?: J, k: V! A/ f" k
  133.     + I; k0 s8 [9 U( l
  134.        return ($distance<=$allowGap) ? true : false;   
    ; u3 f" T, x2 J& z4 V/ K
  135.    }    7 |' I$ g7 B3 @& f" b
  136.     5 W0 A$ Y. G7 a1 r( M0 U
  137.     7 R# J- t2 B8 _6 U/ v
  138.    /**比较两个图片文件,是不是相似   . {0 N+ q9 t6 }. I( g% g
  139.     * @param string $aHash A图片的路径   
    ' l$ n% _* H4 u& ]2 w
  140.     * @param string $bHash B图片的路径   
    4 f) ^" N6 s* G3 X  |
  141.     * @return bool 当图片相似则传递 true,否则是 false   # @0 `6 y" o9 J5 n- S. ^, `" {
  142.     * */   
    / P9 A2 \' z5 a) e. B# E+ U5 P! R  ]
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    4 k( k: O  }5 q# \# W! w' n
  144.        $aHash = ImageHash::hashImageFile($aPath);      e# ~0 u5 R* v( R4 T5 S
  145.        $bHash = ImageHash::hashImageFile($bPath);    ' O, v" T# ]+ Q& \/ q1 H7 H( j- D
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    8 A! K# i0 z+ m* }4 a% ]
  147.    }    " p  [* S* D" G* ]# j
  148.    
    ) l, h) L7 _& v  r' H1 _
  149. }
    - ~6 U* D0 S! c5 u0 x; H" K% B7 s
复制代码
  P5 u+ I$ `0 I' j7 A
5 ?4 H4 x1 B9 s# a; X+ o/ |* i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:52 , Processed in 0.081386 second(s), 19 queries .

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