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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图, b' a% C& w) D5 W! x( w0 H+ _
% r& ~2 w  W1 t- G6 y- Q7 ^; G

, h0 B( C5 T4 S' J, m由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
! r- \, l4 ~5 I$ K
  1. <?php    7 q3 _" l# U5 X  ]9 H* ]- P
  2. /**   & B3 t  o4 w( ]3 Y4 h
  3. * 图片相似度比较   ' m( J4 A6 f) R; [, |
  4. *   
    ! c: a4 s% q/ v, q  c
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  & a9 c# D( p' }
  6. * @author      jax.hu   
    5 x" W/ X, E; |6 G7 q$ Z
  7. *   
    0 m4 r, \& L( L+ O
  8. * <code>   & X$ f6 Y$ W2 R1 y
  9. *  //Sample_1   7 z, B+ G2 Q! \9 p
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   4 K9 K  q6 J7 |3 H5 M9 Z
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ; j* g5 L: d$ y, L3 ^6 u4 e0 }( M
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    + b; J! g) P; T3 q6 E8 e2 ]
  13. *   
    3 W6 w3 L$ E. l
  14. *  //Sample_2   
    # c" M, A4 }0 x% g
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    # C; ~( @  U' \& G4 U
  16. * </code>   ; V# U, t0 w! K& K6 B
  17. */   
    6 J0 @. B- o" l0 Z" Q) ~. b" f
  18.    
    ' i0 S4 U  V# u% [1 U8 U
  19. class ImageHash {    ( v: V! r# U  E( y0 U
  20.     / ^6 P$ b: @/ o9 A$ A( U. E0 F
  21.    /**取样倍率 1~10   
    ( J6 j8 g' b6 Q
  22.     * @access public   3 o4 c7 a% w+ K7 I2 `
  23.     * @staticvar int   
    ) X% ^& S! Z" m
  24.     * */   
    + `0 K! M  \$ Y  |
  25.    public static $rate = 2;   
    6 u1 `! g% }  d! o2 M3 D. ^( i
  26.    
    ) ?1 L; @' i3 c( Q
  27.    /**相似度允许值 0~64   
    # E" D8 ~( c4 z* x" O; W9 |1 V# Y
  28.     * @access public   
    7 B4 b- Y1 J+ ?/ z4 S0 C8 z0 d% G
  29.     * @staticvar int   + m1 a( ?$ [" j) W( j$ s8 N
  30.     * */   
    " t  A& ]* f, q% J. Q# n
  31.    public static $similarity = 80;    0 c( \* l) m  \) j. K, ~9 f3 m
  32.     * d% y3 S& l7 ]
  33.    /**图片类型对应的开启函数   
    " I) \" |7 L2 O' S; C' a0 F! {
  34.     * @access private   
    " a  L/ S& O. u
  35.     * @staticvar string   1 R; P8 n5 i; _  @, _) O
  36.     * */    5 E3 y6 n$ }! ^; _! C4 _+ Z
  37.    private static $_createFunc = array(    % N3 z+ g6 _4 |; R  t
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    - T$ s' S! j) f: a
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    & u4 P+ x& T% a; Y( H; C, _, [
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    / E2 z* ^& q% `% {8 r; o$ i* r9 U
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    0 F. ]+ s5 h. f% N2 C1 D- U. K# e0 r
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    , k# g1 f2 v# _; R( ~5 z. r
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    9 y* i6 u; z6 ~2 ~. n% a
  44.    );    # i' c! l. c. h, c+ |# z
  45.    
    $ l7 P1 q* B* O9 Z+ D2 u
  46.     . ~/ F; H* h7 _+ Y! }5 c3 u1 |5 R
  47.    /**从文件建立图片   ; e+ b" A* [* p, F$ Q
  48.     * @param string $filePath 文件地址路径   1 X( f5 j- R2 J; g
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ) P6 z# s+ ^! y0 X. c! ~% a- P' x6 l
  50.     * */   
    * f$ L& _7 H$ n8 Q0 N, k3 f# O
  51.    public static function createImage($filePath){   
    % r- y* g' n8 O0 T- S; y4 E
  52.        if(!file_exists($filePath)){ return false; }    / @+ e" t3 W6 c  ~* _& N
  53.     ! l8 Y# Q5 }; d+ t  q
  54.        /*判断文件类型是否可以开启*/    0 d7 m& K- e1 u5 g, w  G
  55.        $type = exif_imagetype($filePath);   
    7 k0 {! A. o6 w7 o+ n! p
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    , {; A7 Z" e3 q8 A, h- x8 K
  57.     ( ]$ x# Z2 F& |& s4 P
  58.        $func = self::$_createFunc[$type];   
    - v% D& V5 D! n. d; o7 y
  59.        if(!function_exists($func)){ return false; }   
    " j  d/ A3 ^4 X$ w! y5 N
  60.    
    1 j" b% y0 L- i, f$ G  @
  61.        return $func($filePath);    9 f; c( p6 y7 k
  62.    }   
    6 [0 ]* G/ {3 R
  63.     * S. ^! p% @+ ?6 c# [$ p
  64.     & f* F5 C6 M* Y
  65.    /**hash 图片   
    . q# c, I; o% g
  66.     * @param resource $src 图片 resource ID   
    # W/ M) i9 ?" b2 l8 u1 i5 x
  67.     * @return string 图片 hash 值,失败则是 false   ( V$ y  ^: `7 x' M
  68.     * */   
    0 v; T" i2 ~, |$ B1 X  _
  69.    public static function hashImage($src){   
    - h! `& E& z7 A& G: K1 u
  70.        if(!$src){ return false; }    5 ^1 \& D6 @# p) h
  71.     : }* h2 v' n" l7 v  C
  72.        /*缩小图片尺寸*/    # Y' q% Z; Q3 ?3 `0 x2 Z  u
  73.        $delta = 8 * self::$rate;   
    ' D3 n# i) e3 T, f
  74.        $img = imageCreateTrueColor($delta,$delta);    8 J7 y* c' s  j2 D! _$ v! B
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    7 g& F+ q( E) q
  76.    
    / f4 K4 i" V& G: R2 e6 Y
  77.        /*计算图片灰阶值*/    # m5 k, O3 C6 e, Q+ j* F! W
  78.        $grayArray = array();   
    + v4 p6 d4 H9 r7 ?5 ~  f5 H0 {& _) ]/ v
  79.        for ($y=0; $y<$delta; $y++){   
    ( j9 @; L7 [/ N- v, `! x
  80.            for ($x=0; $x<$delta; $x++){   
    6 U  S. E+ v( [
  81.                $rgb = imagecolorat($img,$x,$y);    ' x: q& J, A  k( j: `2 t; g% H
  82.                $col = imagecolorsforindex($img, $rgb);   
    & I6 o. W' v6 a" |2 U1 R: M
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    5 t+ a- I5 _# I5 T3 o/ e
  84.    
    ' d! k% t1 A) V
  85.                $grayArray[] = $gray;    , t$ W" A! G. S9 L3 i
  86.            }    , q& k# P4 [% v
  87.        }    % X* ~3 k' v% Y) T5 a& P
  88.        imagedestroy($img);   
    : J0 ?1 R( N7 Z( u0 _( Y" v/ L. T: W' H
  89.    
      V+ n  a# t6 A( O4 p! J0 t
  90.        /*计算所有像素的灰阶平均值*/    + C  T% w: _. r, {0 d$ `4 K1 C
  91.        $average = array_sum($grayArray)/count($grayArray);   
    0 b' A, K0 {5 O0 I: e$ O4 Q. ~& U
  92.     " e* w7 u- N1 G3 U4 \
  93.        /*计算 hash 值*/   
    ( _& h& a' z" [. O9 a, T1 q
  94.        $hashStr = '';    1 S4 @' R. A- E. Y4 U3 d* G
  95.        foreach ($grayArray as $gray){   
    # D& X4 `4 B% @' [* N4 z4 E
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ! Z; s* _- z+ g. W- @
  97.        }   
    7 T2 t5 x3 h/ ]* [5 `: m
  98.     4 W2 h: W- n6 f
  99.        return $hashStr;   
    / A6 C' q/ z' q; X
  100.    }   
    6 I8 S4 B' R/ Z- t8 c  ^
  101.    
    0 ^' M- f. f, d- ^2 ]
  102.     9 ^2 }. X4 ?2 F; {' O& t
  103.    /**hash 图片文件   
    2 m. L$ W2 q5 b9 v6 `" P' K  x( r
  104.     * @param string $filePath 文件地址路径   ' b$ t% |1 `8 p" Q- I! L* V! E
  105.     * @return string 图片 hash 值,失败则是 false   
    3 }4 A+ c5 L) D7 g  g& b% s- K& L
  106.     * */    & G2 [& a3 ]0 \: L8 l) d& `- B1 P
  107.    public static function hashImageFile($filePath){    ' r9 C$ H8 y* F3 E! W
  108.        $src = self::createImage($filePath);    , R* D9 j* n9 U0 J- \4 u0 G" @
  109.        $hashStr = self::hashImage($src);   
    5 i9 I& y. T5 U1 h
  110.        imagedestroy($src);    ; V$ G8 \6 K* i$ m/ }. h
  111.     * [( m' D+ `  R8 m
  112.        return $hashStr;   
    9 o/ _2 t8 J  c6 J3 N# F+ a* H
  113.    }    : r; s& b7 ~3 I; p1 [# Z- A9 {0 g
  114.    
    % J. F- @- w9 }- a1 ?( S+ W: J
  115.    
    # R; N$ C2 w6 B% I" o" y/ h
  116.    /**比较两个 hash 值,是不是相似   " r% `- J1 N" P# I
  117.     * @param string $aHash A图片的 hash 值   2 H0 F: n) x: l* |) r9 n
  118.     * @param string $bHash B图片的 hash 值   
    8 Q/ r/ n# q1 j0 _6 l  d4 O2 e
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ; f5 U' C# S6 M' d9 G
  120.     * */   
    ( t+ c" U5 v( o8 i$ G
  121.    public static function isHashSimilar($aHash, $bHash){   
    ' d% y$ q; I0 l# G, E
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    / K2 L3 C4 `3 X6 a9 b9 u
  123.        if ($aL !== $bL){ return false; }    + o$ A/ g6 n+ p% X
  124.     8 W! f, Z( P+ o" Z1 a  v
  125.        /*计算容许落差的数量*/    ; V3 i+ X+ m5 U8 J' O5 j
  126.        $allowGap = $aL*(100-self::$similarity)/100;    ( X7 Y0 M# p2 {+ w) D- {
  127.     9 B: J7 i7 _: N$ n" ?$ G$ t
  128.        /*计算两个 hash 值的汉明距离*/    * {9 W+ W$ N8 B7 \0 G  y7 x! B
  129.        $distance = 0;    8 h: P: M: S( F' q6 \2 Y
  130.        for($i=0; $i<$aL; $i++){    ' u% q: |! \( a$ f
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    * Q: \& c. i! h! E7 f( Q# p
  132.        }    3 F! e3 A6 k' w9 M# x
  133.     % C! O# m. g% Q8 o9 s
  134.        return ($distance<=$allowGap) ? true : false;   
      d2 u2 v6 H+ s- y5 @2 f, N2 J& L
  135.    }   
    ( @/ G  C/ W2 c& k; n! V. V
  136.    
    3 r7 h5 I2 _  o( r- d4 I
  137.     ; G3 u, t' I9 P; X" I' H
  138.    /**比较两个图片文件,是不是相似   2 j1 F. ]. ]6 @! l( [
  139.     * @param string $aHash A图片的路径   
    . S2 ?# t; |0 ]3 S+ {" {
  140.     * @param string $bHash B图片的路径   & P+ c9 p" B! L, d& r* w
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    3 M- o8 O7 k5 h; [+ Z1 ^$ i
  142.     * */    , V2 v- C7 R- \+ |! Q2 _& W
  143.    public static function isImageFileSimilar($aPath, $bPath){    * ?$ ~# m- V4 N$ {) t9 [$ B
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    / B+ l3 u- n* k$ m  ?( g9 P
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    5 `: y2 H, h) C" O1 N7 F1 k2 a. t
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    + l$ W( t" I! I; @" V! j$ s
  147.    }   
    & }' D$ P" N% G+ _
  148.     1 x( n. f, L0 i1 s- t! W$ b+ ^1 A
  149. }
    * U" C1 D+ U3 B7 H; r: Q: d$ S
复制代码

9 \3 j6 R# A6 R
: l( _! T$ _3 @; `$ x% M9 W
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 22:00 , Processed in 0.106036 second(s), 19 queries .

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