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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

, j$ T! O0 w; L2 J& @

- q( |8 s/ D" W" b! c# R由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

4 _, L6 l' G9 Y6 r; g; T
  1. <?php   
    * v1 N9 H  S" G$ @5 b' v
  2. /**   + v6 C3 }; q$ s# i
  3. * 图片相似度比较   
    $ {4 e0 ]8 K0 X# T
  4. *   
    " o$ s! j* N! R" K' O5 t' R
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    5 e; k2 z- c8 E
  6. * @author      jax.hu   
      m* R! V: V, e4 Y; u& a
  7. *   
    2 t' e0 y$ L$ s7 M4 j* ^: O1 `6 {
  8. * <code>   
    0 Z/ w) x8 z$ c/ Z
  9. *  //Sample_1   
    , y( U8 b3 \- ]! J9 L7 J4 @3 q
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
      `# X  i* {; z6 k% G
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');     Z, a$ O/ H% V% @
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   . m' Q3 V+ }' {3 d; S6 s, L
  13. *   
    # f) L# L6 d+ j
  14. *  //Sample_2   
    9 b$ Z2 h$ q  p- @4 P8 l" ^
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   / v: e$ \1 k5 o8 C* i
  16. * </code>   4 y4 a* ]& |1 W6 F1 ^: x4 k- [7 V: ]
  17. */    ! @# d) W) O& D+ S9 s. q
  18.     & x9 o% O0 a9 c( R6 b
  19. class ImageHash {   
    ; p; ~6 u8 i9 I7 x) Z
  20.     8 |! F7 L3 u6 N( x8 d2 X
  21.    /**取样倍率 1~10   
    7 E1 }6 `  \' k( ~8 y
  22.     * @access public   
    ! J" {+ r+ Z4 D7 B1 x( O
  23.     * @staticvar int   8 q. t" Q6 _  Z
  24.     * */    ( V' j5 W1 t  c# D
  25.    public static $rate = 2;   
    ; u& Y5 L/ @2 s# ?
  26.    
    ) m/ a* h: j' |- e
  27.    /**相似度允许值 0~64   ' ?; V+ K- X* i& c7 |# F& ^
  28.     * @access public   
    ' N, n. K  J0 T* K& \
  29.     * @staticvar int   
    9 ?- }, A3 v5 B) `
  30.     * */    ' i, m" V3 c+ V& n7 J
  31.    public static $similarity = 80;    0 b; P) }) r2 d, @' ]! J
  32.     + f: W. g/ u: k4 L! d$ l
  33.    /**图片类型对应的开启函数   
    2 t& L# J* u% J3 G0 c  h
  34.     * @access private   # ^2 O! H, z1 x2 T
  35.     * @staticvar string   & j) ~& }. V. a! `6 H
  36.     * */    # ?& Y; U* M* \+ W5 N
  37.    private static $_createFunc = array(    . M  K6 I: D; U5 M4 D
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ; }/ v) b8 C! e; W7 ~7 [
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    8 X5 h3 `8 b, O! u+ ?' T2 Z! U
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
      r1 S; ^3 \* w: Z9 {# F9 r2 P
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    / p! P, ?4 E. Y. C6 A: @
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    $ R9 X: D. M7 p
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    4 d, m9 G' z: Q( D, Q  k* ^
  44.    );    2 o- y6 L. u2 O' _; u! O- V
  45.    
      c% L- y  G. @- {9 R" ~3 S
  46.       ]( k2 `5 e. z  E4 i* `
  47.    /**从文件建立图片   * `; P$ g5 Y9 R/ Q# s
  48.     * @param string $filePath 文件地址路径   # ^' j7 h* l/ s! ^7 \3 @
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ) z9 L5 N2 X& |8 ~. {
  50.     * */   
    * K3 O8 u" P3 d  A5 L/ w5 c
  51.    public static function createImage($filePath){    3 _- t0 N* X# S- d0 J8 O4 F
  52.        if(!file_exists($filePath)){ return false; }   
    6 X( w$ ^% q7 ?5 w* V! Z
  53.    
    4 h: D: T2 B6 D, r
  54.        /*判断文件类型是否可以开启*/    ) [6 h' F/ f# c% j3 Q7 d& R
  55.        $type = exif_imagetype($filePath);    " d4 ?- m6 v; P9 g' g" C- s+ O% E- H: {
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
      }' Z* F$ }# e% v0 E# @. X
  57.    
    " R2 d! s: l+ t+ @  ]3 A& C0 o! M
  58.        $func = self::$_createFunc[$type];    : o7 K, t3 k6 c3 I
  59.        if(!function_exists($func)){ return false; }   
    3 n. ~; B5 f' q, s4 v
  60.    
    6 g$ I' ?! ?( R- O( z
  61.        return $func($filePath);    ) d: C$ p  o1 I: [2 Q/ @1 k( t6 W
  62.    }   
    / I/ D7 r! c/ M: }+ `1 h
  63.    
    : ?4 p8 C, ]$ S. i8 q1 \7 ]
  64.     ( T- Z3 o  j" F: Q* p
  65.    /**hash 图片   
    7 g% A$ T6 U6 _' P
  66.     * @param resource $src 图片 resource ID   % F# K+ Q2 Z3 C/ Q6 a6 v
  67.     * @return string 图片 hash 值,失败则是 false   
    ) C$ y  H% u" S. N9 w% X
  68.     * */    3 k- \# B6 h4 J7 i9 |* T- O
  69.    public static function hashImage($src){   
    , M9 b8 [: T- S9 h, ]$ `
  70.        if(!$src){ return false; }   
    , H9 S& I( Y1 V1 _1 D
  71.    
    ! t& K3 o0 ?( l# o0 Q: _% W
  72.        /*缩小图片尺寸*/    5 _  c5 v/ g+ j! C' J9 f
  73.        $delta = 8 * self::$rate;   
    ' r% l9 H( W/ m) x9 Y. W
  74.        $img = imageCreateTrueColor($delta,$delta);    " J. T1 }. M' G/ U; Z; F* `3 ?
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ! N5 e2 b% w; M% `2 v7 R
  76.    
    0 @4 q- x$ X5 p
  77.        /*计算图片灰阶值*/    , h. c9 P% q$ u0 k: r: T/ K
  78.        $grayArray = array();    9 z. w$ x' ^2 A% p* Y
  79.        for ($y=0; $y<$delta; $y++){    % N( g* `# v. u( `
  80.            for ($x=0; $x<$delta; $x++){   
    ( W# j1 K- s$ r% P6 P
  81.                $rgb = imagecolorat($img,$x,$y);   
    / V7 `3 C: \3 U) W% ^
  82.                $col = imagecolorsforindex($img, $rgb);   
    $ i. k- m/ S) @* A  U+ h) w" B
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    5 j. ]* i6 R( w' {0 ^
  84.    
    + b: J& V  k$ ~
  85.                $grayArray[] = $gray;    - \/ l8 P+ T$ i3 }8 {
  86.            }    # M6 _$ s: ?( f" X9 s) i; O
  87.        }    / X) B% D6 j4 ?+ d4 g. y
  88.        imagedestroy($img);    # h$ C2 t+ d/ h- W; p- u4 X
  89.     ) _- a" _7 e1 @: P
  90.        /*计算所有像素的灰阶平均值*/   
    ( L0 S1 `; w# k
  91.        $average = array_sum($grayArray)/count($grayArray);    ) E, E( W5 _+ p# v- I' i
  92.    
    3 v1 T$ `3 G# m
  93.        /*计算 hash 值*/   
    ' F0 g1 o, C/ ?1 |, c" b$ w# T( @
  94.        $hashStr = '';    0 h9 y7 `& `# ?
  95.        foreach ($grayArray as $gray){    4 t4 h9 X- R7 `* S4 z' a
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    ; A# }8 i7 e* o0 n2 T+ F
  97.        }   
    . ?' U3 Q/ ?8 ^3 X7 a2 w, M
  98.     8 Y( X! m1 R& \! ^8 c
  99.        return $hashStr;   
    5 \! K  T! v* I* q( D8 m
  100.    }    , P. e/ I6 g2 R9 e7 g
  101.    
    4 a8 L9 F' }" E9 {& D
  102.     ! D7 |$ o3 w1 E8 ?0 _
  103.    /**hash 图片文件   
    ! |% e/ S; r) @. x6 A& ]
  104.     * @param string $filePath 文件地址路径   
    & g, X, m, R5 B
  105.     * @return string 图片 hash 值,失败则是 false   - u7 U; b2 D2 W+ H! w- {4 k
  106.     * */      V2 q9 j( r9 I/ A5 W  y2 P
  107.    public static function hashImageFile($filePath){   
    & P8 d' g$ ]2 g* y+ Y- O6 \  I
  108.        $src = self::createImage($filePath);   
    5 e& o% m4 |9 D2 |
  109.        $hashStr = self::hashImage($src);    , k' `: A4 j& Z9 u
  110.        imagedestroy($src);    % q7 c4 K$ n+ x4 |! G- ?
  111.    
    : Z, G+ f9 i/ c3 v+ ?
  112.        return $hashStr;   
    ) `: P$ i$ d8 w* T
  113.    }    6 D1 h5 Y6 Q1 U4 q( ~* F
  114.     ; q( i: N) C6 c7 V. p- E: ?
  115.    
    , [- {; p, F5 t2 z! f
  116.    /**比较两个 hash 值,是不是相似   
    8 j* Y$ i  i  R
  117.     * @param string $aHash A图片的 hash 值   
    & s1 o4 |. Y/ Q1 l8 f' Q0 z3 i2 ]
  118.     * @param string $bHash B图片的 hash 值   ! \5 w$ ~5 F3 _: p" Z
  119.     * @return bool 当图片相似则传递 true,否则是 false   % i- r) V) b- `% m* p. p8 V3 E
  120.     * */    $ k- w6 p# ]+ o8 e  M* g9 @! ^* d& N
  121.    public static function isHashSimilar($aHash, $bHash){   
    5 S8 i, |; v4 a+ A4 ~! T
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    $ v: H; L& q- p( }
  123.        if ($aL !== $bL){ return false; }   
    $ v" @% Y5 G/ x. u9 A
  124.    
    3 X* B/ a4 t1 b9 ^% v$ t
  125.        /*计算容许落差的数量*/   
    2 v; l2 Z8 j/ ^( W, ]4 y
  126.        $allowGap = $aL*(100-self::$similarity)/100;    % D! F( M+ i4 Z( U5 t2 U% {8 j
  127.    
      W, i* P! \1 P1 A, @3 H# G- n
  128.        /*计算两个 hash 值的汉明距离*/   
    4 M2 n8 _* l  J' W  V- Z, n, A
  129.        $distance = 0;   
    5 a% G" @! C4 ~# {
  130.        for($i=0; $i<$aL; $i++){    ( `9 h' ?, O0 @
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ; W$ d& g: S7 j8 H  H
  132.        }   
    1 t) k6 @% n+ f) [) w: V" [
  133.    
    5 J; z+ m  M0 L: ]" F
  134.        return ($distance<=$allowGap) ? true : false;   
    9 X2 e8 P, x9 p/ A5 M$ j: d
  135.    }   
    5 F( V- H# [7 v- |6 M! N
  136.     9 Z. h- }1 h5 k( o) R! Q( Q
  137.    
    2 f9 _5 i' S) i; ]7 ]0 ~. h3 q
  138.    /**比较两个图片文件,是不是相似   
    1 G) ?" `) [/ S8 B- _$ n* Z; m" G
  139.     * @param string $aHash A图片的路径   & L6 a0 ]/ J! c8 _- u
  140.     * @param string $bHash B图片的路径   - ^( S- L+ @$ |! F6 v- _
  141.     * @return bool 当图片相似则传递 true,否则是 false   ) m3 U* g: E/ v$ s! E
  142.     * */    ' w3 z4 c+ w' A6 x& r
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    & m/ t" ~" L! _" r  p; v3 N* Z, ?; C
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    0 q2 Y' Y0 j3 s, ]5 k# E, }
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    9 E7 \7 x. N5 w5 g# _! q
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    / P  g* ?8 Z/ R- O6 m
  147.    }   
    * L9 p+ R+ e0 t& v' @9 H" Y
  148.    
    3 m- ?4 S' _; a7 t, F+ l
  149. }
    ! P$ d$ \4 h7 q. \: ^$ X* N1 ]0 C9 J
复制代码

5 m/ V1 z8 `6 W6 x0 q* V" P
/ n6 v& {# H, `$ N1 k9 x2 K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 05:37 , Processed in 0.056161 second(s), 19 queries .

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