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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

& t' u" _3 J( c- \/ }* ^由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
: M5 P& O5 m2 u
  1. <?php    ' g* P% Z7 x1 O, `, g/ S; U7 T
  2. /**     @, o/ d6 F8 x9 `- n
  3. * 图片相似度比较   
      C9 l, ~- ^* b" I, [- x! D% I0 ~  r
  4. *   3 L; J8 {4 a+ Z; u
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  1 e7 i( Y: @) d! [( q
  6. * @author      jax.hu   
    # C: B& H' i& k1 H) {5 i5 t
  7. *   
    / F1 f9 p. T6 S* b
  8. * <code>   
    3 P: Z# V  N- J" O3 i* A$ c
  9. *  //Sample_1   ( H0 t' d. ]# Q. O$ f( D: j
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    $ F8 q* H; c; v4 S3 S
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ! e6 K- m: b5 V& N2 \
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   6 t% b. t1 d. c5 `; \+ |
  13. *   ! c( ^0 x' U3 y& r9 i% a
  14. *  //Sample_2   
    $ i- r3 h/ G- g1 E5 P8 V
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ' @5 c4 Z0 P/ B* H: n
  16. * </code>   
    ) j1 c) c0 Y; O2 b5 W# s4 g
  17. */    2 ^, {! Z; t. d) }- v8 D- P/ ?; v
  18.     2 s7 @+ J+ j( A/ W4 j9 n
  19. class ImageHash {    % \7 P/ K, b! _% ^0 W2 ^( l
  20.     & X& F1 f2 {$ L7 Z( W; o* B
  21.    /**取样倍率 1~10   ) i; f: E7 p7 n; m
  22.     * @access public   ; b! o; X( H8 }' z1 n, I8 y
  23.     * @staticvar int   
    2 ?# E3 k' R' `" F5 ?, U
  24.     * */   
    9 ?: x5 H+ g1 F6 v) ~6 E/ \
  25.    public static $rate = 2;   
    2 B; P" }- k1 Z
  26.     6 V3 e& {" _' A7 F2 X& x) ~% d
  27.    /**相似度允许值 0~64   1 z- d' |* t: `# T' G+ r# ^1 b
  28.     * @access public   
    . h  _* I6 k' ^) e& ]3 M
  29.     * @staticvar int   2 }9 T' ?$ x: z9 p/ R& W
  30.     * */    0 Y: \: f+ k2 T0 x. \: I7 J
  31.    public static $similarity = 80;   
    * Y$ A; Y- _* p: f3 ^
  32.     9 s0 l" Q8 l; f9 U
  33.    /**图片类型对应的开启函数   ' }7 @/ O8 P# ~( c$ Z
  34.     * @access private   
    $ d7 d  n7 E: K, T3 m/ r
  35.     * @staticvar string   
    5 {+ ?; x) L( I6 G/ m( f
  36.     * */    6 q- h, x  }0 n/ p5 S6 A  I
  37.    private static $_createFunc = array(   
    9 E$ G$ Q3 G* m3 ^
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    6 X2 I. h0 u. _! n; B
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    # V9 C4 h" F4 D5 l( t0 `& v5 W
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ! G. w2 y: j4 }/ x' t$ Y
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    2 V7 N0 W" a1 O8 S
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    ( K& y! L0 h  N$ j  \, l. y* V
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    9 N* v0 N2 M" a# m
  44.    );   
    : V8 _* J! @; x
  45.     2 V0 p% Q5 `0 t, h) l
  46.    
    7 _( |% z: D$ G$ @) Z
  47.    /**从文件建立图片   
    $ l+ \# U# ]% s$ Z. x' b* j4 J! K
  48.     * @param string $filePath 文件地址路径   
      J8 w! Q. W& R1 G2 i
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ( \6 O/ u- s' C, b. g' t0 K
  50.     * */   
      I9 M: W0 c8 b6 }& S& H& `
  51.    public static function createImage($filePath){    4 i- r5 d* o3 h5 N, y# t
  52.        if(!file_exists($filePath)){ return false; }   
    ; m5 e4 Y% F* V& U3 f
  53.     $ |! o4 G- O( [  H# l% l/ t1 Q3 K" h" w' k
  54.        /*判断文件类型是否可以开启*/   
    / s4 k8 A. ?5 [: ~
  55.        $type = exif_imagetype($filePath);   
    & r. w* T+ ]3 l% q, O' }
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    1 J, _( S& m! [( O6 n  d
  57.    
    7 \  f1 v/ J' c0 x' a; e
  58.        $func = self::$_createFunc[$type];   
    6 _8 n8 n# K/ u' \1 V
  59.        if(!function_exists($func)){ return false; }    6 t  O, p) m. {/ y. G( ]; c% D
  60.     % L% }- n& D) u
  61.        return $func($filePath);    8 ~$ s1 A! ~- P- _$ K& l3 \$ d
  62.    }   
    ( e/ J- x( c( V. J- J8 i& C! }2 K
  63.    
    ; N, e+ \& [3 j
  64.    
    3 o5 Z0 H0 T; r) j. T
  65.    /**hash 图片   
    & V/ E9 j% h' k& F- V  i
  66.     * @param resource $src 图片 resource ID   
    - |9 P( J. z* ?* I% q# O
  67.     * @return string 图片 hash 值,失败则是 false   
    6 V/ m7 X& q/ I- h/ Y0 B
  68.     * */    3 [& d5 l) E, R- Y" A4 y, a
  69.    public static function hashImage($src){    1 Z9 Z" w7 M& Y
  70.        if(!$src){ return false; }    / N8 y6 L% U1 E( ~2 k: P
  71.     3 \' z3 E4 H; W9 Q- k! q
  72.        /*缩小图片尺寸*/   
    & @9 D: ^# w* D3 R8 @
  73.        $delta = 8 * self::$rate;   
    1 w7 R; ]) n, L1 j/ x
  74.        $img = imageCreateTrueColor($delta,$delta);    . `  d- M/ a$ a+ Q/ ?
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    8 E6 n/ S+ s8 e6 R+ Q' L  X9 l, F
  76.     . o; b9 c7 J% d
  77.        /*计算图片灰阶值*/    6 ]: `4 _9 y0 R3 \- e3 i$ B
  78.        $grayArray = array();   
    : E* V. n) q; F* k# d4 u
  79.        for ($y=0; $y<$delta; $y++){   
    5 Q+ }) C' Q, `! a
  80.            for ($x=0; $x<$delta; $x++){   
    1 I0 d5 E( L+ x- ]5 |/ p! |
  81.                $rgb = imagecolorat($img,$x,$y);   
    + I. q4 o* I' z
  82.                $col = imagecolorsforindex($img, $rgb);   
    , N& b9 j0 d% s8 t! H8 _
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    2 ?, E8 u9 n7 _8 S
  84.    
    - H) ~  ~3 P5 J7 }6 z
  85.                $grayArray[] = $gray;   
    ' h, l* f% P/ @
  86.            }    ) R1 r) ~' Q( M
  87.        }   
    4 D/ a  b0 B1 K
  88.        imagedestroy($img);   
    ' c' e1 E/ G, N: A
  89.    
    2 [) u, s  m& a6 M/ y# \
  90.        /*计算所有像素的灰阶平均值*/    3 c$ a  }7 f% V7 X9 z
  91.        $average = array_sum($grayArray)/count($grayArray);    6 T/ B/ {$ U; K! H9 W$ t/ ~
  92.    
    . x* l2 R4 C3 S& E
  93.        /*计算 hash 值*/    ( B; x0 S& T  |% T8 t
  94.        $hashStr = '';    1 ^. ~) X) D0 }- e, V
  95.        foreach ($grayArray as $gray){   
    & _1 |5 R5 h* d4 h
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    ) ^& b% c- V9 }, s# {
  97.        }   
    + c* g4 e7 r/ h( T7 O
  98.    
    ! O$ L& A! E& p# o( T- q
  99.        return $hashStr;   
    $ }" [; P4 h! w2 g
  100.    }    1 w+ h4 @8 |2 C% |
  101.     + x0 Y1 m% U7 v- Y% K
  102.    
    " d$ J" u5 Q; g- {$ a
  103.    /**hash 图片文件   
    2 i$ I5 H, q5 h6 z4 Y3 w/ ]
  104.     * @param string $filePath 文件地址路径   
    0 v: w& E3 v' B. E
  105.     * @return string 图片 hash 值,失败则是 false   4 O2 _# a2 v  `9 {9 x/ U! v
  106.     * */    & o1 b, J, G, @3 @
  107.    public static function hashImageFile($filePath){    7 ?( y2 b# h- V
  108.        $src = self::createImage($filePath);    1 C- D) k5 j3 \/ o3 d4 @- Y
  109.        $hashStr = self::hashImage($src);   
    ! x( V# I; v) o+ \8 |
  110.        imagedestroy($src);    9 }3 W# t. O( u: {, d
  111.     7 ?$ K1 \& S$ s" J1 [
  112.        return $hashStr;    9 t! W: Y/ F/ q2 N
  113.    }      c, D2 j" |; A
  114.    
    ( G1 R1 w) D& n( s7 K5 r
  115.     7 f& M0 b) v# {
  116.    /**比较两个 hash 值,是不是相似   . E% V9 R2 g6 n- h9 E. I) u
  117.     * @param string $aHash A图片的 hash 值   5 N. A1 Z1 v7 d- L
  118.     * @param string $bHash B图片的 hash 值   
    : w! Y. k$ I/ D9 d1 E! i, h
  119.     * @return bool 当图片相似则传递 true,否则是 false   * n6 K6 Q7 T! e& _/ _; I# u
  120.     * */   
    % T  o8 i& i; Y2 C( ~- H& m! M- g
  121.    public static function isHashSimilar($aHash, $bHash){    : K3 K8 @6 V5 \0 W
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    4 m+ l9 L6 m* s( T$ |' }0 d3 w9 |
  123.        if ($aL !== $bL){ return false; }   
    ' l. s. I: w; h) h6 m/ Y
  124.    
    : l7 H: ~% b; ~# H2 j
  125.        /*计算容许落差的数量*/   
    ) G$ a) r2 d* q* y' J4 I: p
  126.        $allowGap = $aL*(100-self::$similarity)/100;    . Z4 R; l+ \) B; d0 ~. n! @8 V
  127.     9 r. B' L, h& x7 s! ^+ z5 Z; h6 P
  128.        /*计算两个 hash 值的汉明距离*/    ; x: \) Z9 c& {8 |2 v
  129.        $distance = 0;   
    . l, D0 x: g7 T% }# I, p) B3 h
  130.        for($i=0; $i<$aL; $i++){   
    % @6 i, n' u8 W( G6 X: q3 D
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    : \8 O2 x2 U* Q: V
  132.        }    / ?7 P! u) {8 F" c3 {
  133.    
    8 p. i$ M/ D8 {. @! |
  134.        return ($distance<=$allowGap) ? true : false;    - l* O( B/ y3 \
  135.    }    / M! _5 [+ u* g! p9 x; U
  136.     7 W) d( a- V. L' w3 ^# u0 c
  137.    
    8 K- V0 |; j' S6 E% [2 `# H2 X" a
  138.    /**比较两个图片文件,是不是相似   , D& k4 d0 {/ W- a8 b2 u
  139.     * @param string $aHash A图片的路径   
    3 r( S5 N( C( Y& Q( T: W! A/ q. M
  140.     * @param string $bHash B图片的路径   
    % ^' }1 G, g4 I& R) d
  141.     * @return bool 当图片相似则传递 true,否则是 false   0 s6 H1 t  Z  m1 `
  142.     * */   
    5 E  @1 E. z/ t+ O' l' J( o" E) \
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    : f4 _- l9 o( \8 i
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    " e! ^% Y  f% E6 U7 C& Y
  145.        $bHash = ImageHash::hashImageFile($bPath);    - f. K# P( T9 H- z' c- c
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    / _. o$ ?, o; `7 O7 T! B9 F
  147.    }   
    # H3 _$ @. j3 I& {
  148.     ' @7 A9 |" s3 {' n' }0 A
  149. }
    3 w' }/ k; U, w5 S
复制代码
0 i; Q) t* H7 S% W% M
# x( [* i- o, ^. ~4 p! I* _
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 23:35 , Processed in 0.061221 second(s), 19 queries .

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