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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
- g! E+ _( @" x0 ?, X3 F
0 e) R. g; l4 k
2 m7 R7 ^4 k, D  B; v/ R
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
1 t5 F1 M1 H/ w8 e9 {
  1. <?php    ( I& P/ g) W$ F3 m" J
  2. /**   
    4 e7 K/ l. a" a& \
  3. * 图片相似度比较   
    : K3 J5 b3 q4 B6 S. O8 Z
  4. *   
    ( m/ Y4 P. k" I- T3 [# w$ M& R
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  8 n7 y1 b" A. V, f
  6. * @author      jax.hu   " y. \8 k0 O3 T" {, G
  7. *   8 E. D/ Z0 J, L+ r# M8 E) A
  8. * <code>   
    " F5 |1 I% A# A& c
  9. *  //Sample_1   * \) [! I+ o! g. V: a
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   2 \; s/ ]& Y" O
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    7 l& _! L$ `! W& E6 m
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ; z" y$ W, t9 n' Y: A( b  a
  13. *   ) d( ?; a* J, y! f) s, k2 q
  14. *  //Sample_2   ' k% R+ h- x1 S3 }+ `0 O
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    - s' Z. b9 X7 `: s6 w! @- A4 C
  16. * </code>   
    # ?; Z* G' V. N
  17. */    6 u4 W3 Z; U9 Q7 w+ ^+ l
  18.     / C+ L3 g) n. ]; ]& x& N" h6 v# R& b
  19. class ImageHash {    2 n( ?4 H6 R8 H4 Z; Y+ [
  20.       z" C- f" P- |: I8 z4 F, R1 _) w
  21.    /**取样倍率 1~10   
    9 \; B1 e- j  d6 r
  22.     * @access public   7 P. T2 v) e% O) Z' l
  23.     * @staticvar int   / Q  y9 g" r3 ~$ v, r
  24.     * */   
    # K# D/ a1 m* {, q0 O2 L
  25.    public static $rate = 2;    & ]1 H1 N7 [5 e  \& |
  26.    
    2 g& [7 a0 W% B' i; L6 G# ?  }
  27.    /**相似度允许值 0~64   
    # R+ I$ w- ^$ \/ s
  28.     * @access public   ) @% t1 |  \+ ^) j6 U) ^
  29.     * @staticvar int   ( m4 `/ E* B! l) y
  30.     * */    # i6 g2 f: k4 m; M" U
  31.    public static $similarity = 80;   
    ' H  d1 c, I* N' V3 x, l
  32.    
    4 Y: q6 u2 _6 G+ J
  33.    /**图片类型对应的开启函数   
    - k. _5 e0 ?+ ?4 Y4 V' e) M6 |
  34.     * @access private   
    / }, p* H5 h6 A% A) C. n
  35.     * @staticvar string   
    / z" c( Q! O! o4 X  v  u
  36.     * */      A9 Q" N/ s) I* Y) H; S
  37.    private static $_createFunc = array(   
    & y2 d+ z. i! I9 E' l- w; T) X( ]: G* T
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    5 J5 _5 @1 X6 Y" N
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ( H& Y* W# ~' W( ]  h# g' U" V+ P* g
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    6 V* I" B+ b/ t+ o/ `1 K  k6 e
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    / {  B# _; r5 v  I) ~0 A9 i
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    - e/ t4 c( x/ V6 ^  H
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    9 v5 g; y5 Z- b: U2 b( C; ~
  44.    );    5 M9 X" g1 V8 ^! w
  45.     ) _% u! q0 P' x- a# Y( ?
  46.    
    - N5 n2 X* ^- m6 @7 n6 u. n
  47.    /**从文件建立图片   
    - Q6 g3 [2 f7 h8 w  P% w8 `
  48.     * @param string $filePath 文件地址路径   : {2 C5 |, S8 Z
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    $ v& w% U% H, `$ W* W3 {
  50.     * */   
    / |& C4 e0 p* N* f3 F" P
  51.    public static function createImage($filePath){   
    - {" a/ e( q" i7 y1 S: e  P
  52.        if(!file_exists($filePath)){ return false; }   
    4 o, f" V% Q( |+ n) w* {; c) K
  53.     ) L! X5 d! v) {' t4 s
  54.        /*判断文件类型是否可以开启*/   
    ! U7 O8 `: l# s/ `0 T- u  O
  55.        $type = exif_imagetype($filePath);    5 n* P. u4 H! S/ {! J# R8 r; p
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ) p0 t: C( [% U" w
  57.     8 o' |$ a3 V- F" s" Z. ?
  58.        $func = self::$_createFunc[$type];   
    : G$ F# l2 P& L4 c" R: Y3 {
  59.        if(!function_exists($func)){ return false; }    9 Z$ q0 G0 s+ h/ W* D4 c$ z) A6 S
  60.     $ o2 L, X' R5 t5 Z# s
  61.        return $func($filePath);    2 F, k2 l6 p/ J& A0 f
  62.    }   
    : K# _) u6 B, H4 m( B6 [" f
  63.    
    ( M0 j! Y1 w: B. ^
  64.    
    7 B6 M$ Y$ E: C# E  K& M) ^! P* U% Q
  65.    /**hash 图片   
    . j. P$ D4 ]7 o+ Q6 W
  66.     * @param resource $src 图片 resource ID   0 s$ i; {! }$ e7 |- t1 b9 q
  67.     * @return string 图片 hash 值,失败则是 false   
    ' Y* D# P: d0 \  }/ j
  68.     * */      S* Q+ M, z. z, b
  69.    public static function hashImage($src){    % y+ n4 E" s* J
  70.        if(!$src){ return false; }    4 k8 t4 S# `% P  F4 `
  71.    
    # D: G+ A* P/ h
  72.        /*缩小图片尺寸*/    ) v' ?" |2 x3 F- [/ u# v
  73.        $delta = 8 * self::$rate;   
    6 N% E& ~  t: X' p
  74.        $img = imageCreateTrueColor($delta,$delta);      i' k: i4 N, [8 Z9 Q
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ' y7 i: g5 K6 y$ {2 K. s
  76.     7 O2 E7 M7 \% X; V% L
  77.        /*计算图片灰阶值*/   
    % u) G# G2 ^2 y2 H2 D, A) g
  78.        $grayArray = array();    ) y7 e. ]2 X( ^$ Z# x$ U6 {0 ~+ }
  79.        for ($y=0; $y<$delta; $y++){   
    5 N" R: }5 Q' p+ N/ w! T% I
  80.            for ($x=0; $x<$delta; $x++){    5 W6 a! T$ ]" I: q
  81.                $rgb = imagecolorat($img,$x,$y);    4 }, _1 t' K1 r5 J; @/ e6 p
  82.                $col = imagecolorsforindex($img, $rgb);    ! J4 p3 m3 J9 V+ D+ b
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    # w& d5 [1 G2 W: p: |, ]
  84.    
    2 A0 h0 @7 N# c
  85.                $grayArray[] = $gray;    7 s! |$ i3 i5 u! E4 b- w
  86.            }   
    4 Q5 k( b6 \# g0 _8 z+ W1 n
  87.        }    9 T: H+ J6 R3 r/ q/ u3 n
  88.        imagedestroy($img);   
    * b+ Y7 d" q% r' A9 q
  89.     # S5 @( Z5 C, J" Z- `3 z+ J* m
  90.        /*计算所有像素的灰阶平均值*/   
    - I* U' d2 D6 ^, K6 o2 ]2 J
  91.        $average = array_sum($grayArray)/count($grayArray);   
    # M  j$ h) C( G. p
  92.     + x* M# |( p" h1 I
  93.        /*计算 hash 值*/   
    " v+ Q% O. u8 k( N& j0 V( y' R9 O6 U' g+ e
  94.        $hashStr = '';    " D' K* T- F5 W
  95.        foreach ($grayArray as $gray){   
    % a9 Y/ D% [3 _( o: _
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    0 M( q- C. {- E# _5 n( N7 i
  97.        }   
    ( c/ r' \/ M, {
  98.     # L, G& d8 o3 r, q' g1 e1 o% S% ?
  99.        return $hashStr;   
    * K. k0 [1 D$ K% U$ u7 p) @' \
  100.    }    0 K: J/ \" k- O1 I; W
  101.     - [/ Q) Y7 _  f) i
  102.     # Q9 R, Q, y/ l6 J; l
  103.    /**hash 图片文件   
    & Q0 X0 o; Q3 c) P* x4 f7 ?5 w
  104.     * @param string $filePath 文件地址路径   
    7 ]/ W8 j  `) w; y" S, F# W1 c* M
  105.     * @return string 图片 hash 值,失败则是 false   5 S0 {6 T5 H  c1 M3 [0 |% d
  106.     * */    6 _* T% ^$ b- G! ?, K0 j
  107.    public static function hashImageFile($filePath){   
    0 h0 `5 ?. b, O: U
  108.        $src = self::createImage($filePath);    , A# W) l9 f4 t; w: V! q) O, [" f
  109.        $hashStr = self::hashImage($src);      ]% V* Q) B3 K! a/ O8 _
  110.        imagedestroy($src);    4 l' _/ ~4 z& Q3 Z
  111.     9 J+ b# O8 F6 j( m8 ~
  112.        return $hashStr;    ) Y  J. w' B( p; s
  113.    }    ' R8 ^, T+ S) ~. m
  114.     2 b4 X& x  B) \* U! z- K
  115.    
    + }. R4 ^) g) b" L, U6 p
  116.    /**比较两个 hash 值,是不是相似   4 a" v! X. Z4 o
  117.     * @param string $aHash A图片的 hash 值   % }* s7 ?1 [. t6 ]7 o' O
  118.     * @param string $bHash B图片的 hash 值   
    + M, E4 h* Y2 F; q  Q) G
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    " y: r5 e- Z4 O' J2 h# k
  120.     * */   
    3 O0 d! G/ T! j! x/ ^4 d/ [
  121.    public static function isHashSimilar($aHash, $bHash){    0 @! W# q  n. P! [8 ^  p" q
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ) _' M' Q% {% M( M& ^+ t7 d8 X% l
  123.        if ($aL !== $bL){ return false; }    ; a5 O: S# w0 W7 k/ R1 l
  124.    
    ) a3 r. X$ W- i! Z7 B6 @; P3 B
  125.        /*计算容许落差的数量*/   
    4 r5 e7 Q; o/ H% c6 k
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    8 Z3 n, W, k* v
  127.     ( [5 q0 t, \0 S' @7 `
  128.        /*计算两个 hash 值的汉明距离*/    ( a, y4 \2 h3 T: w( B! r8 }0 r3 D- `6 ]
  129.        $distance = 0;   
    8 ?8 g2 m! H2 x  D# F# m
  130.        for($i=0; $i<$aL; $i++){    0 f% R' d2 m* z9 S) u; d
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    , d/ q+ k8 J5 p/ D
  132.        }   
    : N* J+ f( g- b. D9 [9 w
  133.     & P% a  _5 g4 H. h
  134.        return ($distance<=$allowGap) ? true : false;   
    ' K. @1 m, O% Y, M. D; g
  135.    }    " M% [/ W) G0 x  s  s: K/ c
  136.     ' y# U% }+ ^% [: n6 A- ^9 `
  137.     % f7 H$ a. @7 s& x
  138.    /**比较两个图片文件,是不是相似   - V( T: Q# r- {  F2 Q: @
  139.     * @param string $aHash A图片的路径   
    8 v; x' Z3 u0 J% {4 s3 r) z7 g( h& J
  140.     * @param string $bHash B图片的路径   " @6 ]% k: L# V0 S
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    / H- _* h" ^4 M3 [+ u
  142.     * */   
    ( Z3 a, q7 |: M% l- w+ Y
  143.    public static function isImageFileSimilar($aPath, $bPath){    * P7 c& W* r2 z/ s, D* ]
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    % ~0 R. q! \2 Z5 K' U
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    4 E5 F& F0 a. K, W$ M, \
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    # r# N$ P' R# G+ L4 A' \  n
  147.    }   
    & Z' {* \6 ~* Y6 g5 i
  148.     + e6 P( Z# D2 E8 H* A+ Z
  149. }
    ) @, v9 ]0 w8 I2 r/ p! c
复制代码

; s" D, H0 ^6 ?/ s
" \$ j' F1 f5 m
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 11:39 , Processed in 0.053344 second(s), 20 queries .

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