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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图0 m1 O. f: D$ u) M( s9 a3 l9 X
' p* s4 ^/ P4 M5 a: X( O6 U; f
1 {; I0 g5 W. U  }7 t- o
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
; [% ^' T/ A4 R* p' K
  1. <?php   
    # L* C; N- ]7 p8 s/ G+ l
  2. /**   , \& p/ s, G9 H- f9 }0 y
  3. * 图片相似度比较   5 f; K% N* j3 Y. f4 \
  4. *   
    1 @; ?$ \: O3 a; Y4 K8 z- P
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  $ A. n0 I! i* E4 R
  6. * @author      jax.hu   1 \: p( s- K# f
  7. *   
    6 p, w% {# N6 c7 ~* g6 |
  8. * <code>   
    - f, ^/ d# K  ?$ P( s
  9. *  //Sample_1   
    6 h* Y1 H+ w1 L' R0 X7 c# _
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   0 p! a% }% e8 X0 Z+ \$ j
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    / s1 X% E  G! {
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   % ~; U& s# X1 i5 _7 }$ B7 K
  13. *   
    * K! L6 [, g# _; S3 Y/ D5 H
  14. *  //Sample_2   ( l9 V8 R' d! _1 O3 G
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   & C) L1 r! O0 {" }+ F9 m0 V2 N
  16. * </code>   & T' |) D; v8 y' r( q/ H7 i) o
  17. */    ' m3 e5 R8 ~) g# f# A: z6 u0 h' G* N
  18.    
    ; _9 J; F+ D6 h$ }- }4 K. U( w
  19. class ImageHash {   
    - y. M/ K  M* f" B; C
  20.     & [7 A! ^: F" ]3 f- S: D
  21.    /**取样倍率 1~10   
    ! a9 s8 t  T) `. n# F+ l5 v" r
  22.     * @access public   + U  D/ _9 e) x9 T! U
  23.     * @staticvar int   % l" e! t+ H' T" C% y
  24.     * */   
    # ^" y6 u: v+ Q$ r( a
  25.    public static $rate = 2;   
    ! Y* z, }# R* O+ }7 {
  26.     & G9 b4 B6 a" n* q. U7 x) M
  27.    /**相似度允许值 0~64   
    ; i- l% D! T# }# @
  28.     * @access public   7 ~/ L* ~+ r2 }" b/ w5 V
  29.     * @staticvar int   
    8 y' U/ l2 m# f' D1 e
  30.     * */    ! F: O) y! E2 e5 _4 f# o9 ~5 m
  31.    public static $similarity = 80;    & l, h' [& V' O
  32.    
    ( b9 e0 ~6 o& Q0 O% `/ t; g
  33.    /**图片类型对应的开启函数   ( Q* P( W* _* w, i& e! |4 n# k
  34.     * @access private   0 ~% W) L2 V5 v5 R% \/ {
  35.     * @staticvar string   0 a& l9 E0 _. i# S# `0 c1 E
  36.     * */   
    8 `; W' D/ r) Q3 x
  37.    private static $_createFunc = array(    4 G0 t: {  j( p$ P  k9 f1 Z
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    $ F8 @! o9 ~1 V0 y5 }5 `
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ; n1 `( n2 D: R/ U( u: U0 ~- u
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    ( s; p0 i/ G1 ^
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    & z) J" d6 Y- {0 w) |% W" Q3 ?
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    & m. q' _8 U5 u* t4 b
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    . B' M0 ?7 M$ }; I
  44.    );    8 o5 ^2 Q% [0 B, a* Z% h
  45.    
    & N/ G6 f, A0 @4 B
  46.     % d. e+ s# u" ~  {/ E3 [" a$ k- Y
  47.    /**从文件建立图片   
    5 ]) N1 u$ [2 U2 R7 _
  48.     * @param string $filePath 文件地址路径   9 e  W/ p% A; [! o' F; Y3 I4 C
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    + H# F1 I* R6 Z) {
  50.     * */    0 u2 K  X3 Y0 e; k4 A3 m" ^  ?
  51.    public static function createImage($filePath){   
    ) ^/ V2 t- O( p0 V1 L
  52.        if(!file_exists($filePath)){ return false; }    6 q7 ^5 b7 J9 x  J
  53.     / y" M# |+ I+ N8 ~
  54.        /*判断文件类型是否可以开启*/   
    8 w1 }0 F) A+ @/ v
  55.        $type = exif_imagetype($filePath);   
    ' c" a/ [  S* k4 i! U8 z
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    + }, M& {! ^3 z6 r% u2 N
  57.     ( X, r0 ]7 P" s+ ]% m3 |. Z  o  V# t
  58.        $func = self::$_createFunc[$type];    # r8 h  }* s% Q6 A+ m; N
  59.        if(!function_exists($func)){ return false; }   
    ) U7 [- K; {8 N" O5 M8 d! q1 L% U; l
  60.     ) ?% M. P! H8 k$ ]
  61.        return $func($filePath);   
    ) |$ c: u/ M0 h$ b3 [
  62.    }   
    . ^) r6 j. z6 @7 l; o" f0 j) Z$ e
  63.    
    8 Q$ x0 n; _% i# k+ x
  64.    
    $ p7 d; Y4 N" i8 D, s& |
  65.    /**hash 图片   $ ?7 X# J3 v' M7 ?1 m% d- p
  66.     * @param resource $src 图片 resource ID   
    - e9 W- Q6 U# z0 T' h
  67.     * @return string 图片 hash 值,失败则是 false   4 F( u0 v- f2 W" E
  68.     * */    " ]2 h- g/ }( F3 G6 p, N( z5 \/ \) K
  69.    public static function hashImage($src){   
    $ M1 Y8 F1 n* e, r2 P3 t; Y
  70.        if(!$src){ return false; }   
    : S0 a) L% t6 c0 {: q
  71.    
    " R3 F6 ~4 `5 o$ W, z7 w
  72.        /*缩小图片尺寸*/    * F0 Y/ N' L+ o+ @0 o
  73.        $delta = 8 * self::$rate;    4 G) v& j  Q& _+ e8 r. @
  74.        $img = imageCreateTrueColor($delta,$delta);    * h& C) X$ L& E
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
      T: g& s- s1 U2 P+ Z
  76.       w" P" b' g& F7 P' f) t/ f
  77.        /*计算图片灰阶值*/   
    6 O' P$ K8 y( ]
  78.        $grayArray = array();    ' q: U; H& i$ {3 M# d* N
  79.        for ($y=0; $y<$delta; $y++){   
    4 }4 S, X+ e0 a; w1 _6 b8 D$ H
  80.            for ($x=0; $x<$delta; $x++){   
    ) b4 h( k( Z! d# s. Y' A4 j
  81.                $rgb = imagecolorat($img,$x,$y);   
    7 H, m" o- }* k  [; c2 f
  82.                $col = imagecolorsforindex($img, $rgb);    , u# c/ v1 w! b, M. `( J4 x. v4 P
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    5 N: C' D3 H  s8 m) e+ T, p8 [: Y
  84.     7 T1 H3 ], [5 Z
  85.                $grayArray[] = $gray;   
      w( g( W4 X; _4 M$ Q# f
  86.            }   
    % Q$ z+ o, V$ ~- u* \& [. l
  87.        }   
      W- Q3 y$ N1 [- P& ^* P
  88.        imagedestroy($img);    ' L" Z$ g& }9 I6 G- k
  89.     " n$ P& g- {) ^' H3 [- P+ s
  90.        /*计算所有像素的灰阶平均值*/   
    : w; e+ b) d7 ?! B* ~3 ~3 g
  91.        $average = array_sum($grayArray)/count($grayArray);    % `! X, K9 _+ t# d
  92.    
    , R0 \% {8 K  H% O$ Y  u' E
  93.        /*计算 hash 值*/   
    ( M& [3 Z% Y1 k2 R+ J
  94.        $hashStr = '';   
    2 ~( m, ~4 w- Z! G4 g/ Z
  95.        foreach ($grayArray as $gray){   
    ; }& F, x* e7 k$ @/ X0 r
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    / C+ }9 M% z$ E/ u/ Y
  97.        }   
    9 v! B9 c3 o6 a: f
  98.    
    % \% H1 @, g* H* r* b
  99.        return $hashStr;    8 s7 ?6 V. |, K' p1 a
  100.    }    ( P4 j  N+ O1 H) o9 j6 F4 k- |0 |8 t
  101.    
    ! Z) I- w+ O5 `6 x0 d
  102.     & g3 [0 _. L1 S' b1 i
  103.    /**hash 图片文件   ' e# B) A' R$ d; o
  104.     * @param string $filePath 文件地址路径   
    : e3 e) ~/ v5 L. _
  105.     * @return string 图片 hash 值,失败则是 false   & T" P. M- T* v3 _, h- ^
  106.     * */    + O$ E3 v: |, T( l- s+ Q
  107.    public static function hashImageFile($filePath){   
    ' z# F9 A/ u& z4 @* Z$ I
  108.        $src = self::createImage($filePath);    " l  \1 P' ?" S  @1 p
  109.        $hashStr = self::hashImage($src);    + S; m9 b7 n8 l3 H+ }2 b6 o5 }
  110.        imagedestroy($src);   
    8 i! s" z' a" L% U
  111.    
    , }. O" l8 o5 i2 B
  112.        return $hashStr;    + ], `6 J4 X: t$ I  Y% e4 r
  113.    }    + ~; {) f: x+ K& T3 D% P+ r
  114.     " O7 q- X9 B5 }2 i0 G6 b+ S! C( n
  115.    
    8 y" g/ \3 b- X1 |
  116.    /**比较两个 hash 值,是不是相似   ; f% [1 e. d  i! ~2 X$ w' o
  117.     * @param string $aHash A图片的 hash 值   4 |$ v- Z! o. F4 E
  118.     * @param string $bHash B图片的 hash 值   
    3 g0 @- U! u6 E" H
  119.     * @return bool 当图片相似则传递 true,否则是 false   ; s2 ~8 f! k: I) C
  120.     * */   
    0 v7 ~, T# v0 J+ ?
  121.    public static function isHashSimilar($aHash, $bHash){    ! }/ M) f! c# ~; [+ q
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    3 t  Y: \- [  O
  123.        if ($aL !== $bL){ return false; }   
    ' k3 P2 v- u' \$ k: p
  124.    
      @/ H) ~! g; w0 g
  125.        /*计算容许落差的数量*/    5 f5 O5 i/ z2 P& e) t
  126.        $allowGap = $aL*(100-self::$similarity)/100;    3 f# F3 q. `: r. V" x7 r5 F8 |' m
  127.     9 r: s7 d9 d" k. W! |
  128.        /*计算两个 hash 值的汉明距离*/    0 k7 S3 O/ p9 N  P0 F/ g* \( R
  129.        $distance = 0;   
    # g4 G, i# ~# A; D- C
  130.        for($i=0; $i<$aL; $i++){    ( w, A* E1 s, w7 i; X- b) w
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    5 U& |+ f- F/ m" X* @, f, v9 z
  132.        }    % y1 }9 o( u% u: W  W. v
  133.    
    6 g2 `' p) |) F+ N9 q4 m
  134.        return ($distance<=$allowGap) ? true : false;   
    1 m% ~+ W. C2 ~/ Y% G
  135.    }   
    8 B9 [! O, v- h; q
  136.    
    0 ~+ X  A8 k) ~: Z* S) _$ y. r5 h$ E
  137.    
    " ^) H" q5 Z0 e9 V, ^2 W
  138.    /**比较两个图片文件,是不是相似   + C! q. q1 g" G* ]0 z8 {$ P
  139.     * @param string $aHash A图片的路径   
    ( t. i' ]( Q! {4 b* p
  140.     * @param string $bHash B图片的路径   
    ' o$ _4 ?5 E9 G$ S7 X
  141.     * @return bool 当图片相似则传递 true,否则是 false   8 }0 g6 w4 V) {
  142.     * */    1 z  J& ]5 @- P5 `' o. u: Y( ^8 ~
  143.    public static function isImageFileSimilar($aPath, $bPath){    ' K) p, e* k0 P( U. c
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    ) s: H  I% O+ N% `' Y9 `% b
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    , A+ Q& r7 H) M* p: m
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    9 R# s6 f1 t8 x# S* H: B9 [
  147.    }   
    : t# ?! c# s* s
  148.    
    , K9 h! z! f% f! w* B' F
  149. }/ u* |1 {5 r$ T* y& Y: M1 c
复制代码

- T& ~! @/ t6 w# j9 }6 G- G" t6 ?9 D4 e) j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-1 00:28 , Processed in 0.069617 second(s), 19 queries .

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