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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

: c) B7 a9 z1 O9 w( b- X由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

% R: J0 I8 M  Z$ x: P
  1. <?php    . y6 p; o0 L( D1 O1 r4 p
  2. /**   . H( k7 w0 w3 w4 c' l
  3. * 图片相似度比较   
    " W( W: E( R5 G( D
  4. *   
    , Q7 {# J$ m% s
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ) E# a( C5 O% f. j2 L. k1 D
  6. * @author      jax.hu   * |( |+ b7 I* i
  7. *   
    0 o: }  ~! [9 i
  8. * <code>   
    ) t* ~% m/ C( y4 |$ b
  9. *  //Sample_1   
    5 h. P8 Q: e! v+ |4 D- o
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   ) f/ J% Z( g4 P0 V# r6 R
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    , A% g2 @% P  A+ @6 O
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   $ ^0 M+ l5 _% U- u3 V  K
  13. *   
    " j# f: b' ?- D6 y
  14. *  //Sample_2   8 t) p3 z' Z# Y4 {5 S
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    . ?5 j. ^' Y: N( _3 _
  16. * </code>   3 m. d5 M8 Z2 k) `* h+ y' e) I
  17. */   
    # z3 X" O4 [. V# k- s2 \8 z2 L
  18.     " o/ O5 G' V  j: H9 K, F
  19. class ImageHash {    ' Q: Q9 y- g+ a, U- M  d( h
  20.     + V# b. Q. s, w6 e
  21.    /**取样倍率 1~10   * X, h2 ]. z$ S' B- g' y( W& v
  22.     * @access public     _0 p# h: Q, D0 G
  23.     * @staticvar int   ) M3 y, ~! j, X
  24.     * */   
    3 E% i& H  m/ T7 R
  25.    public static $rate = 2;   
    % Z, j1 `9 [+ j: g7 F
  26.    
    7 t9 u* ?. x" @" W4 w
  27.    /**相似度允许值 0~64   1 s0 N7 l2 {$ L4 P  f
  28.     * @access public   5 E2 Z! |  z+ G" G. @/ ?
  29.     * @staticvar int   
    ' |, H. N6 [7 D2 n- E( G1 b
  30.     * */   
    # T# P- w' C1 ]; B
  31.    public static $similarity = 80;    # B" O! l+ g, v
  32.     ' Z, l' g9 J- o1 ~( u* U
  33.    /**图片类型对应的开启函数   $ a. m9 }7 ?+ L% ~% f
  34.     * @access private   
    2 F# G, d4 f% j+ ^: {
  35.     * @staticvar string   
    & ?8 b8 w* ^! H2 N# K1 p* g
  36.     * */    " i; M% h! T% [& R4 S; D) }
  37.    private static $_createFunc = array(    0 k+ |0 d, n2 H+ R  `( g
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    0 O) P3 d* l( P! U+ t8 S" i( _
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ' I+ W" }2 [0 C# {
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    * H; A% I% T2 b/ q; ~
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ( e& X9 m; \* L9 U1 v+ q, a
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    - E/ o6 _) Y/ ?: d3 F( ^) P
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    # M. s7 J* q; ?1 Z
  44.    );   
    6 D1 f' B4 f9 p( A5 L+ V/ Q
  45.     - ^4 y4 |5 b4 O. |4 A* ]: y0 n0 @* Q# m
  46.    
    5 g& d# Q- B, b0 m' _1 \: w9 m
  47.    /**从文件建立图片   + |9 T- A/ \8 y/ Q2 ~
  48.     * @param string $filePath 文件地址路径   / L  ]( x9 Y9 q& A
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   6 o& t5 `, n* g8 W
  50.     * */    0 P5 ^+ p% A$ N
  51.    public static function createImage($filePath){    6 }* e+ A/ h% Q9 ^# c
  52.        if(!file_exists($filePath)){ return false; }   
    4 j) B8 w8 g3 |
  53.     " G9 y7 ?  w( H' X/ S, W
  54.        /*判断文件类型是否可以开启*/   
    . x4 e( b3 W/ G* m% G% y5 `, `
  55.        $type = exif_imagetype($filePath);   
    6 c* |* g4 ^# e" \
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    , I7 S1 n' U3 [" Y9 t* A
  57.     # ]5 S7 a, \9 P$ Q
  58.        $func = self::$_createFunc[$type];    8 @. v( o# G  N' i
  59.        if(!function_exists($func)){ return false; }    9 i7 ]" u* x$ G
  60.     1 G" M- E6 ]4 ]( m: h- F
  61.        return $func($filePath);   
    ( M$ B' |) ~, [0 M/ R
  62.    }   
    # h8 E, F; O6 u$ ?! T- Y- I
  63.    
    " G8 b3 J, k  d
  64.     8 }4 y& P0 }. p1 Y1 M# H
  65.    /**hash 图片   
    6 L7 m9 D/ k+ K& Z3 Z
  66.     * @param resource $src 图片 resource ID   , |7 R/ [" ?! \+ A- g* }6 Q: t
  67.     * @return string 图片 hash 值,失败则是 false   
    ; R( U; ?$ `0 r* G9 z+ N
  68.     * */    6 q! g- U% h  f2 x$ q4 U
  69.    public static function hashImage($src){   
    5 x+ B% M! x4 u" }
  70.        if(!$src){ return false; }    % _. Z* v; E  L* }5 p" G, _; f
  71.    
    * ~) v* y7 W6 J8 l! v
  72.        /*缩小图片尺寸*/    3 W; q$ X& ~3 c/ [4 Y2 H% j
  73.        $delta = 8 * self::$rate;    & _2 j" A, ]% D) v$ L1 W
  74.        $img = imageCreateTrueColor($delta,$delta);   
    . ^) P' A) Z* V
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    : E" S0 N7 s8 {- B* y
  76.     ' Y% v: S- h$ A: s9 k$ {7 l7 e
  77.        /*计算图片灰阶值*/   
    ; _, S0 @9 e& w5 ^) a
  78.        $grayArray = array();    3 t  n( H4 K4 R' H7 e4 S7 _  e
  79.        for ($y=0; $y<$delta; $y++){    + n* F6 R! k8 i) ~: k8 x
  80.            for ($x=0; $x<$delta; $x++){    7 {& {- h' i3 u' p% w
  81.                $rgb = imagecolorat($img,$x,$y);    8 o0 o1 g3 Y: ]( T/ z! s
  82.                $col = imagecolorsforindex($img, $rgb);    2 C  Z; c& i5 }; d4 {# Q
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    1 v# e3 k( w0 u  M/ J
  84.     / L/ M0 A' k# M1 R+ i
  85.                $grayArray[] = $gray;    1 y% C7 M& T! U/ {
  86.            }   
    8 c( v0 b/ n3 c1 P( @$ }
  87.        }   
    9 M6 P' I! ]: t7 V
  88.        imagedestroy($img);   
    7 X8 o* o6 F2 e% _3 A: h) Y
  89.    
    - D; D  {% c2 i( n: P  M" x# V
  90.        /*计算所有像素的灰阶平均值*/   
      u( q8 ~9 k3 ^9 C4 @
  91.        $average = array_sum($grayArray)/count($grayArray);   
    $ v! u4 g8 s5 @( P
  92.     ) v1 D# |; _- g5 B0 `
  93.        /*计算 hash 值*/    ; c2 ~: |; }3 \6 M, U; W
  94.        $hashStr = '';    4 Y* U: @) z( U$ C, z
  95.        foreach ($grayArray as $gray){   
    + M6 O* S+ Z4 M) S7 u" u! n
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    $ i3 r, R, z, w" y7 p. O
  97.        }   
    0 g8 p- X9 s$ n5 J- S
  98.    
    / F' B  @) {' t! C
  99.        return $hashStr;   
    ' s& `, C1 u" Z& M
  100.    }    ! [9 X2 x, @/ x+ V
  101.     4 {; a! T1 J- K
  102.    
    7 X5 N% ^$ n. c4 }
  103.    /**hash 图片文件   ! L1 ~- U2 ?. _4 Q) z! v/ o
  104.     * @param string $filePath 文件地址路径   ! `6 m, ]3 r* W5 i# N4 `
  105.     * @return string 图片 hash 值,失败则是 false   " a2 s2 z* ^* W$ c
  106.     * */    ! ]2 c$ k9 u, d, J2 @
  107.    public static function hashImageFile($filePath){    - j0 q0 E0 o( I; }6 W, X# \- @; p
  108.        $src = self::createImage($filePath);   
    1 V7 d  |+ g9 a9 }; {
  109.        $hashStr = self::hashImage($src);    0 @3 q" w% k( I$ t" G( p! v+ q
  110.        imagedestroy($src);   
    , o9 F0 p$ n! K& w: d/ q! Q' k
  111.    
    4 t$ Q5 }% p+ l' q4 |% D
  112.        return $hashStr;   
    6 W5 A$ B) ^4 Z& F" N, x) N9 c: f6 K
  113.    }   
    , [$ y, L' O$ ^# u+ w
  114.    
    - m' o4 x4 ?' ~% z' S
  115.     7 M# m8 C4 s) K9 x
  116.    /**比较两个 hash 值,是不是相似   
    # A- F3 o# W2 l2 s0 T, v  \' J
  117.     * @param string $aHash A图片的 hash 值   - i8 X7 H7 ~2 G
  118.     * @param string $bHash B图片的 hash 值   7 e  ?: E# Y% U0 X% Z& E) l# b
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ; f: A8 L/ N# @( g. {- ~0 F7 n
  120.     * */   
    7 t: Y# E9 v: U  K
  121.    public static function isHashSimilar($aHash, $bHash){   
    4 b2 x. R. v% @' f- U! ]7 R
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    3 x9 T7 B  i, k" F: |
  123.        if ($aL !== $bL){ return false; }    9 z9 Z. q/ i; P0 K) }) X! l4 _
  124.     ) W5 @0 ~$ e& R0 ^
  125.        /*计算容许落差的数量*/    3 ~, O; d1 F, M% `, @2 M7 ~) Y
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    & k4 S; O2 F" v
  127.     + B$ G- `' Q- I
  128.        /*计算两个 hash 值的汉明距离*/    8 {0 ^* Y4 z0 ~1 h& E0 r
  129.        $distance = 0;    ; G' L: E1 n& ]2 N
  130.        for($i=0; $i<$aL; $i++){   
    3 Q2 o! i" y7 o9 Q4 `5 X  O! m
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    , a* }; v6 i# r, P9 E1 }
  132.        }   
    ; R8 u5 T+ D3 S5 n5 o: e
  133.    
    8 t* J; K# e. a* k
  134.        return ($distance<=$allowGap) ? true : false;   
    4 R9 Q4 u, v8 i( F8 ?) ?
  135.    }   
    . N8 O! ]- _2 I
  136.     ' p. K( J8 A: j
  137.     . H# e' ?7 x; t
  138.    /**比较两个图片文件,是不是相似   
    . U0 t$ d5 f8 N( Y
  139.     * @param string $aHash A图片的路径   
    $ n" t2 d# U. M  u2 k9 X
  140.     * @param string $bHash B图片的路径   ; d; F+ I4 e' r% W" c5 U3 C6 r
  141.     * @return bool 当图片相似则传递 true,否则是 false   + J& ?5 P- Y( N$ n  i
  142.     * */    8 v  z! [& j% f4 X0 e! u$ g
  143.    public static function isImageFileSimilar($aPath, $bPath){    - ]/ j9 }* S* e0 K7 n+ [
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    , R% r% C. [6 q+ t4 U7 e% l
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    & t# }0 a1 {6 ~& Q4 a
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    + R4 W1 j1 T, Y$ e0 l
  147.    }   
    , X" B8 y* X# L+ Q# j0 O" d- N6 `
  148.    
    $ F. |1 }- ?, {- B
  149. }) O$ O9 _) U! q
复制代码
% w9 F  T, V& u5 U

# _5 T( w' s- P( p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-21 10:33 , Processed in 0.059704 second(s), 19 queries .

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