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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图/ j( ^+ Y8 K- b+ F5 ]  C- j  J$ `
- z1 V6 ?! X6 B2 s. H
* t. {5 H  Q/ }/ c
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

3 R7 X' q6 Q, R' E9 j6 I
  1. <?php   
    3 V6 X$ |: f5 m# _
  2. /**   
    : I1 D3 ]  T, C. z: o. p
  3. * 图片相似度比较   4 _7 c+ ^  p  q
  4. *   & F6 X0 ^: x; _7 i' B- I4 }/ f: u& U
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  ) ?; V8 O8 }- x9 e
  6. * @author      jax.hu   / i* j% u7 T0 k$ C% v
  7. *   
    6 T$ T. {/ f/ `. A( ^' `( V
  8. * <code>   
    ! ?5 g* Q( O, H3 d8 A! f
  9. *  //Sample_1   . Y( {) g! z3 F% a" i9 _
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    + r/ s7 M4 h# y+ _
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   - Q; r+ B4 E5 N/ y3 Q
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ) W: C+ R) M) E" i( u7 x& R
  13. *   3 v7 D( A; U; d" j2 |  B2 C* M
  14. *  //Sample_2   
    . N' |+ B* S& J
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    # c1 z5 l2 W* d( g" |: W/ ^
  16. * </code>   
    ( H/ L8 }) F0 N, H' B
  17. */   
    ( A; q! n; ~  j0 V6 y
  18.     - B4 n; ?: m( Q1 d/ z' W
  19. class ImageHash {    : y1 S0 W# W: V1 J
  20.    
    & |# T( Z$ Z0 q( x& Y2 B
  21.    /**取样倍率 1~10   ( J$ ]' \4 c" h' h6 B$ A: S
  22.     * @access public   
    ( e7 D- Q3 [: T2 L( |# Q
  23.     * @staticvar int   
    * b- u+ i& V& ]" n1 y+ q
  24.     * */   
    - W" [! }9 J+ w) [6 H
  25.    public static $rate = 2;    9 `. l) W6 B3 C, A
  26.    
    1 V% i* H+ f2 T
  27.    /**相似度允许值 0~64   ) D; h" W# v' k5 y
  28.     * @access public   6 R: n/ o0 {5 `& S3 i
  29.     * @staticvar int   
    , J6 a8 W9 e+ }
  30.     * */   
    1 p4 q7 j! o; o
  31.    public static $similarity = 80;   
    ; b9 i! J: _5 H$ u) j
  32.     4 d8 e) E& F/ a; x+ y
  33.    /**图片类型对应的开启函数   : W) N$ G; f: [) T& t
  34.     * @access private   3 T  ~1 W# n8 O- y
  35.     * @staticvar string   
    8 F6 w4 u% W4 a4 P4 d$ r
  36.     * */    5 F0 p7 g4 N" o. B5 `
  37.    private static $_createFunc = array(    8 S  k1 K3 U9 b9 Y9 a
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    $ A1 a& S8 @* b8 C; x) v* ^
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ( J- V& M! e( U4 }
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    6 }: {2 D4 x& G: p. J: O9 o5 r3 }
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    0 y0 \7 R0 O6 {# C% h3 E* c
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    ' Y2 v( w% T  t" l: B
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ; ]" J: g, F  `2 w5 E% d
  44.    );    0 z8 `; m; ?* n3 m" ~+ H- @
  45.    
    . j0 d" Y' n; \$ S/ b
  46.     4 y' ]' g: L* h7 v
  47.    /**从文件建立图片   
    ! I8 T  z, \: B' k- s7 l
  48.     * @param string $filePath 文件地址路径   
    " C$ `  j; R' R% ~- \- H1 g6 ^
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   1 M" T1 Z* ?/ B4 l- Q! h0 M( X
  50.     * */    , s- Q7 P! |0 ~8 O
  51.    public static function createImage($filePath){    : v$ J" B" n5 v# s% \
  52.        if(!file_exists($filePath)){ return false; }    ( z" ?; z' w4 u
  53.     ) k! x* l% R& }& v
  54.        /*判断文件类型是否可以开启*/   
    " p2 |. Y- S% _
  55.        $type = exif_imagetype($filePath);    5 A% [! s- ^7 ~4 ^# \, C3 ^0 s
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
      P8 C2 `& Q# h: Z9 s
  57.     8 J/ y0 d( W7 K  i& V
  58.        $func = self::$_createFunc[$type];   
    6 ^9 y" t- t* ]* g4 c, X0 v
  59.        if(!function_exists($func)){ return false; }    5 S% N5 O3 \' c, k2 _/ @* @1 r; t
  60.    
    + I4 t3 y" d: j$ N" ^6 G+ K- Z
  61.        return $func($filePath);    1 `0 Q! o( i* F' e  o1 N$ z
  62.    }    % j$ r" e; q4 n& U
  63.    
    ' |6 n. E- d) f) V6 G# a2 [1 G* Z8 i3 T
  64.    
    5 v. I+ G! W) w6 U
  65.    /**hash 图片   
    / k" C' K- V, h0 s* `1 O" f
  66.     * @param resource $src 图片 resource ID   2 T9 D: t& J) U9 T
  67.     * @return string 图片 hash 值,失败则是 false   
    ! r1 h6 \/ c9 e1 e
  68.     * */   
    % w4 ]& }. T8 h4 Z& \
  69.    public static function hashImage($src){   
    - I7 {4 C0 @! \8 L( v* o
  70.        if(!$src){ return false; }    3 {" ]8 L0 R% V- j$ _2 _( D, g
  71.    
    4 Z' ^9 g4 s3 J6 B
  72.        /*缩小图片尺寸*/   
    $ _& X# ]0 @8 C2 }, M8 s- B
  73.        $delta = 8 * self::$rate;   
    6 {3 h9 c+ A, g2 X) x8 d
  74.        $img = imageCreateTrueColor($delta,$delta);    7 h# S0 O4 k! p# n
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    * {, t, Q( b$ a  s# ^
  76.    
    4 b+ J/ k- Y. U) v2 O
  77.        /*计算图片灰阶值*/   
    , k6 a( H+ X/ p# ?( y" x/ k
  78.        $grayArray = array();   
    + f* n1 F3 {+ \  b0 `* r/ v5 r
  79.        for ($y=0; $y<$delta; $y++){   
    8 I1 v: F: O! k3 R  Q6 @0 R* m! i
  80.            for ($x=0; $x<$delta; $x++){   
    3 ~1 J0 y4 I9 C) V& ?, M  U3 u# p
  81.                $rgb = imagecolorat($img,$x,$y);   
    / a) r3 b; I/ y  d
  82.                $col = imagecolorsforindex($img, $rgb);    0 g% Z3 b6 R/ P! C0 H. h! b, J
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ! W9 I! Q4 Q$ U) l
  84.     * X# l( _4 |* T+ i) i( N4 N& N
  85.                $grayArray[] = $gray;   
    / q( X6 O; g: T+ E6 K0 [' _) P# n
  86.            }      S" c0 P( c3 L4 N6 G5 T
  87.        }   
    - o) `, `7 y# k$ |! Y  u3 G
  88.        imagedestroy($img);   
    & I% A$ o8 ?: g  \9 U$ t
  89.    
    9 o' K9 L2 H9 a( A
  90.        /*计算所有像素的灰阶平均值*/   
    4 q7 x4 z( m" V+ q6 v
  91.        $average = array_sum($grayArray)/count($grayArray);   
    3 U* Z3 y, y2 H
  92.     1 F  x. j; t3 x5 K2 N. J# q
  93.        /*计算 hash 值*/   
    $ V0 ]. f- P) l& w6 b- b, H. X) B: A
  94.        $hashStr = '';    - v) v2 [' H1 ~- s$ a  R
  95.        foreach ($grayArray as $gray){   
    0 t/ E  p( V: Z4 k* C  B+ R$ y- e% E4 i
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    % [* x+ Z+ F8 ]) t
  97.        }   
    8 L9 ]$ A$ C. y( R( R! H+ T1 h1 L
  98.     " g: x5 Y) u; X$ B+ `9 z' b
  99.        return $hashStr;   
    - |3 h1 h* Y  }* V1 v* f
  100.    }   
    2 v: o: f  l- o6 S
  101.     7 k& w3 U# j$ C8 w( d. x0 F
  102.    
    3 s9 \0 ^; X  G) r
  103.    /**hash 图片文件   3 V9 ~( @/ Q! o* d
  104.     * @param string $filePath 文件地址路径   , `8 ^; C" G$ L; K# Z
  105.     * @return string 图片 hash 值,失败则是 false   
    % i: X8 H) i% J- P" h- y( \
  106.     * */    0 U! f/ J' O/ p& {& G; l
  107.    public static function hashImageFile($filePath){    3 C) W% i- S* W4 t; H% X: s  k- F9 V/ H
  108.        $src = self::createImage($filePath);   
    , s0 T1 O, o* @, z! i9 g. s
  109.        $hashStr = self::hashImage($src);   
    5 A# i6 h2 U& `% I; N/ I4 k; F" d
  110.        imagedestroy($src);   
    + w9 L& N' y: T
  111.    
    + |7 @0 d" p) o# Z9 Q' @/ ?
  112.        return $hashStr;   
      R/ ?! b, K. [( G
  113.    }    # d) @( B; d; A, R: }1 O- D' R
  114.     & f+ B; G- I" u6 U$ S8 ]
  115.    
    ! P6 I1 e( {* @" X0 B$ p
  116.    /**比较两个 hash 值,是不是相似   
    3 Z0 Z9 Y, P4 j' g- }
  117.     * @param string $aHash A图片的 hash 值   
    % m3 T, p. S8 F6 j5 u
  118.     * @param string $bHash B图片的 hash 值   ( N" W# G2 w+ D  g& r% B2 e
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    6 x2 O0 f( q# m* B& B! o
  120.     * */   
    8 E5 j' q0 Y/ G  R( [
  121.    public static function isHashSimilar($aHash, $bHash){   
    . c+ K9 ?& ^# V7 ~4 k- L
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
      ^9 w& E) a" b0 q8 s8 }: [& {
  123.        if ($aL !== $bL){ return false; }    * @: }7 H& ^* J6 X* `3 `: K
  124.     ! Z/ v. [: r7 \, a; i6 ?9 N
  125.        /*计算容许落差的数量*/   
    9 y7 L: |+ F/ L0 z: M9 p
  126.        $allowGap = $aL*(100-self::$similarity)/100;    " I0 X$ Q  y4 k# b
  127.     & X% B" \2 b3 `
  128.        /*计算两个 hash 值的汉明距离*/   
    5 c) ]' a( K5 ~; H4 w4 K" L6 C6 q, f/ e
  129.        $distance = 0;    1 M4 ?' z) y* W! ]) r, z1 G& o
  130.        for($i=0; $i<$aL; $i++){    ' R2 ]9 V: [, W; M- }0 f$ a
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    " ]7 t# v6 D& S! m) k: ~9 |3 m, ]
  132.        }    & K* U" _; f1 F
  133.    
    9 u& y. _' c8 \2 c$ O1 [
  134.        return ($distance<=$allowGap) ? true : false;      C' a. _% v* `5 f
  135.    }   
    0 r% e+ w: X: ?) S) a1 k- T4 Y+ L9 |
  136.    
    ( d3 ?7 e8 R" Q* u- s
  137.       L" l% @, C9 n: j
  138.    /**比较两个图片文件,是不是相似   
    / ^! z3 V+ ~, P
  139.     * @param string $aHash A图片的路径   ) w9 G  e4 a( K$ |8 ~6 }) `1 y! G& ~
  140.     * @param string $bHash B图片的路径   
    7 ~' B9 L, V$ |* I9 j* l
  141.     * @return bool 当图片相似则传递 true,否则是 false     M4 l" V% [* t8 n; R- k
  142.     * */   
    0 a) m- D  j" J$ P  S7 z6 z
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    % O' x0 D7 O9 W/ D
  144.        $aHash = ImageHash::hashImageFile($aPath);    & x+ M2 i" s" O: ~9 t$ r
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    * p% `! g' R% ]7 C' D7 f
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    * d  M; K& H: a  z
  147.    }   
    - L6 n, F% M( j. z
  148.    
    2 h6 e6 j$ i  g8 }6 M0 ]/ {) W
  149. }
    * n+ ^) Q2 O0 t1 C4 O
复制代码
& `/ K9 E; ]  z: `2 s; K
0 x$ x( ~" Z' d" V2 a' y6 E6 C
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 08:19 , Processed in 0.113446 second(s), 21 queries .

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