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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" ?/ g2 E$ h. A3 z由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
2 W1 _3 R9 O) Q" P/ O4 ]
  1. <?php   
    # p. I' G& r* G5 X3 z3 R- @- \
  2. /**   4 J! ]& g* Q* p
  3. * 图片相似度比较   , d' F9 F  n; q8 _. G8 F
  4. *   
    8 _" W1 x4 S% i9 e0 I7 m* H, |
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  5 W1 K3 {' W8 t1 c' @5 B
  6. * @author      jax.hu   : Z8 k3 ^- C* l: R
  7. *   
    1 @' E2 @+ g. `( c/ I
  8. * <code>   
    1 U8 m3 N/ O# @7 h/ C- y! \
  9. *  //Sample_1   7 e+ D: G$ Y6 V0 a) l4 d8 S+ {
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   + u8 m/ d: O$ z9 A6 a& k
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');     l0 \! b: {, e: v1 C. j* w. E
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));     |- `/ Q; E- }/ c8 U: h0 o( _
  13. *   
    3 r3 I- V: L7 w1 N2 E& u
  14. *  //Sample_2   6 g4 K9 e1 i7 o, f
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    ; [- o& ^; E, P: l" @; U( _2 F
  16. * </code>   
    . n% r) r1 |" o% P* N( n% M4 \
  17. */    ; `: ]+ n$ y. n; h! C
  18.     9 H8 R# n; ?& `" N) P5 r
  19. class ImageHash {    5 H7 e( _, ~  V8 S  |
  20.     ' s" V. o  L2 x+ q0 ]
  21.    /**取样倍率 1~10   , P% [9 z) |$ q- }  D
  22.     * @access public   ; P: a! \  a9 v$ I, R
  23.     * @staticvar int   4 |* P% [5 w3 w( r+ z1 g
  24.     * */   
    ! `) x1 n2 J5 v, ~# o
  25.    public static $rate = 2;    8 q" t+ D/ p( B! K- j( w
  26.     7 {. W; |2 _7 f, ^: m' ^8 y" q
  27.    /**相似度允许值 0~64   , i3 Q. X& \+ ]+ p: p4 @
  28.     * @access public   & k. {8 n8 K0 p7 |
  29.     * @staticvar int     U3 x8 @* }  f1 J; c
  30.     * */    + p2 I0 G& k% h5 y$ T
  31.    public static $similarity = 80;   
    3 n7 C, w  X$ f7 W: {! l
  32.    
    * h3 u& q' F4 l
  33.    /**图片类型对应的开启函数   0 }' t1 p: M# g* ?( \2 P
  34.     * @access private   
    7 Y/ f) ]% [# }7 ]) C; o$ Z9 \
  35.     * @staticvar string   
    * d6 y, g5 J5 b
  36.     * */    + f9 h) t) |) {; N9 x& F; W0 ]
  37.    private static $_createFunc = array(    - c: i2 U- v5 m6 h& D2 ?9 W( D4 `8 J
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    # D- G) x6 G  _/ Y# D, M  M
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    & |( Z% j- A3 d3 Q7 Y3 P7 b
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    $ M' G( N1 I+ H" T8 J2 `2 D9 R6 a
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    , i" Y) a/ X, N* [/ o6 D. K6 o
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    % Q8 t0 S% a1 h* {, ]9 |
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    / K" Q7 Z, A0 @$ m
  44.    );   
    6 ?$ P. ]6 V+ A6 E$ O7 u
  45.    
    % Q; m4 ]! O; G8 F- Z/ u
  46.    
    ) s! r7 s7 I: J( E1 [
  47.    /**从文件建立图片   
    ) i4 z9 D* o: O4 t- h$ Q
  48.     * @param string $filePath 文件地址路径   
    % p  Q$ ~, ~. [8 l
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ) B. H4 Q; i4 i  Y
  50.     * */    + B5 b  s: f) ~
  51.    public static function createImage($filePath){    # T6 d) S, F. d, G9 X
  52.        if(!file_exists($filePath)){ return false; }   
    * g! S  R! i  S/ i& I9 a, @+ Q! U
  53.    
    0 l! B9 J- [' `# H. h
  54.        /*判断文件类型是否可以开启*/    9 L% O  I2 [  V- |* K% v
  55.        $type = exif_imagetype($filePath);    . x9 @8 t9 D! \! H( b) h
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ; f) I/ P. N, Q( D" y
  57.    
    / Y: a1 u. @! g# {  w
  58.        $func = self::$_createFunc[$type];   
    - M1 M7 x/ j6 {4 J$ x7 w9 n
  59.        if(!function_exists($func)){ return false; }   
    2 p* a- C; v( c3 z1 a& x7 e
  60.    
    4 `7 ?/ {1 W0 j
  61.        return $func($filePath);    . N3 h- G( d0 c
  62.    }    ; I; m' m  [3 P9 I' i, j9 Y
  63.     ( g& y5 V3 {! R
  64.    
    ! J8 ]( O! a" M1 s* w
  65.    /**hash 图片   6 Z$ V, z4 d* f; ?, i
  66.     * @param resource $src 图片 resource ID   * e& {1 j# i# A5 d9 }: u
  67.     * @return string 图片 hash 值,失败则是 false   9 U$ x/ [7 s0 d/ x, r+ G) j9 k, K
  68.     * */   
    0 ~4 K5 o8 v: b% O: a5 f* d  I8 \5 i
  69.    public static function hashImage($src){   
      z: y+ {- ?7 w+ j
  70.        if(!$src){ return false; }    0 }: z, U: A- e) \6 m( C+ @3 X
  71.     + q  R$ ~& X4 Q; x. b
  72.        /*缩小图片尺寸*/   
    # `- C+ k, j* U' k3 q" L" u% q( j4 L
  73.        $delta = 8 * self::$rate;    5 _3 K/ v9 g* r, g- v4 P
  74.        $img = imageCreateTrueColor($delta,$delta);   
    4 t2 A0 ]% w7 P& k1 Z
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ! L1 [5 x6 }$ U' ~3 U- i  }  V
  76.    
    & @$ r9 e! i7 y  _
  77.        /*计算图片灰阶值*/    " W: N; e6 l; U) I. h! A6 S
  78.        $grayArray = array();   
    # B, s9 c2 A3 S0 d8 n: S9 ]
  79.        for ($y=0; $y<$delta; $y++){   
    + _& P; y$ E3 q$ c& ]) U
  80.            for ($x=0; $x<$delta; $x++){   
    / z0 c& \  |* r& x/ l6 [( j
  81.                $rgb = imagecolorat($img,$x,$y);    $ i) X( A2 T! `; g  m8 Y3 W
  82.                $col = imagecolorsforindex($img, $rgb);      j6 f' [' p% }+ w
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ( {, W9 |4 r! y9 W
  84.     ' \, q1 s) k" _5 M3 V
  85.                $grayArray[] = $gray;    9 T3 F  @  V3 ]( p; q3 m+ y" K
  86.            }    2 L' r- a, V4 f( n6 Q
  87.        }   
    7 m7 v( h% E! [: j  q: z8 B4 m$ T
  88.        imagedestroy($img);   
    : ~, ~$ q4 W2 F/ U' w, n
  89.       \' @2 @) {0 U8 q$ P8 ~: v$ ~
  90.        /*计算所有像素的灰阶平均值*/    $ w( W, l  S2 v0 F
  91.        $average = array_sum($grayArray)/count($grayArray);   
    " O; M, z$ _$ S* u8 N! M, U  Z5 R
  92.    
    6 H. s5 k; [/ `9 l" `( }2 h3 C
  93.        /*计算 hash 值*/    5 Z1 V: k% w5 `; e7 p* D
  94.        $hashStr = '';    2 F% K+ q) k8 E) y
  95.        foreach ($grayArray as $gray){    5 T4 G9 L1 N6 E& I; J
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    6 p8 i3 E6 m+ c4 z- O: i2 ?3 f4 k& B
  97.        }    2 K) v, W% i% \' o$ |' h
  98.    
    ( N' ]6 y$ R; m6 Z) l
  99.        return $hashStr;   
    5 u! j1 O1 w3 ]$ f
  100.    }    9 ^: B9 v! T3 H% K
  101.     - C, s3 B2 x% W4 N0 l( U
  102.     & @/ r: z- A6 y" `% E, _9 `
  103.    /**hash 图片文件   ( M. _" i7 p+ [( @$ L. V3 N+ t
  104.     * @param string $filePath 文件地址路径   
    1 ^4 V( v" m' L8 r: ?
  105.     * @return string 图片 hash 值,失败则是 false   
    ; O: T2 K! z, D- U3 e/ \
  106.     * */   
    3 O# i/ {5 I4 G% B; J; C5 q! ?. a
  107.    public static function hashImageFile($filePath){    " z0 a1 A* J; F
  108.        $src = self::createImage($filePath);   
    " {, Z. K- h8 n' k- m7 R
  109.        $hashStr = self::hashImage($src);    1 ^2 w: z, g& }+ j- U# A/ O
  110.        imagedestroy($src);    & P( u8 |. o1 K6 x
  111.     4 X0 k! w( U: [+ N4 q* ?, `) V
  112.        return $hashStr;    8 x  F# _0 T2 ?3 w  u
  113.    }    $ m. e4 O# X8 _8 a2 n4 g4 t
  114.    
    1 w5 _/ u6 u. X5 J& B1 v$ b& x7 \* @
  115.     2 ]7 B! O! `* x
  116.    /**比较两个 hash 值,是不是相似   2 s: Z8 Z( G' L! {
  117.     * @param string $aHash A图片的 hash 值   
    6 w0 ~! b2 y& m8 O
  118.     * @param string $bHash B图片的 hash 值   
    + t. b% {+ N9 ^" k
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    & \: L) L3 @( i$ c7 Q* [
  120.     * */   
    6 l8 @! [6 U  X6 B1 q  y
  121.    public static function isHashSimilar($aHash, $bHash){    & ]7 w" H3 a1 W; S/ S& u0 ^
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    / J* {% A- H! W5 b- l
  123.        if ($aL !== $bL){ return false; }    " B  O' k1 A4 y4 d9 |
  124.     - I. e  m2 k6 T5 s
  125.        /*计算容许落差的数量*/    2 x- n2 x/ i2 r1 e3 v2 Q
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ( J: Q7 O: |& {; }
  127.    
    & y8 H$ S) D& S3 `$ m2 C7 M
  128.        /*计算两个 hash 值的汉明距离*/    9 {+ _7 f4 ~# L% {: C6 S
  129.        $distance = 0;    ! A9 z/ h& {9 K" ^' _
  130.        for($i=0; $i<$aL; $i++){    % d; a1 w! Z: X% v! g" k
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    & t8 u7 D9 l' }" P5 z$ w
  132.        }    . @% ~0 b$ w% Z: P
  133.    
    8 p9 r' \/ u/ D) }- D% Y. }
  134.        return ($distance<=$allowGap) ? true : false;   
    ' @& ?- J& b3 Q. z0 P# M" v
  135.    }   
      w; i1 F9 S; k. n% |: b
  136.     0 u! h7 l3 E- [7 M! c5 F
  137.       S. O$ ]3 r; J+ n4 }0 D
  138.    /**比较两个图片文件,是不是相似   
    % V' T1 n; v' H' _+ R
  139.     * @param string $aHash A图片的路径   7 T5 q- d! J" I' ^
  140.     * @param string $bHash B图片的路径   
      }9 E$ K5 e4 h9 Q. ^
  141.     * @return bool 当图片相似则传递 true,否则是 false   : F/ q8 g* Z8 E6 i
  142.     * */   
    1 t* O5 {! r  C8 P' ^$ Z
  143.    public static function isImageFileSimilar($aPath, $bPath){    8 N* i/ [6 J8 u1 K9 P
  144.        $aHash = ImageHash::hashImageFile($aPath);   
      p0 k1 b: F! ^, ]3 L3 x* s6 S/ ?
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    : \( j; i- i8 Q  B9 j: @  r! B- O
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    . v4 Y: N; P' T* [, t; v
  147.    }   
    ' o# u8 _$ x: ?! ?5 n! r6 ]: R$ R
  148.     1 B* p6 n6 w5 u
  149. }, R, |* V* B) g( u! K) G. L
复制代码

" W* _0 N& b0 Q7 K
* ?! F6 t, l, v4 Q. P
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-20 17:44 , Processed in 0.057084 second(s), 19 queries .

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