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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

7 ~4 g2 d+ r  D& D  }
& ~8 A$ u% A2 c% L$ z* R% c$ G
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
. N3 m3 q3 h! Q1 j. d% M0 k% F
  1. <?php   
    ; E$ ]$ R+ E3 K5 [: O
  2. /**   : n8 B1 e/ {2 H
  3. * 图片相似度比较   ) P- L3 ^3 ~# C* [4 H9 c# R2 q
  4. *   ( _9 V7 Q5 r& H2 O3 A
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  * e% b) G; Z" W1 G5 w" ?" G
  6. * @author      jax.hu   7 ~0 l/ \4 d. \/ P; Y0 P
  7. *   . x" L" h1 s/ u: {6 f) c
  8. * <code>   
    ! F; W) e* o) C; t6 f
  9. *  //Sample_1   
    5 j0 J4 u0 W8 r$ j: h- P. i* ?
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   , U* }! E- O2 q
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   8 C4 t( R1 l$ l% b& g, ?8 m
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    - _$ v+ o' l7 W9 v; j% N! C* \
  13. *   
    3 L; _$ D  ^2 ]) {
  14. *  //Sample_2   
    / `5 p1 C  C  G! u" `" y
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   - t; }% t5 o9 Q
  16. * </code>   
    ) k0 S' a  H' `
  17. */    9 w0 X% Z& v, ~* Z
  18.    
    4 ]! T& N. X% Q  R' a1 b# R: T
  19. class ImageHash {    % ?0 {. G: }/ m5 `
  20.     " _0 R6 S" u, L' T: r# \- Y8 S) {
  21.    /**取样倍率 1~10   " {! z/ _/ m- v4 D7 d, @  n  A
  22.     * @access public   
    % H- t4 T* S, j3 r( D
  23.     * @staticvar int   
    . _( w% b2 [% r: C. P7 y2 v9 r
  24.     * */   
    $ w# \- R( ?' ?8 O4 l
  25.    public static $rate = 2;    ) _, N2 z; R6 Z6 b. `
  26.     - l" H/ G/ h1 S! i$ f6 K
  27.    /**相似度允许值 0~64   ( U4 Q' [4 l) Q" x
  28.     * @access public   
    1 m: B1 ~5 C5 ^
  29.     * @staticvar int   
    ! V' G: E  P( I8 F! B
  30.     * */    8 H/ _+ H0 u) X  n( A
  31.    public static $similarity = 80;   
    ; ]3 I1 u* \- P% O0 f8 R( `5 s
  32.    
    . K7 u$ d% z5 u* s9 L" R
  33.    /**图片类型对应的开启函数   
    / m4 o. W4 m) e4 P
  34.     * @access private   ) C" ~5 Q3 k2 j1 M; J
  35.     * @staticvar string   / Q# x! h" k- z, Y
  36.     * */   
    ' f% D  Y- I. Z4 p' n, @- t6 P
  37.    private static $_createFunc = array(    # @, B- c( y  t8 V. A5 y( ]
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    8 F. ~7 Z9 a( }+ I* r# O
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    . O' H, W6 S3 m) C  f
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    % l7 r; w% Z  U5 c; T9 _
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    : Q) E5 P$ e; B7 S3 h
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    $ K# L! W9 ~4 e
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ; P" L: i6 |& Z0 N' T6 @% r
  44.    );    ( G- l- y' R9 R0 N! `( O
  45.    
    - T( U) ~& @$ B& y) M
  46.     + `' U" B' A( k' c
  47.    /**从文件建立图片   
    ' L, N" T5 K" w6 P0 M, M
  48.     * @param string $filePath 文件地址路径   
    + M3 w* A2 z1 u4 ?7 c
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ; w* b, p3 \; G- b( m: t
  50.     * */    " i; V& v& n) l; L
  51.    public static function createImage($filePath){   
    3 S2 @; ?& S9 J" n
  52.        if(!file_exists($filePath)){ return false; }    : D0 ^; [5 ]0 c7 \8 S4 S
  53.     . {7 c  w: C' @$ j: F% L' P3 \' {4 Q
  54.        /*判断文件类型是否可以开启*/   
    1 C( ~" i& k1 ?6 F7 r0 w
  55.        $type = exif_imagetype($filePath);   
    1 a! j, }0 c1 o8 s! u/ k- X% e
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    1 C; X  H# O1 M# `4 N
  57.    
    & u5 |( d% f7 E) A' N! E# z
  58.        $func = self::$_createFunc[$type];      c0 |+ a: @  }7 @- c% D- i
  59.        if(!function_exists($func)){ return false; }   
    # @1 K% `) Y; M' n( G
  60.    
    $ y0 \+ b# B4 W+ v; @
  61.        return $func($filePath);    ' n% D7 ^5 ?: K8 c
  62.    }    " l% W1 [/ T/ I$ ]  u4 Y: d
  63.    
    ) ?/ t0 i; N) Y! s5 _) p0 n- I
  64.     ' a& O+ x/ E) E) D5 u% @7 ?
  65.    /**hash 图片   / G6 H( p# b" W1 m* c( p
  66.     * @param resource $src 图片 resource ID   
    ! H* R4 [, k- S8 m, P
  67.     * @return string 图片 hash 值,失败则是 false   
    + n! D+ e5 u. D" f8 r' d
  68.     * */   
    - z4 Z$ D: T" s& r2 \
  69.    public static function hashImage($src){    - Q3 ?( p5 t6 q; u' R8 F
  70.        if(!$src){ return false; }    # n* F5 h  r3 \  O7 y- F
  71.     : h- f( P% ]+ s% F# ]4 h( q
  72.        /*缩小图片尺寸*/    4 W- w3 e- t/ q  v' x) j; a
  73.        $delta = 8 * self::$rate;   
    3 ]" q. s$ A& m) D
  74.        $img = imageCreateTrueColor($delta,$delta);   
    4 ^5 c) D' p3 Z0 l! B; x: B
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    . P1 z/ a$ u- E/ C! e" P3 V
  76.    
    ( g8 g  }( x; Q0 v0 U' B
  77.        /*计算图片灰阶值*/   
    . ?- o4 L8 |- P" R+ T# V7 D
  78.        $grayArray = array();    5 c. d% t5 T6 `; M4 U2 N$ }' d
  79.        for ($y=0; $y<$delta; $y++){    ! @$ y0 C9 F8 J3 c
  80.            for ($x=0; $x<$delta; $x++){    3 ]% J' b( w* @' w5 [
  81.                $rgb = imagecolorat($img,$x,$y);    , f6 n$ \; X! x: u/ g. F
  82.                $col = imagecolorsforindex($img, $rgb);   
    ' H! |) |+ S5 r2 Q! O# Q
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    # L# ~+ P  s0 P
  84.    
    / }, g5 e! K4 y% f) O2 V. i
  85.                $grayArray[] = $gray;    - F' n' d+ I! {$ i  G: J
  86.            }   
      l1 Y: F2 |" K* x; Y6 ^
  87.        }    3 \5 H; C2 J* j" g/ C2 ]
  88.        imagedestroy($img);    * u6 r- f: m7 H( {6 E
  89.     ( {( G3 _/ V* t7 h" Y
  90.        /*计算所有像素的灰阶平均值*/    8 `$ W  d' o' e0 }
  91.        $average = array_sum($grayArray)/count($grayArray);    . z7 `# q) u8 a* l1 C
  92.     7 t0 k7 M+ j+ D: G
  93.        /*计算 hash 值*/   
    $ V7 b0 p9 t" x9 P/ Y& t, J
  94.        $hashStr = '';    9 @% M# X: k  C, d3 n' T
  95.        foreach ($grayArray as $gray){   
    7 }- G* g. B% p" R, U9 w, U
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    # O( P3 x! f3 v, Z4 r* A
  97.        }   
    4 N. P/ W% F. p8 c
  98.    
    " p! Y( d8 u: T3 `. u9 X, U
  99.        return $hashStr;    , z* |0 T9 k( |2 {/ I  e, L
  100.    }    - ^3 Z4 J' y$ O# E- _1 p5 t
  101.    
    ! ?; ?1 U, k" E' T
  102.    
    0 c: Q0 ~) t2 }2 b8 g8 b
  103.    /**hash 图片文件   6 V/ j6 w) r5 q" Q
  104.     * @param string $filePath 文件地址路径   5 I" W/ z& J: B) m( V' j2 |! a
  105.     * @return string 图片 hash 值,失败则是 false   2 s2 ^3 }/ D  K% x
  106.     * */    / t6 C# _3 w* a0 V' |& g# K& [% M
  107.    public static function hashImageFile($filePath){   
    1 [! @8 J) }" |
  108.        $src = self::createImage($filePath);   
      Z% @3 a' l1 c/ k9 S
  109.        $hashStr = self::hashImage($src);   
    - L/ [5 L' p& |2 B% y$ t( o4 ^! P
  110.        imagedestroy($src);   
    # S9 @# a, C. z8 O* L7 Y" \
  111.    
    ' Q3 z' O  [8 G0 t, r, B, I2 \: \
  112.        return $hashStr;    ; ?/ h3 Z5 y1 b7 N8 ^  [
  113.    }   
    + ^# i! g3 v3 {$ J9 s1 r4 m
  114.     7 n; Q0 Z" s  ]: [1 P; T( h
  115.       s1 ~* D% a& H) b
  116.    /**比较两个 hash 值,是不是相似   $ K. T7 N8 z6 M
  117.     * @param string $aHash A图片的 hash 值   ' q& ~9 @2 n) ~8 o' r
  118.     * @param string $bHash B图片的 hash 值   ) q& d! h! R" }  @
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ; I' l$ q, w, q/ G. y7 \  f
  120.     * */    8 b7 O( m! t( k
  121.    public static function isHashSimilar($aHash, $bHash){    " A" |. C5 g& N. e' y1 X
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    + L1 ~1 z, t& k9 F
  123.        if ($aL !== $bL){ return false; }   
    " m8 {; @- r; k+ j: S7 z. q. c" o
  124.    
    ; h) o; D1 @4 G: V+ p( H
  125.        /*计算容许落差的数量*/   
      l0 e, }" ~/ K' k$ B1 `8 z  P
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    9 b( \0 }3 K! L
  127.    
    & B$ E# @- C! [7 n" m! H! D' c0 v2 M
  128.        /*计算两个 hash 值的汉明距离*/    " A4 m, f; L& Q+ J2 S
  129.        $distance = 0;    ( v' D2 ~' K4 V/ c. W
  130.        for($i=0; $i<$aL; $i++){    1 V+ T, V, q' r6 `) w# \0 O
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    : F; y# f% ^; g9 S, s$ v8 C8 G
  132.        }    4 `1 R- k6 }$ v
  133.    
    + Z2 ]3 R" `. U. s) A  x# d
  134.        return ($distance<=$allowGap) ? true : false;      n/ O  U9 @' E" H  u
  135.    }    5 {: E& h) e* x* A( F
  136.    
    4 M+ d* S. }% p6 J8 \' C# g
  137.     4 j$ o3 F! x- \
  138.    /**比较两个图片文件,是不是相似   9 T" ~" K2 t0 h+ Y9 d2 a; f4 D
  139.     * @param string $aHash A图片的路径   1 `3 G) d2 Y: y# s
  140.     * @param string $bHash B图片的路径   ; l- _9 v/ l! h- _9 f7 t: p. h, \
  141.     * @return bool 当图片相似则传递 true,否则是 false   5 n, E1 [* z7 s( B: g$ G# [
  142.     * */    2 E  j/ P8 I4 z; x) U- e5 g
  143.    public static function isImageFileSimilar($aPath, $bPath){    ( }# L1 I/ @* p+ M* L
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    . \8 j& I" h- X6 m9 a$ q5 [3 R
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    2 _5 u) N& O0 d/ b5 O5 O, ^/ W
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    # a  u2 n  U' N2 X! a
  147.    }   
    / J" |2 c2 J8 T. R
  148.    
    9 O  k% u" P$ L
  149. }
    5 F8 {3 {- R* n( g4 {% ^
复制代码

3 E& v* H, J- I! ~9 `' T3 Z5 {4 B" T6 ]% b% L2 Y8 ?/ W
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:24 , Processed in 0.052644 second(s), 20 queries .

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