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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
3 L0 Z3 V. t$ o, I* _# v8 ^0 W0 [7 ~2 G- U

( k- }2 r8 z+ B" `3 \由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
0 p0 }( q6 Q  ]: e" a0 l% p
  1. <?php   
    1 c& R9 u! A6 M1 f' Z$ @2 K5 b
  2. /**   
    ; J3 l& Y3 {' B/ Q/ d3 C" w
  3. * 图片相似度比较   ) H& s5 y5 ?' v0 T" c1 x4 b8 }) c9 V
  4. *   ) ]; }) F8 K  ?: L% e5 G% e: u
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    2 w0 l0 D, v! }. i6 _
  6. * @author      jax.hu   # n" L. F4 v$ F: ?6 C; o4 N* F
  7. *   
    ( v8 j1 Q0 c( D9 Y
  8. * <code>   6 y1 D3 H/ ]5 c* X9 s
  9. *  //Sample_1   # f9 |" @* i4 z2 Y8 L1 \, d
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    8 |- G; N# {' K+ ~9 q6 z# J3 B
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   + K% L. k1 Q* f( X5 f
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    5 z/ C( B: A( r6 d6 ~2 O
  13. *   5 N% s5 |$ ]0 p/ R* Z& ?8 J  E& ~8 i1 s
  14. *  //Sample_2   
    % ~5 G/ P$ [' T, I; Y5 l+ r& W4 ^1 B
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    % Z+ w6 f7 l7 B" I$ X( a
  16. * </code>   
    ; P6 i; ]) s" A- K0 e0 N
  17. */    9 w/ }8 g. |& X2 |+ j
  18.     3 i2 W  o0 t, Y: ?+ k
  19. class ImageHash {   
    ( }) a: j" u  a, x
  20.     : ]* \" d! p. N6 e$ b8 }
  21.    /**取样倍率 1~10   
    & t9 B5 m0 w/ A2 a
  22.     * @access public   
      V3 a0 t$ m! D& h6 m" W
  23.     * @staticvar int     y8 i" n4 q3 D6 Z( w
  24.     * */    . @  V, X7 K, ~% L% i. y: I2 o
  25.    public static $rate = 2;    8 u) D* z5 O6 R2 {- h
  26.    
    # w( |& l0 N. V0 y7 U; }" I. z
  27.    /**相似度允许值 0~64   
    ; W7 |+ z2 E4 b! e0 C/ |
  28.     * @access public   
    ) j9 H* u% u! p1 C- f/ K3 K
  29.     * @staticvar int   
    - j, S5 {  @+ K: }% x& i* V9 }. O
  30.     * */    ( u* t0 `/ Y! ?! n+ ^
  31.    public static $similarity = 80;   
    ; Y2 `! f" k+ T. m& q4 M
  32.     1 c) P- `% S. A/ w
  33.    /**图片类型对应的开启函数   0 P) `) Q( C, G3 B+ R) }6 m0 d
  34.     * @access private   4 z. L( c, }* G; N4 _% ^, j
  35.     * @staticvar string   
    ' K" p1 f" e3 o* i& ^, C( C1 m* V& W
  36.     * */    , u1 m" k. k+ D1 a: d
  37.    private static $_createFunc = array(    $ S  W3 {9 Z4 {8 M: u& O
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    , p+ R0 ]2 ?# E$ M' k% h
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    - k7 j2 y. Q% w8 T8 A4 ~1 j% @8 i
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    ' }/ T& ?9 G( w+ d0 x
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    & P; H, ]7 s0 P+ q; ~( D0 Z) r8 v
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    " A7 \3 {. r1 |$ x
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    * _3 i1 R5 f2 D; Y2 |! p% F
  44.    );   
    0 n( G- F$ Z: u
  45.    
    % a- P; ^# S2 w  h8 m
  46.     ) d( o4 P' e- o2 w& v
  47.    /**从文件建立图片   , I9 Q+ [! w/ k% E/ t# G
  48.     * @param string $filePath 文件地址路径   
    , @; x- C& |& q1 {8 ^- m- [
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   % }' Q0 r* K$ e; R
  50.     * */    ) k6 O3 a0 B0 r6 J9 U
  51.    public static function createImage($filePath){   
    % _) D7 F' S6 S+ [; p
  52.        if(!file_exists($filePath)){ return false; }   
    # ]' c! x3 z  h4 B9 P
  53.     6 R3 i2 y3 m1 e4 C/ j# w9 v0 m4 Q
  54.        /*判断文件类型是否可以开启*/    1 r! C) x: i4 _# Q' g
  55.        $type = exif_imagetype($filePath);    & {) A6 R4 Q+ C# p- Y% @
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    3 Y& u( P. S" O
  57.     4 {, v3 u: f7 L, I: o: t9 i
  58.        $func = self::$_createFunc[$type];      N3 R4 s' Z; M# a% y' A# V
  59.        if(!function_exists($func)){ return false; }    - P( ^, h  Y, }: `( |
  60.     $ @. n; [! B6 y* f) s
  61.        return $func($filePath);    ( B# N* y( T3 F5 {
  62.    }    / j. l2 i8 j4 y
  63.     , ?! j% B/ f3 y* d
  64.    
    5 x6 N9 A( t+ N$ t
  65.    /**hash 图片   
    7 V# Z5 `1 e+ t! F' |
  66.     * @param resource $src 图片 resource ID   
    - l- O& F% X: N, N5 k. R) J
  67.     * @return string 图片 hash 值,失败则是 false   7 t3 g4 p0 o8 D
  68.     * */    ( s  \3 Q' _) u+ {  G, o; x3 U' q6 j
  69.    public static function hashImage($src){   
    / C' R" n# l' C& C) F, V
  70.        if(!$src){ return false; }   
    + Z1 s# e: B6 @( l; x1 P
  71.    
    . {; I& s% y# @: @8 B2 J
  72.        /*缩小图片尺寸*/    : u3 @) f8 S8 E' b
  73.        $delta = 8 * self::$rate;    & S4 ]3 E. n: ^/ t
  74.        $img = imageCreateTrueColor($delta,$delta);    # C0 z- n( G9 x$ ^) W% Q6 Q
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    * k3 w' A2 y# s, R# R& {7 ^
  76.     ) ^3 q- H+ G/ u
  77.        /*计算图片灰阶值*/   
    , O6 Y$ M" y* v
  78.        $grayArray = array();      x: V- D5 @0 m2 D
  79.        for ($y=0; $y<$delta; $y++){    & S* ^8 r5 N5 W$ g' W
  80.            for ($x=0; $x<$delta; $x++){    ) V2 S7 R6 u1 G
  81.                $rgb = imagecolorat($img,$x,$y);   
    / l0 s3 \6 F: F9 }
  82.                $col = imagecolorsforindex($img, $rgb);   
    2 K" f/ z3 F; \' x& J0 k( X& e
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    3 P' {- }3 Z; f- u6 X0 w
  84.    
    2 ?+ p3 m5 E/ p
  85.                $grayArray[] = $gray;    - _( @1 [  o) `
  86.            }    ! |) W8 u2 o; K. t0 [1 k, B. t
  87.        }    2 {* W( i8 O6 V, w, H2 Q
  88.        imagedestroy($img);    , C) p% \, h# g" Z3 `
  89.     ( {; t7 D9 w! D/ _
  90.        /*计算所有像素的灰阶平均值*/   
    ' s0 p' x# J7 ~6 W0 O( B
  91.        $average = array_sum($grayArray)/count($grayArray);   
    6 L! x% _3 n$ m. B) w
  92.     1 K3 x; d4 G* u( U- {
  93.        /*计算 hash 值*/    - q0 Z- E2 ?" _1 D" K- K+ l
  94.        $hashStr = '';   
    , T; F% t; e) ^/ M
  95.        foreach ($grayArray as $gray){    ' z/ i3 p2 e* U( y7 D. M( n
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    ) x4 C! v. m( W
  97.        }    2 J; q' S4 K; k4 ]0 ^3 E
  98.     0 [- J( z) u& H  r' U2 A
  99.        return $hashStr;   
    + M, y& N9 c& \
  100.    }   
    . E5 o" y! E6 B0 u1 }  Y; Z7 o
  101.    
    - g9 O; f+ U$ O# P
  102.     # [* M3 b% L7 s, I1 i
  103.    /**hash 图片文件   % c& Y1 J1 q4 u3 K
  104.     * @param string $filePath 文件地址路径   3 ~1 [3 j  q' x: ^
  105.     * @return string 图片 hash 值,失败则是 false   
    : _5 Y! b8 W; l
  106.     * */   
    / d! b. e# K/ N0 I, ]: o6 @
  107.    public static function hashImageFile($filePath){    4 V9 l0 e/ z" z6 j7 G
  108.        $src = self::createImage($filePath);   
    & \# X2 D. I+ C: h& ]9 o6 o# j. L' h
  109.        $hashStr = self::hashImage($src);    5 n0 A) q- g0 Z5 m. U2 g) E2 t
  110.        imagedestroy($src);    - j/ x9 |* u/ U; h* X
  111.    
      [: K/ c- t9 k' T, \
  112.        return $hashStr;    , v4 E3 \0 N# R7 E4 v& g. B
  113.    }    . N- R1 ]$ R6 z6 }' Z: R
  114.     % t  q  t8 A7 R4 p5 p3 @
  115.    
    ( @1 o8 t; H2 c1 H$ z; L: l
  116.    /**比较两个 hash 值,是不是相似   
    + C# c( j4 `' [
  117.     * @param string $aHash A图片的 hash 值   ! U; T3 I( @! Q6 S& l0 \# c7 _
  118.     * @param string $bHash B图片的 hash 值   0 h- ]+ o: n% W8 G7 w$ e7 k
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    : O  U" Q$ r0 S8 R4 A
  120.     * */   
    2 E1 }0 a, d" a2 e) o/ M7 }8 ]
  121.    public static function isHashSimilar($aHash, $bHash){   
    % k! \; b% e* T8 l9 d
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ) H9 h7 D9 b  P, \& Q
  123.        if ($aL !== $bL){ return false; }   
    8 K* Q& k) d; N, `. ]1 ~
  124.    
    5 w* x) m4 v9 L" X7 X. I( p3 M
  125.        /*计算容许落差的数量*/   
    & ~# q$ T' O& d( a# B) r
  126.        $allowGap = $aL*(100-self::$similarity)/100;    $ t8 E( X  m# C4 P5 e4 \" _
  127.     ) B# L7 J2 D/ c
  128.        /*计算两个 hash 值的汉明距离*/    % ?2 [  A* W5 g( O* y8 a
  129.        $distance = 0;    ! o$ a3 H3 _3 }: x! }0 u
  130.        for($i=0; $i<$aL; $i++){   
      y! d: z0 V1 a: |3 l; b: N' e4 e1 s
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    7 X8 w$ a& t# e! g; G7 b+ n1 v+ k
  132.        }   
    ! ?+ I! {  K, k! h! m
  133.    
    8 Z9 D/ G! t0 c8 c
  134.        return ($distance<=$allowGap) ? true : false;   
    * {5 Y( O9 M+ i" K* n5 w; u
  135.    }    0 }5 T3 x+ b1 F! j! A
  136.    
    3 ^$ o0 q; z( v; R* L
  137.     + ~# r8 _7 o3 Y# f, l3 h
  138.    /**比较两个图片文件,是不是相似   $ a  r4 h0 K- j/ K5 E7 J0 _
  139.     * @param string $aHash A图片的路径   
    9 I4 |  Q+ n, d
  140.     * @param string $bHash B图片的路径   & J# a* @- b  Z* |0 R
  141.     * @return bool 当图片相似则传递 true,否则是 false   3 q% N9 V7 p/ i; S6 X! l4 K
  142.     * */   
    # h1 y6 b" |# U
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ' l; Z, C4 G: W0 R1 |
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    0 `) ?8 b0 F9 ]! S" W  \# b- A
  145.        $bHash = ImageHash::hashImageFile($bPath);    4 \5 q1 s# ?; @  H' T
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    7 q  j2 `0 I/ f
  147.    }    9 P1 G5 T5 @+ ^; u& h3 F& O6 j
  148.     : d( _8 F1 p( u0 R8 m# U; w
  149. }. H+ j0 e  o! N9 K/ L
复制代码

8 V7 ]+ Q& T7 S  h' t, v. u2 B3 _8 t) ]7 m! A, k
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:31 , Processed in 0.107344 second(s), 22 queries .

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