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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

- u  i' r& b1 w

4 X6 I- G/ g' O; }由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
, m5 y9 p, i$ j$ e( }
  1. <?php   
    ) K# C+ y. }3 J% f
  2. /**   : I. t/ @4 H. F
  3. * 图片相似度比较   & E2 |+ Z  Y/ a
  4. *   
    ( [4 y6 c( h5 L0 p: R, n; {& g7 j
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  + P9 G1 y& a+ r4 j/ S
  6. * @author      jax.hu   
    ! B9 e" w, z" }$ \* {5 S
  7. *   0 C  ]# ?, J$ j1 ?3 P" u
  8. * <code>   1 ~# U6 p8 [- O$ }5 o- E1 B' u
  9. *  //Sample_1   5 A1 t9 t( h0 y. J. a, A, w0 Z% j3 \- Q
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   7 t! P% @3 }, M
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   - H7 V7 s% ]; y
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    7 W* D& \1 ]  Z# |9 i( D/ T
  13. *   ) I; F6 h* A% j
  14. *  //Sample_2   / J7 g# _% d, ~" T3 R
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   " Z4 D* o3 `0 S, j
  16. * </code>   # M' o6 A& `9 d4 u! M; p& L0 U
  17. */    4 ]- t9 a) v1 _
  18.     ; u! r9 g! L9 f' n% U) U; f: l7 V
  19. class ImageHash {    ) l+ s6 z: A0 l. A# k  s2 }0 o
  20.     ! |; _% _3 I, [4 l, ~
  21.    /**取样倍率 1~10   
    ; D& `/ s; f; U/ l, M# M! }+ d1 R% Y, \
  22.     * @access public   
    3 e9 p- }/ d+ w7 a
  23.     * @staticvar int   
    # ]+ Z% s; M9 e' u. S
  24.     * */   
    3 @$ G, P5 q+ C7 @
  25.    public static $rate = 2;      i; o3 H5 b' E/ o) l  u
  26.     ' P5 L/ }' K! g& l, e
  27.    /**相似度允许值 0~64   
    - }- M( d# I/ K  X+ Y
  28.     * @access public   4 ~3 O9 n, u, M
  29.     * @staticvar int   9 d; q6 M9 {* s8 F6 ?* T4 i; j: y
  30.     * */   
    * f' Q" R5 r0 ^9 b1 y# N4 ]/ T
  31.    public static $similarity = 80;   
    & A, y8 o- x4 _7 E
  32.    
    . I5 z, B" N; G+ e5 ]6 X
  33.    /**图片类型对应的开启函数     N/ h+ v  j5 g$ e
  34.     * @access private   : P" z* f7 w% d8 |% L# v
  35.     * @staticvar string   / ?2 X! z1 x. `
  36.     * */    ' B# W4 q/ j' E
  37.    private static $_createFunc = array(    1 R/ q. Z5 B  k1 P) G0 }7 F
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    $ t/ D' G- Q4 A& O, J" i
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    . ]: J4 U' H" g
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    7 y. c3 A; O; n) f3 E) v
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    + S1 D  X' T4 `3 z8 h6 k
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    1 X5 f8 j4 T/ T+ J: Z  ~
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    # x+ j9 Z9 l( f$ b4 I
  44.    );   
    / j/ c0 M( E/ Y- i8 F5 ^, V' ?; Q- n
  45.     + O; f4 {9 N9 W: W# m' x9 O
  46.     + q( q5 L# p7 x
  47.    /**从文件建立图片   
    1 C: F; L4 G; L" K
  48.     * @param string $filePath 文件地址路径   
    0 ]! x1 d/ N: r  ?, T8 X( \
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    2 e/ g: P, e) T
  50.     * */   
      x& _: O% c  m) ?/ N5 T0 e: L
  51.    public static function createImage($filePath){   
    / F. a8 M: D+ P: Y" w9 t5 p
  52.        if(!file_exists($filePath)){ return false; }    2 x& L5 I2 N0 g2 t: G; K
  53.    
      ]# W" A9 x5 s- r
  54.        /*判断文件类型是否可以开启*/    0 ^3 l. V( ?6 l
  55.        $type = exif_imagetype($filePath);   
      b* p: x$ q" N  P9 W' w
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    " Y. a7 i7 H7 a" D* g& G
  57.     ! {2 f6 N4 U/ }1 j- Y. a4 A! }
  58.        $func = self::$_createFunc[$type];   
    5 W) ]* s  M8 P8 m! M: Y2 Y5 |
  59.        if(!function_exists($func)){ return false; }   
    ; `' N+ r5 c8 p; P4 r" m5 o$ v
  60.    
    2 K3 w% G# B% z; ~
  61.        return $func($filePath);   
    - Z* s, e5 |6 u9 b" F8 g3 K
  62.    }    ; p8 b# T' r  D. d# U% s
  63.     , p" P: G! n- G5 T8 {
  64.    
    8 w, O+ V" S$ K( E
  65.    /**hash 图片   3 D2 k" w3 D- @0 Y3 l: a- h' F/ K& a
  66.     * @param resource $src 图片 resource ID   
    ) G0 R9 m- x! a
  67.     * @return string 图片 hash 值,失败则是 false   * ~; M) U( H) _- F/ M
  68.     * */   
    - K% V4 I6 h5 v4 b" d
  69.    public static function hashImage($src){   
    . q, s: @0 O/ ?6 H7 i3 @" U
  70.        if(!$src){ return false; }   
    ) I/ ?7 }0 m0 r4 }0 @) \
  71.    
    - U2 s# }4 C) r" z# {6 j8 A- j
  72.        /*缩小图片尺寸*/   
    0 t# c# \/ l9 r! K8 ]- D# z) L& ?% x
  73.        $delta = 8 * self::$rate;    # G  |5 r! H( K% w
  74.        $img = imageCreateTrueColor($delta,$delta);   
    : z9 X1 N. @( b4 z% ?6 W8 p
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ) T  F7 H: W5 f* n
  76.     4 Q9 ~3 M3 v) |! ]; d. D
  77.        /*计算图片灰阶值*/   
    0 @: M( R& S* e4 O
  78.        $grayArray = array();    . e; M* `9 {0 G
  79.        for ($y=0; $y<$delta; $y++){    " V* w& T3 C: d7 b2 I
  80.            for ($x=0; $x<$delta; $x++){    $ S9 \, q4 l8 ^* a# m5 h
  81.                $rgb = imagecolorat($img,$x,$y);    % u1 m4 ]0 G' z+ E
  82.                $col = imagecolorsforindex($img, $rgb);   
    # D" x+ ]: h9 f; E2 O
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    3 K$ c$ J4 A  ?" }6 m% [; q
  84.     * T7 b8 [! |; ~+ i3 ?, g. o
  85.                $grayArray[] = $gray;   
    ' D# s/ U' Z! \; F0 L
  86.            }   
    # O9 }4 U" _. x( I( m
  87.        }    ) i# q: \- ~# a: f. |* {
  88.        imagedestroy($img);    . t+ x. T  p6 _$ h, M
  89.     + w6 [5 L& W; i! h! H
  90.        /*计算所有像素的灰阶平均值*/    : C8 c; ?& v' X* p4 M& D+ e
  91.        $average = array_sum($grayArray)/count($grayArray);    & m& q7 t+ _9 `+ t7 n" G7 M
  92.    
    / T2 i' l  T" j6 _: j6 Q: ?2 }) p- v
  93.        /*计算 hash 值*/   
    , ]+ r3 R. o5 A  E* X- I1 p
  94.        $hashStr = '';   
    / h  y8 O9 l+ U  y2 N
  95.        foreach ($grayArray as $gray){   
    / w# I" O: u1 ]/ A
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    9 b/ _2 Z2 q' m
  97.        }   
    % ^7 `  B4 }. x) Y, i3 u
  98.    
    / V0 g# w" S2 l* Z# e8 i. S% ]
  99.        return $hashStr;    4 O) [8 n$ R$ L: m' l
  100.    }    * ]- n& B$ ?+ {1 L+ \
  101.    
    8 v+ ]' m+ O/ J! Z' i
  102.     # T0 T6 H* G' A1 n- q  X+ s
  103.    /**hash 图片文件   0 C" I( \- m. s# Q2 s' j" W
  104.     * @param string $filePath 文件地址路径   5 b9 c# a4 v! c% t7 d
  105.     * @return string 图片 hash 值,失败则是 false   
    4 q7 e) Y  O* k4 ^
  106.     * */   
    / J. u& _9 r/ |4 D
  107.    public static function hashImageFile($filePath){   
    $ a  q4 d1 a# R" U8 W( q4 Q
  108.        $src = self::createImage($filePath);    # L. _1 x) ^7 C8 D
  109.        $hashStr = self::hashImage($src);    : X& D9 m" x" g+ m
  110.        imagedestroy($src);    . ?( {% Y+ M2 H, c0 e+ j
  111.    
    9 |9 c1 j5 P* U! x. C# n
  112.        return $hashStr;   
    % j5 ^9 Z+ n1 A: V8 o, q+ g( w1 z3 `/ c
  113.    }   
    ' W( y* Y5 U6 G
  114.    
    . n" [5 x9 _+ I3 H
  115.    
    , m; N: |5 \7 S$ B7 K4 _2 ^
  116.    /**比较两个 hash 值,是不是相似   ; c/ U; K2 v8 Y/ R3 @
  117.     * @param string $aHash A图片的 hash 值   ) I+ D2 f( w& [: @4 U% X( p
  118.     * @param string $bHash B图片的 hash 值   
    / j" ]5 r1 e2 d4 M
  119.     * @return bool 当图片相似则传递 true,否则是 false   8 G8 n& v! N! ~3 f
  120.     * */    * h3 P. f  o  ^! U# _, O
  121.    public static function isHashSimilar($aHash, $bHash){    / w# D- `  N. M  M
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    / G6 c7 U& J2 H: W+ |
  123.        if ($aL !== $bL){ return false; }   
    + u, J5 v( ~/ H- X
  124.     ) f. r% d3 O; s/ I; z
  125.        /*计算容许落差的数量*/    4 |* N: i$ J7 j; R* b
  126.        $allowGap = $aL*(100-self::$similarity)/100;    , W; q# H( ?8 C( v& d
  127.     / H: o$ M: M4 J1 N: ?3 i, u
  128.        /*计算两个 hash 值的汉明距离*/   
    9 g- L; N. N* x2 B- D0 u
  129.        $distance = 0;    . E( v* U6 v1 f9 N/ o5 r
  130.        for($i=0; $i<$aL; $i++){   
    / Q7 j, B1 K2 ?) S( q7 P2 F
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    3 t9 a7 `# s( \8 l$ K
  132.        }   
    5 Q( a  t3 ?# I
  133.    
    9 c- a6 c9 T( m! ?
  134.        return ($distance<=$allowGap) ? true : false;    % Y+ q: t. F. C" q
  135.    }    . b2 d) ^) C2 W
  136.    
    . G0 Y4 Z. z9 y0 m5 ]) f$ Z8 c
  137.    
    , {& l  U8 G( ^. ^
  138.    /**比较两个图片文件,是不是相似   4 I: Y' @1 \2 Y6 o
  139.     * @param string $aHash A图片的路径   " d  w" M. c( n# E3 K  G: y
  140.     * @param string $bHash B图片的路径   3 ?5 I) h( l  g/ w. v  q! }
  141.     * @return bool 当图片相似则传递 true,否则是 false   # |7 r1 |& q- w3 d; o; J7 u* t
  142.     * */   
    3 j: }! s$ v8 I2 E7 S& Z/ t% x
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ) Q8 @* j1 u# h$ k- ?
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    " g9 s( z7 X/ ?0 j& Q/ n& f
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    + `3 O5 ^* E, L2 U$ v
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    " C! J! t% X3 w4 _! ]
  147.    }   
    6 b0 D) F% M1 Z6 ~) |: i
  148.    
    " y9 c+ V8 R* y  N$ f' |
  149. }( i0 a! {' a3 P/ B7 G
复制代码

/ i, j+ Q$ D5 A3 O4 \5 g4 i* y& D9 E" o: D/ L# b
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 13:33 , Processed in 0.056926 second(s), 19 queries .

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