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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

' w3 n! _- R- e4 ]  N由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
; B* E1 n' c1 J) H; n
  1. <?php    - N, O. B# T1 ]$ H' {
  2. /**   0 y5 y8 S7 L5 o
  3. * 图片相似度比较   . z: C3 [7 n. o
  4. *   
    ( q0 @% k6 p/ m. B9 \
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    % ]5 d+ `7 r, G! x% j- c3 a
  6. * @author      jax.hu   4 Z% K- F) o6 F$ r+ w
  7. *   3 _% Y% e, x! @; `. J
  8. * <code>   
    ! s( p. ?" ?, Z+ E4 a
  9. *  //Sample_1   + n1 t4 |/ i8 w
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');     n7 D/ Q* E( q/ Y) a2 g
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   . \4 r" g. k5 k3 e/ T* ^+ P
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    , G. U% f, e: O6 }* {
  13. *   3 W6 Z4 m% q& F
  14. *  //Sample_2   & ?+ r$ l) {1 y8 \: r! {: ]
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));     T4 i. n  H/ W% d. D. P
  16. * </code>   
    : }3 ^+ f) H6 `8 x. {: E
  17. */    . B7 Q, N5 v' i5 r" _
  18.    
    , u4 f% m" A( p7 j( F8 H! w
  19. class ImageHash {   
    % q: p& B# M- e, G9 k$ S
  20.    
    5 ]( F/ y  ~; J7 U: m" ]' I6 V
  21.    /**取样倍率 1~10   / |* z/ a$ C. a* X; Y7 l' r) }
  22.     * @access public   8 M* s" ?; O! U' w
  23.     * @staticvar int   
    8 i% k( f( B+ ^/ b: Y7 `% ^/ l1 Q
  24.     * */    , G4 i; Y3 C: c, ^% b
  25.    public static $rate = 2;    6 X- n& ?2 z) n9 a; v3 e% f
  26.     6 h' r) R$ ]1 N6 ]& b
  27.    /**相似度允许值 0~64   1 a) p3 x5 @+ _/ I; ?0 Q/ R2 H3 _
  28.     * @access public   
    / T! V5 O2 y9 u0 H. i- ^1 g
  29.     * @staticvar int   - {1 Y1 l/ Y5 v6 ]
  30.     * */   
    ' q6 I+ y' B4 ^# \5 `* {
  31.    public static $similarity = 80;   
    9 T& ~2 @. K/ b$ _' f
  32.    
      B9 [0 Q1 y/ |7 j4 P
  33.    /**图片类型对应的开启函数   
    & t6 V5 \  g+ c( c
  34.     * @access private   
    ; s$ r6 \0 K; W/ k" i
  35.     * @staticvar string   
    + h7 J6 v- U0 z* B- v- ~
  36.     * */    - ?, @1 l2 q& d# U8 V
  37.    private static $_createFunc = array(    - R) s; o7 M7 |$ ]3 a( O0 v6 I
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ! J% g' _* T% V0 G8 k5 {: Y5 k
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    : E0 b$ O* {1 J
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    : B7 v$ }6 p# F7 p( L- `: Z/ o
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    5 C& Z0 T4 n1 H
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    8 E, |3 v! \1 Y) S5 C' i
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    . Q8 |# Z% V) f1 _9 \* U, @( J8 V
  44.    );   
    & f# ^; x0 @) o# E+ Y( D9 F- _
  45.    
    + [7 @2 Q! d( n
  46.     2 e+ c& u2 q# G3 ^8 r
  47.    /**从文件建立图片   ) s% T( U1 C2 G* M
  48.     * @param string $filePath 文件地址路径   ' l, h& d1 n" _) ]* ]  X6 w% W
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   5 ^$ ]* @1 I0 {% V3 f5 V+ [7 c
  50.     * */   
    7 a: O$ F7 @/ t' H
  51.    public static function createImage($filePath){   
    1 u7 c2 f) Z  Z' W( @" n
  52.        if(!file_exists($filePath)){ return false; }    0 y+ @% ?" K9 e" y7 y6 W* L! ]
  53.     " e% R+ F; M# S! H
  54.        /*判断文件类型是否可以开启*/    4 g# E) W# b' B% x6 o
  55.        $type = exif_imagetype($filePath);   
    ! n' y1 A5 v! c
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    ' F' @: o9 `: C! L- Y
  57.    
    7 k& O7 X8 N0 m
  58.        $func = self::$_createFunc[$type];   
    9 H! v) e7 C2 d9 w' N6 ~3 o3 |
  59.        if(!function_exists($func)){ return false; }    ) V# W$ l& h1 V
  60.    
    0 f. V7 C- ?+ [: u- {) Z
  61.        return $func($filePath);   
    3 V) A2 q. [" |/ H( y. f% k
  62.    }   
    4 j/ f! a% l) u, V
  63.    
    ' j( x$ r6 f$ L; g9 S+ v
  64.    
    ) j& V1 K9 q9 K' ~
  65.    /**hash 图片   ' r  ]$ m" o3 F- p( A' G
  66.     * @param resource $src 图片 resource ID   
    7 Q# z) P, e3 }& |
  67.     * @return string 图片 hash 值,失败则是 false   " I1 j3 @0 A+ f2 l1 \
  68.     * */   
    4 V3 @, F3 G- ~( N
  69.    public static function hashImage($src){    : N% I1 h3 ~% O
  70.        if(!$src){ return false; }    9 T; ^' H# H+ o4 ?9 h
  71.     , d# m$ a* V: ]1 s# l6 u
  72.        /*缩小图片尺寸*/   
    4 H4 h* L2 \) ]9 t/ j: h
  73.        $delta = 8 * self::$rate;   
    0 a; B( P( r  l0 `9 A
  74.        $img = imageCreateTrueColor($delta,$delta);    & [( v7 b- L# q9 |3 S4 _: f( J. t
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    * E2 x6 u0 `* ^* m1 b+ o* i+ ]
  76.     ) x( X8 a* H$ p  _
  77.        /*计算图片灰阶值*/   
    / q; U0 O/ A/ ?% m0 v0 J
  78.        $grayArray = array();   
    . y# e# s5 Y4 `6 w4 p' K
  79.        for ($y=0; $y<$delta; $y++){    ! \0 W0 F+ _% [' e2 p
  80.            for ($x=0; $x<$delta; $x++){   
    * v( S- I/ p2 T  t/ J, t; q/ U
  81.                $rgb = imagecolorat($img,$x,$y);    7 Q9 K% A& t) G. ~& t
  82.                $col = imagecolorsforindex($img, $rgb);    . i% I1 k0 e1 S! G
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    9 T6 ~" i5 T+ R( u  v
  84.    
    4 `) t' U. b' U! @
  85.                $grayArray[] = $gray;   
    2 l1 A( D2 g5 `& z* v( T) y
  86.            }   
    0 C& J  R, \2 x- ~9 I
  87.        }    6 W" I$ u% A; W0 c5 d( r, K+ n; E
  88.        imagedestroy($img);   
    % r4 ]% K& y+ E' t/ [
  89.     3 F. G7 b, \; Z
  90.        /*计算所有像素的灰阶平均值*/   
    ; G- F+ c. L4 J+ U
  91.        $average = array_sum($grayArray)/count($grayArray);   
    0 r( b8 s  l/ i7 \
  92.     ' Z) q* C4 y; R1 M, ^
  93.        /*计算 hash 值*/    ) ~3 y8 O5 M' I- g* W8 y2 j* ^
  94.        $hashStr = '';   
    % c5 \$ K) N) d" x3 g; O" R
  95.        foreach ($grayArray as $gray){    ) Q+ u9 H! G* y( U: X
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    7 _' N  W( j( P5 s6 Y: _! H: w5 `
  97.        }   
    7 n, A2 m' U1 w1 f9 F  i* G7 _8 S
  98.    
    ' @5 E1 M% o  h* e9 T0 \9 z
  99.        return $hashStr;   
    3 O2 {' D8 \& u7 |4 @
  100.    }   
    # v5 r1 ^! N! P
  101.    
    " Q/ }: ?; B" g% p7 t! A; x
  102.     2 I8 p$ u8 S7 c/ v' f  \
  103.    /**hash 图片文件   
    ) U5 c' |4 D' {/ U& M
  104.     * @param string $filePath 文件地址路径   ; x) y$ ]  Y$ {
  105.     * @return string 图片 hash 值,失败则是 false   5 E7 l! w1 x& j, {
  106.     * */    & w) H% I7 E: p6 }
  107.    public static function hashImageFile($filePath){   
    * I- q. T, L! J  L  M. P& M( M
  108.        $src = self::createImage($filePath);    1 D: f7 ~) N$ l9 h# U6 S! a
  109.        $hashStr = self::hashImage($src);   
      l+ f* z1 d0 q
  110.        imagedestroy($src);   
    ! N) Q* B! f( X) r; l9 }  S9 a
  111.    
    0 }$ D( m. L* S" W# i+ J
  112.        return $hashStr;   
    " O( c; [0 q7 g# y. C. ^
  113.    }      l6 K2 S5 X8 m5 i
  114.     3 x$ [- \! s5 @1 d7 C
  115.     : J: u* B& p& B9 g
  116.    /**比较两个 hash 值,是不是相似   5 F4 |' ^; a0 Y& t7 R" i
  117.     * @param string $aHash A图片的 hash 值   ; X/ a* ^- }* A* a& `+ w  ~" q0 i
  118.     * @param string $bHash B图片的 hash 值   
    ( e" A& f/ H. X: O% r
  119.     * @return bool 当图片相似则传递 true,否则是 false   / ]3 j0 A+ L! K' b# i
  120.     * */    ' e0 w. E" ?/ [8 s. I: j
  121.    public static function isHashSimilar($aHash, $bHash){   
    $ x4 @  i  I1 E. ]
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    % }2 l7 [5 f- ?( A* }1 _$ D
  123.        if ($aL !== $bL){ return false; }   
    0 Y- T0 v. ?- \5 i
  124.     / M8 x' z: n* p) V
  125.        /*计算容许落差的数量*/   
      \9 o. G, d* ^
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    6 ~: z; u' M: A* b3 A: M
  127.    
    : z/ X/ m+ A. M* E( x$ i
  128.        /*计算两个 hash 值的汉明距离*/    & ]4 J2 L( Q" s$ b. O
  129.        $distance = 0;    2 c5 A$ g4 M; |& F& W. [1 J
  130.        for($i=0; $i<$aL; $i++){    # P7 G* x+ w2 w1 \
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    1 @8 O) m# m4 G; a& r- N& G! a: F
  132.        }    ; m* X. T& v. M$ a
  133.    
    / @( f+ ~) A: v! X! H
  134.        return ($distance<=$allowGap) ? true : false;   
    % T& i0 P7 ]% \3 W; u4 W
  135.    }   
    6 I8 X% d" z4 P1 @/ G/ ]# i- P7 u
  136.     - f1 x) R; Z- c+ c
  137.    
    - `$ v7 s. w% A9 |$ h
  138.    /**比较两个图片文件,是不是相似   
    $ O9 [; |5 p1 F, F
  139.     * @param string $aHash A图片的路径   8 A( Z; z# Q, [/ O& }
  140.     * @param string $bHash B图片的路径   1 _" X2 n5 A7 y' s1 i1 q
  141.     * @return bool 当图片相似则传递 true,否则是 false   " `. g$ `; K6 i0 z3 W
  142.     * */   
    ) d3 n3 f/ `  U2 W% i0 D
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    # z, G, Z4 p6 p9 n/ g3 F0 U
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    : @. }. N: t7 L9 y
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    * g0 U6 a/ O9 @+ O: p/ S
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    9 `( `0 N  v4 i+ ]0 V
  147.    }    6 ~7 c. a! u6 K+ x' c! Y3 x/ r
  148.    
    ( U0 n; m3 F3 M- j6 }" H
  149. }4 U/ E- R' L2 G5 p
复制代码

7 v# T6 \" }! U1 T/ y" M& L5 j8 D4 T) G7 K9 ~( s
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:11 , Processed in 0.057083 second(s), 20 queries .

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