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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图% o, |. K0 v% M+ f! ^) c6 J
( y1 r& w' O* m1 {. P
' v) z% v; P# @% [. Z
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

. t9 E% k1 _7 q2 x5 J
  1. <?php    # P" j) g: f! [2 S" |
  2. /**   
    : b0 c2 M& w6 u4 P2 l- H
  3. * 图片相似度比较   
      `1 ]! v3 J* S4 s) M! [
  4. *   
    9 \" \) m* ?1 k" r% h+ e" m
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ' L# W- C9 Q/ `  s  \# W. n
  6. * @author      jax.hu   
    6 s: g" {& @$ M* R& m( ]
  7. *   
    / [. c. }* t7 ~  N
  8. * <code>   
    3 n1 x" b2 V* M6 C. d
  9. *  //Sample_1   
    - b# a/ P- S9 K* Z7 D' l: f
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    $ l. w' Z6 C3 M1 G7 k6 R4 G8 o, F
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   + Q; }1 x4 x+ ]- c5 T. B8 m( A
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ; U- Q, x1 G$ k
  13. *   0 \2 b/ Y  J1 t; i. F
  14. *  //Sample_2   - g% G  q2 \) \$ ?5 h4 `0 P
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   $ O! r+ i9 Y1 e* O% I6 g. E# X9 z  i
  16. * </code>   2 H) b. j  x# x: [: y/ h; H
  17. */   
    9 z' q) L# T1 B; A$ R2 _
  18.     2 t1 v0 @9 k0 E% {: h
  19. class ImageHash {   
    7 \: x( i& N4 K& ~' ?) t
  20.    
    , E. p0 i% C) k- b1 k0 W) Q, g
  21.    /**取样倍率 1~10   
    5 r1 E7 B) N& K+ Y1 h: }, ~2 C
  22.     * @access public   : U+ ]% D; L/ W& f: U
  23.     * @staticvar int   
    ; P$ d$ S2 n! o2 H
  24.     * */    : l: |6 z' v1 P8 v3 K, o2 U6 b
  25.    public static $rate = 2;    + y8 J, {. P) e- H
  26.    
      t; p1 q. D, t5 v
  27.    /**相似度允许值 0~64   
    # F, N% j1 ?- z
  28.     * @access public   % P2 d/ |" k- g+ N6 ?+ J  @, k
  29.     * @staticvar int   
    8 `( L; r$ {8 S( i+ g3 y& {0 D) a
  30.     * */    - _! O6 H  Z- N+ i
  31.    public static $similarity = 80;   
    + o4 W. Y# D6 f" W
  32.     $ D' Z. G' H1 V/ {5 O
  33.    /**图片类型对应的开启函数   
    ) M9 n5 r/ y9 S3 u1 X5 @
  34.     * @access private   & Y* p8 v& W+ x0 g0 P
  35.     * @staticvar string   
    8 M( x  Y1 O/ |
  36.     * */    $ ^/ j4 F2 r# N. r& \
  37.    private static $_createFunc = array(    7 @9 g+ J6 O1 I2 i6 o+ g7 k& f/ u
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    7 W8 ]0 l# V/ i( {! T
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    8 T0 M5 a  F3 t& M  A
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    * t1 y! a( P* E
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    . l% f5 \. h1 F  ]* g1 \; t
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    0 g8 v/ I/ G& k! e
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    5 F: p5 I6 i" {; M3 ?/ a
  44.    );    ; V$ s5 \4 B3 ^) g$ R, y$ n
  45.     : T  N; N$ z; h. u% w' F1 `
  46.     4 g( h" d/ }! b/ b( f; s; j
  47.    /**从文件建立图片   ! S) |3 V: R8 f" N8 H  {. o) r
  48.     * @param string $filePath 文件地址路径   ) `/ R2 P5 Y& }- I
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   . L  I, h" D- O3 y/ m* b+ q' d
  50.     * */   
    1 O3 ]" |4 y, f+ c9 ^' ]0 n! C
  51.    public static function createImage($filePath){    5 j6 G: f) t8 ?$ e2 g* V: H. [
  52.        if(!file_exists($filePath)){ return false; }    6 I+ z# O( U6 F' e
  53.     ! f1 ?4 A: n! L% A6 K
  54.        /*判断文件类型是否可以开启*/    " H) N6 c" {# I: D
  55.        $type = exif_imagetype($filePath);    8 v$ |+ S) v2 w1 u3 Z  a
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    3 X6 v* Z( }# R+ ~3 Y3 u+ ], D
  57.    
    $ e' v) m+ I! I5 B
  58.        $func = self::$_createFunc[$type];    ( `/ M% m9 W# L4 |3 N
  59.        if(!function_exists($func)){ return false; }    . v# C5 K, i+ h$ r& g1 b  L7 I
  60.    
    + ^  Z  v, @/ V+ Y# |0 Y
  61.        return $func($filePath);   
    3 y+ W1 L, T: a3 T8 Z. C) b) ]
  62.    }   
    6 V, }, M4 [0 v) V
  63.     * |1 T5 z' t" q7 }4 b6 W5 E
  64.    
    ; ]; O0 p& `. ^3 c
  65.    /**hash 图片   
    5 `; a! _1 U3 e9 g6 N  m
  66.     * @param resource $src 图片 resource ID   
    4 O& E! C) Q" o1 h. {* Y
  67.     * @return string 图片 hash 值,失败则是 false   ! r( v4 z2 K& T4 y
  68.     * */    4 \& k4 @, _* f- p& {
  69.    public static function hashImage($src){   
    - T3 A( b5 \2 P3 d
  70.        if(!$src){ return false; }   
    - x2 |7 }4 l& E: n
  71.     % A9 B+ Z+ V, P
  72.        /*缩小图片尺寸*/   
    $ y! ^+ d& j# j) J+ b: {
  73.        $delta = 8 * self::$rate;    + A: j( u( J0 T+ O3 x1 m! }9 ~) H
  74.        $img = imageCreateTrueColor($delta,$delta);    + h. O1 G9 L4 z; p
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    1 |7 y3 k! S6 n! E2 z
  76.    
      ^3 F; J7 K' s
  77.        /*计算图片灰阶值*/    $ L: {* G5 L/ B
  78.        $grayArray = array();   
    1 c8 t1 ?; W8 P: e) M2 }3 m0 O- @7 P
  79.        for ($y=0; $y<$delta; $y++){   
    & i! M! B# Y9 F
  80.            for ($x=0; $x<$delta; $x++){    * d; U; S( {5 a9 R' z( D" V% O
  81.                $rgb = imagecolorat($img,$x,$y);   
    % f$ `$ T% C! U
  82.                $col = imagecolorsforindex($img, $rgb);    ; m- T7 p7 t' L/ j8 S
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ' C6 p  _& o. Y- n2 g
  84.     ; C; u, p- D/ ?* E; A# B& W; ^" R
  85.                $grayArray[] = $gray;   
    - y2 |9 g: T3 S6 O4 u; C
  86.            }    # A+ i: O/ S9 X$ U( A. N5 b
  87.        }   
    - b( U, J! F, A  F* P6 I
  88.        imagedestroy($img);    / M, ]6 U9 R1 N; C2 |
  89.    
    8 s! X9 W# X8 V; I
  90.        /*计算所有像素的灰阶平均值*/      |% T0 e; S4 [% P  x  E
  91.        $average = array_sum($grayArray)/count($grayArray);   
    0 {, j# l% P# p# c
  92.    
    ( n7 d3 P& @% v) W, i+ G
  93.        /*计算 hash 值*/   
    ) I6 R' ^+ I" F9 Y% F
  94.        $hashStr = '';    6 W0 j! ~! M3 w, o8 Y2 X
  95.        foreach ($grayArray as $gray){   
    + I) C- l% @# ^" w0 H3 {
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    3 w- L, m+ x' n# [
  97.        }   
    % b% Z6 B+ q6 I& q
  98.     ; y. Q; u+ Y% n1 P' K
  99.        return $hashStr;    + l7 v$ k7 ~  {4 r2 ^6 n
  100.    }   
    % q5 T. h/ {9 P' M. n6 r: l
  101.     1 G6 L  Y9 J# K; `) \3 c% V
  102.     3 R$ r% k( m) K2 y
  103.    /**hash 图片文件   6 }) V7 d* d% d8 i" Z
  104.     * @param string $filePath 文件地址路径     b+ W4 j9 O/ T2 H: A' N0 h; Y! _
  105.     * @return string 图片 hash 值,失败则是 false   7 \- K/ l: v) Q1 m
  106.     * */   
    6 T( ^* p1 P5 N7 o; n
  107.    public static function hashImageFile($filePath){    3 D6 ~  E& w; G4 ~* A* u
  108.        $src = self::createImage($filePath);   
    # c) O% J/ C5 u2 F, ~6 W
  109.        $hashStr = self::hashImage($src);    : X* g% u! {( _$ P( E
  110.        imagedestroy($src);    3 H/ W( \7 a" R8 _
  111.     " S& I& C+ }+ p) X6 {% q
  112.        return $hashStr;   
    9 n5 S6 \" E' c  A
  113.    }    ' ^! F5 B; b( y; U- r  d
  114.    
    2 y9 U' W, P6 N6 L( ^" P
  115.    
    7 D7 @7 k6 z" d3 e# u
  116.    /**比较两个 hash 值,是不是相似   
    ! U$ I. @  S% }6 a/ |1 N7 S# b( N
  117.     * @param string $aHash A图片的 hash 值   $ Y/ _( M) {3 v: h; T' d) X
  118.     * @param string $bHash B图片的 hash 值   4 ?5 \  H+ ?, i: A& j
  119.     * @return bool 当图片相似则传递 true,否则是 false   " ~/ ~# G- _, t
  120.     * */    / J- Z' A2 u/ K- v8 p; M
  121.    public static function isHashSimilar($aHash, $bHash){   
    0 ^; m' F1 `! y3 O: G+ |
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    4 f4 J4 h4 w. @  g) S6 V
  123.        if ($aL !== $bL){ return false; }   
    % F. [+ l7 {  w- y9 I/ D& d
  124.     8 h8 l2 i. S  v/ y
  125.        /*计算容许落差的数量*/    9 j/ c( E% ?% U- F: a
  126.        $allowGap = $aL*(100-self::$similarity)/100;    6 \' }8 X4 F3 |7 \, H% S- P
  127.     / Q8 q( |2 c  M( Q7 T) z: W# ~7 P
  128.        /*计算两个 hash 值的汉明距离*/    , b7 {4 R" t' ^/ e+ J- k
  129.        $distance = 0;    + |+ H8 t" ?! e( Q8 m" {. }& b( i0 j
  130.        for($i=0; $i<$aL; $i++){   
    : O( ?) r  O* z: T7 s( l8 G8 {! ?
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ; j0 S( w% d$ o3 ]  k
  132.        }   
    0 \$ r* N! q3 E5 ?
  133.    
    / x: v: f# l# p: ^# d9 \! }" ?
  134.        return ($distance<=$allowGap) ? true : false;    + C, k9 w" J+ }9 h0 D8 D
  135.    }    & L' M0 |. q8 m4 x& S! s- o2 ^/ y
  136.     % h- q7 E9 g$ `2 y5 V& F- h7 ^
  137.     . N2 [: s/ L( N
  138.    /**比较两个图片文件,是不是相似   
      {* f( C0 d* _8 K) O( @8 R: N* }
  139.     * @param string $aHash A图片的路径   # _8 H1 r  t9 H- n7 j: W4 X% O
  140.     * @param string $bHash B图片的路径   
    6 k9 W6 s5 E) ~5 r
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    1 z" v0 ?1 E* a6 ^
  142.     * */   
      G2 D1 K5 A) F: h. B! {9 H
  143.    public static function isImageFileSimilar($aPath, $bPath){    * x7 f! H* }, p
  144.        $aHash = ImageHash::hashImageFile($aPath);    . {0 Q7 z! z& }; _2 O, h( l
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    3 f$ W/ H. [) q; i, ^3 |
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    7 I& E+ h2 \; j5 k
  147.    }    1 @" l1 A7 L1 ~- Z8 c
  148.    
    0 t% _: q7 @* h# b  L
  149. }
    9 h$ k6 w+ r# @3 A: G
复制代码

6 W- g, x" v- d  a- @0 J8 L8 |4 O' v) R; Z6 |8 Q6 }6 l
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-19 15:53 , Processed in 0.056910 second(s), 20 queries .

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