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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

7 c+ W& u: {3 ~, @5 `由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
3 C- R$ D6 r9 A5 ~
  1. <?php    % o% Q) Q% t! G: |
  2. /**   
    1 f1 @: F' X! S" {$ ]: ~
  3. * 图片相似度比较   
    " y' v, [4 S7 N! o. q: x
  4. *   " n6 Q/ V' l; q8 g5 y2 T
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    2 _9 P' d# b9 f* N) y/ O5 G& l
  6. * @author      jax.hu   
    6 ~2 D# v0 X* M6 ^. ~) |4 b8 ]
  7. *   3 \9 \  u  w1 t/ x
  8. * <code>   : P7 d5 Q& U8 O6 u  n" R7 f) U' X0 X# T
  9. *  //Sample_1   * S  R' A( V( @6 b
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   . n& K, a( E: H% t
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ) G$ j& b3 r8 J$ S& v; S6 \
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   " y  c0 M# w6 Y* h3 j
  13. *   / W* ?( N2 w8 s* H* \. o* ^
  14. *  //Sample_2   
    : p# F2 `, |2 `. q" @; m) S6 Y
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   # C! T/ [( K. N
  16. * </code>   
    2 v; o0 e( _" k
  17. */   
    2 `2 p: Q! O9 _& m
  18.    
    ) d) x* T: x$ s, _) R+ h9 t9 {
  19. class ImageHash {    3 i' S* g5 S+ C, h7 R2 ?
  20.     ) C# O/ `# E; b% L$ [
  21.    /**取样倍率 1~10   
    3 `7 y* K2 o; v  }: [( \- y$ i
  22.     * @access public   
    - L( e+ \' T: `& V4 R1 V$ L' q9 G) r4 G. n+ y
  23.     * @staticvar int   2 ]8 C4 u% i9 ~$ ~. W# m+ o0 {
  24.     * */    ; F+ m( J3 U; |2 J3 T1 k% c
  25.    public static $rate = 2;   
    , W. Z/ [, I! Z
  26.    
    2 m6 E% m$ C2 u/ ]# S$ V) H8 d# }, w
  27.    /**相似度允许值 0~64   ; {; Z( v6 W/ h" x
  28.     * @access public   
    & n  |, G* _5 Q2 Y' r+ M. c
  29.     * @staticvar int   
    / I+ n' s* R$ j/ t0 G8 v8 l9 M
  30.     * */   
    - K, x) r$ K5 w, J
  31.    public static $similarity = 80;   
    9 Y% k% \4 b/ F) I3 D  D2 D4 n
  32.    
    ( w5 ]$ ]$ @: G7 E" n5 s; p  t
  33.    /**图片类型对应的开启函数   ' V3 M/ m9 T$ Z' c: t4 x0 ]
  34.     * @access private   , K9 n- |# e( ^  ]( P  k# x
  35.     * @staticvar string   
    ( X/ @/ |2 r' O- e+ ~$ B! y
  36.     * */    : K' o2 @6 U& d9 w) l" p
  37.    private static $_createFunc = array(    & v1 j  P/ i% m! b
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    & F/ ?6 p( e4 Y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    4 }6 y/ b) K3 g1 l5 e/ G5 ]  b
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    / @& {4 M5 t: c5 c6 K0 r
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    " e- \# v" T; B- H3 ]/ W( J
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    " O  K/ @  a5 `+ C' J
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
      E. @8 z- y+ N: L9 A+ e
  44.    );    $ G. Z$ G% \% C: N  y* X
  45.     + L# X  Y5 V3 V3 ~# c
  46.    
    ' \, b5 c# W0 j! A2 o* L
  47.    /**从文件建立图片   
    . n8 X  y- {' W% v4 ?: J
  48.     * @param string $filePath 文件地址路径   
    ! Y5 f- l/ R$ v3 ^! ?
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    9 a) m6 g- a4 I( o) Q/ `
  50.     * */    8 O5 j* G" h/ Q8 }$ t8 v
  51.    public static function createImage($filePath){    ! `. i: L* t# `! W# y
  52.        if(!file_exists($filePath)){ return false; }   
    5 l% }% a  k0 X6 f1 Q& y
  53.     8 \! {* e$ W; o5 a5 s- h5 _
  54.        /*判断文件类型是否可以开启*/    0 g; p5 a' a$ i/ C
  55.        $type = exif_imagetype($filePath);   
    7 k# K" z0 O$ \% ?7 l
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    * ^$ [+ J7 Q  A/ Z4 |6 R
  57.     ! R7 q# K8 f, b& e& b
  58.        $func = self::$_createFunc[$type];   
    ; q5 l; _; M- F6 A5 m2 Q- `
  59.        if(!function_exists($func)){ return false; }    - C$ S; \. [8 M: h4 K/ S
  60.    
    ' {# m  s* B: l2 S8 r( _
  61.        return $func($filePath);    7 z( n; I5 V, h* A
  62.    }    ( b% X. C9 G6 K! n: v
  63.     / o$ ?8 P$ j  a
  64.     & X, a* q5 y8 a- W& v( r
  65.    /**hash 图片   0 _+ r* i* X! \, L, a- G# H8 s
  66.     * @param resource $src 图片 resource ID   4 V6 B' q+ a+ t  O9 A: l
  67.     * @return string 图片 hash 值,失败则是 false   
    # \! x# E/ W7 ^1 j; O
  68.     * */    * B: n& b# h5 h/ d( |  F
  69.    public static function hashImage($src){   
    , ~0 q( D: ?) W2 _$ A) J, a+ H# }: y
  70.        if(!$src){ return false; }    6 z; N2 x6 Y1 o; O
  71.     ; r3 F! {$ u4 x
  72.        /*缩小图片尺寸*/   
    * h& v( P2 ?' k! k# o2 c3 P
  73.        $delta = 8 * self::$rate;    7 J& |' ~4 w1 w
  74.        $img = imageCreateTrueColor($delta,$delta);    2 Q0 N  W6 h; E5 B; _6 ^
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    * g5 c! I; t5 a& P# i" g
  76.     3 I: `3 q$ Q, Q! c  B
  77.        /*计算图片灰阶值*/   
    ' u, g5 e. X' G+ P
  78.        $grayArray = array();    9 ~) [/ n) n7 a
  79.        for ($y=0; $y<$delta; $y++){    8 m% o, m2 R2 B4 H" [( w9 r4 h
  80.            for ($x=0; $x<$delta; $x++){   
    - f. ~5 K0 @6 k( d( k# e
  81.                $rgb = imagecolorat($img,$x,$y);    ( H  S5 v7 T& A, U0 u
  82.                $col = imagecolorsforindex($img, $rgb);    ! v% K) F! d! a# i
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    1 t2 ^7 d; ?9 U( J9 o
  84.     # y7 l6 v, C: m7 i  |
  85.                $grayArray[] = $gray;    ) `6 z: O. X# F+ f
  86.            }   
    1 J" P0 F* Z' @4 u
  87.        }    5 U8 u5 K0 V# F% {( M0 {& L0 ]4 G
  88.        imagedestroy($img);    6 _' U- N( x0 X' l+ @, K4 V% n9 Q2 D
  89.     $ ~6 M- Z; r- ?0 `
  90.        /*计算所有像素的灰阶平均值*/    - t( W7 l0 V8 f, p' I# \
  91.        $average = array_sum($grayArray)/count($grayArray);   
    2 z* I; x5 n, u$ P; F2 v
  92.    
    & U7 \, S2 D: g7 p- P- h9 G
  93.        /*计算 hash 值*/    , I) L5 j: J6 l/ W' ]% V
  94.        $hashStr = '';   
    / T0 r! F8 x7 U0 _! z0 V
  95.        foreach ($grayArray as $gray){    ; B4 ~7 P# ?( T# ~
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    + F/ ^! Z4 E* K) m3 C/ d
  97.        }    9 M. S( M& ]' g  G
  98.    
    4 S0 Q* \2 Y% D3 H! K2 K
  99.        return $hashStr;   
    # t( p' q/ a* O: V7 W8 w
  100.    }    + p; C" g: |! r" D: ^9 @" H
  101.     6 @0 z9 ^2 M3 o1 D: y. c
  102.    
    # _) a$ C3 x; `: f3 X% a
  103.    /**hash 图片文件   
    / I0 e) F, ?! S; C, M1 T) I
  104.     * @param string $filePath 文件地址路径   
    0 w8 m' Q/ B9 b8 X
  105.     * @return string 图片 hash 值,失败则是 false   & e8 [& u& ^! r" J' c) X, m
  106.     * */    $ [8 s4 G5 z2 M
  107.    public static function hashImageFile($filePath){    - k" V0 [* S8 N& T3 d/ A+ ?. c, O8 C. f
  108.        $src = self::createImage($filePath);    : h) y  i: U8 {, ^) ]
  109.        $hashStr = self::hashImage($src);    0 [( e' q% z  y( N) [6 w3 Y( _0 R
  110.        imagedestroy($src);    ' H8 D$ k$ t$ Z# A0 A
  111.    
    + x. y  V. g: }" h+ x
  112.        return $hashStr;   
    : Q3 ]0 B8 U/ u( j
  113.    }      C$ A* a6 N5 Q% }
  114.     0 S) H, u* r4 Z: T8 f
  115.    
    + ~$ O# @' H8 Z0 D: X# ^  d; Y
  116.    /**比较两个 hash 值,是不是相似   
    & h1 x6 h0 s8 w2 k1 R6 o9 n% d
  117.     * @param string $aHash A图片的 hash 值   1 {1 G* @7 B6 V+ r
  118.     * @param string $bHash B图片的 hash 值   " K; D1 d& j3 o; f/ ~
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    " G9 O1 g, m; E8 R; V6 g
  120.     * */   
    1 X& l/ X. P: c' p+ ?
  121.    public static function isHashSimilar($aHash, $bHash){   
    & K0 v. X/ J$ }* m; J8 ^* s
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    5 i6 j' Z1 d$ `/ m0 U4 F' G
  123.        if ($aL !== $bL){ return false; }   
    ' m% D* Y! F: t3 y4 l1 D
  124.     : A; y$ _  Z, Z' \/ a
  125.        /*计算容许落差的数量*/    , z4 X' i* s8 W; ^6 _+ l
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    6 Z' k. O1 E& T& |4 E* N
  127.    
    5 ]4 C6 L2 ]0 i; ~, [
  128.        /*计算两个 hash 值的汉明距离*/   
    + a# D& V! `6 Z3 V' F
  129.        $distance = 0;    % `; S, j+ N, r* h3 \) W8 Q
  130.        for($i=0; $i<$aL; $i++){   
    8 m- R. ]! s$ |0 b
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }      U6 z6 g$ F4 G% c+ ?
  132.        }    " H6 g$ y- T( T. H* p  `
  133.     2 h. c; D$ i# u2 K; P/ G6 o4 y" ^
  134.        return ($distance<=$allowGap) ? true : false;    " h% \; _1 S/ f  {& _
  135.    }   
    4 h& H* A& }8 v. M
  136.    
    0 ?: y% A* q/ v3 @8 a
  137.     ' a- ]# D- n9 S1 g: \2 |; }
  138.    /**比较两个图片文件,是不是相似   ) ^! `+ e. b  r2 G: x
  139.     * @param string $aHash A图片的路径     q( a2 [# Q% N% ]6 ~/ ^* ^
  140.     * @param string $bHash B图片的路径   % p0 T9 j0 Y2 G6 ~" t# Z, u
  141.     * @return bool 当图片相似则传递 true,否则是 false   ' v* n; _- _) _( F. a1 `
  142.     * */    ) e$ G+ ~! [2 Y, q! M4 p
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    . N+ Z. i& q3 r6 {6 }( w' v% o6 T4 b
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    4 V* I1 E) T* j3 ]. E
  145.        $bHash = ImageHash::hashImageFile($bPath);    - Y# N3 u$ r  x
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    4 B/ v: C! H7 A# v6 h
  147.    }    ( h4 A0 _( e  c: @8 V" m
  148.    
    8 Z5 D# [4 }) Y$ v0 ~7 {5 U
  149. }
    : d# t4 c) i* y- w" A+ ?, l& U
复制代码
& g7 j) Q( B1 J0 ]+ G- V

* S6 F+ U* G* f) D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:54 , Processed in 0.122183 second(s), 20 queries .

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