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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

) p9 f4 F! s2 }+ ]: {
3 N- n3 t- l" U  J: t
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
# l& m5 y$ F( g2 l7 G
  1. <?php   
    ' z8 H$ K( y1 Q( s# \7 K
  2. /**   0 g0 q$ W( Z* b% H0 @. g+ X* X0 g: ~
  3. * 图片相似度比较   
    , k" `+ ^5 ]  U+ Q! h( d: C
  4. *   
    3 W3 ~, X6 v( a1 d# d3 z1 E
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    % D0 |2 G  l6 l* q
  6. * @author      jax.hu     ^5 i; g$ C, F3 U# L  F' B
  7. *   7 T9 @/ r" K' T5 R3 t. F
  8. * <code>   
    ( L4 d1 f5 u# B% }# O( d1 K
  9. *  //Sample_1   , J* B6 k: f7 A, `
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    8 ]  I9 n7 S0 L1 {% [, d
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   0 q2 X/ e9 Y& A+ r% E9 i
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    . X' b' l. T+ {' }# W. C
  13. *   
    3 N% C; `( Q. w1 W4 P7 C
  14. *  //Sample_2   
    # m- X5 T3 N8 M! t6 [* S
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    : t% X! C  N+ G# t
  16. * </code>   
    % c- q7 P, o3 I1 I! s/ d7 J! A
  17. */   
    : j+ e) w7 K6 D% }3 c
  18.    
    5 _6 F6 W7 X' E3 M: y
  19. class ImageHash {    : R2 i: K% y4 J
  20.    
    : g2 k4 K+ _  B" Q0 g
  21.    /**取样倍率 1~10   . J  Y% M) C9 V* |3 S
  22.     * @access public   
    ( g( k; A8 i5 r
  23.     * @staticvar int   
    % [3 p9 N! o' T
  24.     * */    # j+ P/ I+ u7 j; r$ M3 P( T: q- ]
  25.    public static $rate = 2;   
    4 P8 Q$ p3 H/ q0 L" t! _2 ^6 X
  26.     ' ^6 h: y# l, {3 G: _- f  E
  27.    /**相似度允许值 0~64   ! S! t( `5 E- j& p, V+ w. }8 W8 Y
  28.     * @access public   
    7 m/ U  i/ W8 {. g( Q- j
  29.     * @staticvar int   ' @' a7 n% z( }: T- _5 n
  30.     * */    # Y1 \. H8 T) S( P. _" p
  31.    public static $similarity = 80;    " ?5 s" h4 l2 S- }3 ~
  32.    
    8 `& ~( _& Z& O! d9 Y+ L
  33.    /**图片类型对应的开启函数   ! r$ w5 `& v8 ~. x2 d
  34.     * @access private   - ?9 E& q- x8 R: s0 N9 g) X
  35.     * @staticvar string   
    : S4 }: S5 ~8 [; E) |2 U8 D2 t
  36.     * */    7 W0 R# T3 p' B. o
  37.    private static $_createFunc = array(   
    5 p4 O- t1 E, P4 v% C: [) |% ^
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ' n4 P! E/ S- o' U6 g
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ) |. t- W6 F- O
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    # m3 M$ @) M9 E& y/ Q, B0 X; V* }
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    4 |+ B" E" g% u+ `8 V5 Y
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
      J, g* @# f; i/ U
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    - H4 _8 Z1 K7 u% p9 ]3 a3 E! ?
  44.    );   
    " J' {7 e% m9 M/ \
  45.     6 }* |" x8 m( B2 H+ w. f# U0 x: x
  46.     1 q6 X* `- @7 W& b. T
  47.    /**从文件建立图片   - T, e2 K. u: m3 \; J
  48.     * @param string $filePath 文件地址路径   
    ! o7 k0 C1 V+ d6 q/ W/ D! v# K4 x! H7 e
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    " W, Z7 x7 k2 Z5 P2 D
  50.     * */   
    , w8 G/ Z' }8 l9 m7 y' j
  51.    public static function createImage($filePath){   
    # ^7 J$ h3 ^$ j6 v
  52.        if(!file_exists($filePath)){ return false; }   
    0 n% n- L! t5 R7 C+ u/ Y! U
  53.     . B1 `: N: h) X- Z# H
  54.        /*判断文件类型是否可以开启*/    ! b4 y; X( q  F: x% S5 d2 H$ Y! L
  55.        $type = exif_imagetype($filePath);   
    0 @$ a* H5 i) D: ]. ~
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    5 T4 T% w- A' X; O4 ?" w
  57.     $ e3 @: e) i3 |. Z9 Q4 u! V, y
  58.        $func = self::$_createFunc[$type];   
    " p. C2 G, @& G2 s
  59.        if(!function_exists($func)){ return false; }    2 h: X0 W4 P/ ?. b. Y% }
  60.     8 U2 }" |( _6 [+ K! L
  61.        return $func($filePath);   
    ) O, V$ Q" G- o+ H' s" Z- z
  62.    }   
    4 f& K1 L1 g" }7 v* y9 W3 H8 s
  63.    
    & w# _, b* O5 W/ ^1 Z
  64.     * U4 t! W: F' _3 i. }% `
  65.    /**hash 图片   ( U, e- o% R" w( Z
  66.     * @param resource $src 图片 resource ID   ) L. b1 L9 v) _- N% x$ ~; |
  67.     * @return string 图片 hash 值,失败则是 false   9 E+ T; Y. l+ N7 l0 x$ v; @
  68.     * */   
    9 K; E% C- o+ X7 T# j+ S) ?1 u
  69.    public static function hashImage($src){   
    3 k* S9 i' s$ l  x; ~
  70.        if(!$src){ return false; }    8 E+ r& }& Z4 N4 A# [) ~
  71.     / Z4 q2 k3 Y" |3 V, i7 H
  72.        /*缩小图片尺寸*/    # e5 F( k, Q3 t* I3 t+ H& M) P
  73.        $delta = 8 * self::$rate;   
    4 _7 K0 R( I4 a3 \
  74.        $img = imageCreateTrueColor($delta,$delta);   
    1 B4 k% Z9 I* Z) ]2 }2 i* ~  K% O( ^
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    & y, h9 r  V* A3 G  o, f2 ?8 \, V
  76.     1 T1 I/ I+ W& k9 Y8 P; p1 ]' |
  77.        /*计算图片灰阶值*/   
    ( C5 ^# k, i+ a1 a
  78.        $grayArray = array();    8 E# M; R. U- n/ U# a9 n/ J; B7 b. c
  79.        for ($y=0; $y<$delta; $y++){    " [& _* c, U+ t
  80.            for ($x=0; $x<$delta; $x++){   
      Y/ O8 a3 C& w
  81.                $rgb = imagecolorat($img,$x,$y);    # ^/ T$ Q- s9 u- }2 p% O
  82.                $col = imagecolorsforindex($img, $rgb);    0 |2 \9 j. G2 z" V- ^
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    # p( K* u6 @& m6 u7 O4 `& J
  84.     + g% G: @& I5 |% Z; S4 b- d, }' Y! b1 T
  85.                $grayArray[] = $gray;   
    ( a2 \3 }% {, i% p5 [
  86.            }    - Z5 h# A. k" H" e
  87.        }   
    ) \4 c: q! t+ ?. J/ p8 I$ v+ V/ l
  88.        imagedestroy($img);    + c/ A7 l7 ~, d$ a* v8 n- o: j9 h: U- [
  89.    
    : a& I/ Y! q* Y. j0 ]
  90.        /*计算所有像素的灰阶平均值*/   
    5 j# B, m9 t; J7 J& u
  91.        $average = array_sum($grayArray)/count($grayArray);   
    9 f! r3 ]7 ]! q
  92.    
    ( H/ d; y9 C2 i- O0 y( I
  93.        /*计算 hash 值*/   
    1 n# @! Z* s8 J
  94.        $hashStr = '';   
    % ^2 y2 r( \2 D+ _: A+ A
  95.        foreach ($grayArray as $gray){    9 {# S- ]- e: w  a1 p% i5 h
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    4 ]2 z8 R0 X5 C/ r# P. m9 A
  97.        }   
    + {8 H8 }$ w/ A. z- `
  98.     6 y' T; M3 [) \+ g# C% \
  99.        return $hashStr;    ; N  i2 y& @1 j9 _2 @/ V2 P, i
  100.    }    % @- k: T. ?1 T
  101.    
    : ^( H6 u+ E! }( x7 I  q
  102.    
    : p! S3 S2 Q6 T' X
  103.    /**hash 图片文件   
    9 e  Z/ u, c( @+ _
  104.     * @param string $filePath 文件地址路径   
    + t4 T7 ^* G6 Q0 x& `3 L
  105.     * @return string 图片 hash 值,失败则是 false   
    ' D& g3 ]" O7 N" o+ ^
  106.     * */   
    % z6 Y1 e% _( I0 W# z+ ?' c
  107.    public static function hashImageFile($filePath){    7 K4 f) Y( N$ E# ^2 q* T2 v
  108.        $src = self::createImage($filePath);   
    & C& L1 v7 ]) R, ?5 t. j
  109.        $hashStr = self::hashImage($src);    % P7 ^8 l; w+ b" E
  110.        imagedestroy($src);    ( O! q7 {) r! v5 u5 D+ }# C  [
  111.    
    6 n5 o! I. N0 G, c6 Y5 g# v
  112.        return $hashStr;    ) X& Y1 v4 P) _: }
  113.    }    % C/ Z/ d' Y% r* s
  114.    
    1 \" x* w6 r" a' `/ l
  115.       B7 }6 p, K& {- ?; D
  116.    /**比较两个 hash 值,是不是相似   
    : h- Q, }" F, o# ^1 o, M
  117.     * @param string $aHash A图片的 hash 值   2 i# @) }4 y) I2 w! u; b4 d, b: Y! }
  118.     * @param string $bHash B图片的 hash 值   6 p+ \. _4 j" }, C+ G+ u' A1 G
  119.     * @return bool 当图片相似则传递 true,否则是 false   + R9 H9 @/ D- @% ^- J# x5 Z1 t
  120.     * */   
    * n; ?' |: k! R# U- X+ T
  121.    public static function isHashSimilar($aHash, $bHash){    6 ~. z0 W7 Q' ]" v" a
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    2 [* [: {' w7 y: A' s
  123.        if ($aL !== $bL){ return false; }    " I: b. o" {) }
  124.    
    2 t' T7 g. H  W( g
  125.        /*计算容许落差的数量*/   
    0 H3 L" O/ W! v
  126.        $allowGap = $aL*(100-self::$similarity)/100;    / E+ T: s4 l: v1 j8 ~2 H. a; n
  127.     + m' H' v9 F6 P& K! P/ C- n- C
  128.        /*计算两个 hash 值的汉明距离*/   
    ' q: p; H' D0 e3 h2 q+ y
  129.        $distance = 0;    0 S+ }. z( w- n7 w
  130.        for($i=0; $i<$aL; $i++){   
    & T- T# E* b! k; z; M% q5 [
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    # L" w! G  p) A* z
  132.        }   
    $ G% @. n! G9 q* Y2 O/ L9 o0 j5 J
  133.     : a6 @8 c/ p2 d( B3 L
  134.        return ($distance<=$allowGap) ? true : false;   
    , y3 q7 g- w) E3 P, f
  135.    }   
      I3 }4 h/ [/ k/ ~  N! J7 R. ]- S
  136.    
    6 D8 b6 Y- P3 N0 H
  137.     0 p* Q' J# h0 s0 U6 e
  138.    /**比较两个图片文件,是不是相似   4 K) i7 w' T6 n: z7 Y
  139.     * @param string $aHash A图片的路径   6 u4 G* v. b# d6 S
  140.     * @param string $bHash B图片的路径   4 k, Q3 d2 \; {6 K2 v, ~
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ) }9 X7 m( ~/ p
  142.     * */    3 _  K7 A) B- F) \' t! ~
  143.    public static function isImageFileSimilar($aPath, $bPath){    . q+ T1 g5 ]% K8 |
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    , b* t" r/ {- w3 A) M' V: Z
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ' Z+ C: L. B( T! z8 B4 `
  146.        return ImageHash::isHashSimilar($aHash, $bHash);      I5 ?* N0 u2 a% J; p
  147.    }   
      b9 J- E" `6 J# D, D% q
  148.     ; B3 [, [9 [& M' T5 o
  149. }. \. M  [3 P" ^1 _  h% H" p5 @
复制代码

, U) T3 f! ?: V7 u% m7 D' m3 E! h6 j5 ^. l
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:19 , Processed in 0.052669 second(s), 19 queries .

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