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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
$ l+ a- \: w/ M2 v3 W- F+ _( |  R& u* F$ E1 m9 _
4 ?5 n, B% S. L+ H9 m
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

  r3 L0 E* |5 p
  1. <?php    4 K! X5 ?) a" H$ Q* N* p
  2. /**   $ a7 U- Q# N. S3 N" x& c
  3. * 图片相似度比较   
    " p$ W7 p. _$ i' s
  4. *   
    * c1 }! F- l) F6 y
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  1 W% y* v3 `* ~3 r% c6 C- I* V
  6. * @author      jax.hu   
    0 ^$ N# a6 l/ `/ M% D% c
  7. *   
    % d; W! p# {4 i" y- U# t* b
  8. * <code>   % n; y$ q2 q* d0 E7 k7 Q* F. {0 P
  9. *  //Sample_1   - s! o; @) Y- p7 Q9 w( I) U8 \
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   4 ^: g' d0 u' F2 R7 B
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   " r7 N) w3 y; O
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ; G( x) M  R' x. z' g7 u8 _$ b3 ?
  13. *   
    ( o- a. G7 P& ]) H$ f; ~( T
  14. *  //Sample_2   
      G& s0 N0 V, F0 I1 U( N+ v
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));     |% c  H% d: G$ u
  16. * </code>   ! R; l9 v5 ?2 ?) q- `; g  N
  17. */    % D, h  T( ?, T4 e8 ^+ t
  18.     6 ~, |6 T% R. |+ ~$ x
  19. class ImageHash {   
    " h6 C- B1 {$ F  M/ O  V7 ]  x# K; M
  20.     * |$ A0 C5 S; h/ q- X& P
  21.    /**取样倍率 1~10   . x6 q* t4 l9 v' e) O# j
  22.     * @access public   ; b7 A* Y/ u8 D. t+ ]" v1 p
  23.     * @staticvar int   
    $ B1 c8 s! p4 Q  \$ C% u; m
  24.     * */    8 _2 C8 [8 Q5 N; S: J
  25.    public static $rate = 2;      e8 p1 S+ T( X1 n9 u
  26.    
    8 W. M+ e( s/ J1 c. n
  27.    /**相似度允许值 0~64   ( z8 b6 _2 e3 n4 Y( k( X
  28.     * @access public   + t$ L6 C$ z9 \. q# l0 J
  29.     * @staticvar int   6 F; g: m8 v' D) w& }: U% m
  30.     * */      @& }: i* a+ _* M. T
  31.    public static $similarity = 80;    3 I; _) [: [$ j3 I( A
  32.    
    4 v5 L5 ?& d! I
  33.    /**图片类型对应的开启函数   
    ; v4 J5 ]6 o& j, O$ O
  34.     * @access private   ; c% f! O2 A' d7 M
  35.     * @staticvar string   7 Q# J4 Z# a% l0 f2 H/ N
  36.     * */   
    * P! `. X" K9 }# t" c- i, U9 Q
  37.    private static $_createFunc = array(   
    - o5 _# V) Y2 L3 J) B& ]/ ]
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    - }. F7 b/ O) F- `: o
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    % t) n: B  B% E" c- I) G
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    4 Q) G$ h& V. F
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    . e# ^9 e1 t8 _5 O0 g- t9 d
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    # ^- |. o& d! \" n
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    8 L7 m: f. l5 T6 b
  44.    );   
    - k. r9 B6 `' l( e
  45.    
    % G) m* d+ s! x3 F3 |
  46.     ) N3 n. G. U# Z* ^2 @& Q
  47.    /**从文件建立图片   , _3 f2 V1 p, Q0 f
  48.     * @param string $filePath 文件地址路径   , z5 T6 n+ T. ?2 C3 t3 @0 A
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ( U9 r! e: _: Q6 Y* V  x( y) u
  50.     * */    " x/ R0 {6 H2 [: I0 x1 [( ?/ L
  51.    public static function createImage($filePath){   
    ! Z& [% i3 @# Z5 a
  52.        if(!file_exists($filePath)){ return false; }   
    5 o) F* c) w, G
  53.    
    . o7 X7 d, r7 ^
  54.        /*判断文件类型是否可以开启*/    $ r6 M. A% V( @1 w! U% x
  55.        $type = exif_imagetype($filePath);   
    ! D  t* m) Z$ [% J
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    ; z% ]& ^* S: O6 [/ p5 d6 f
  57.     " C0 [' G9 E2 y7 Z' E
  58.        $func = self::$_createFunc[$type];   
    7 s7 @* ?2 w: ]# W8 `
  59.        if(!function_exists($func)){ return false; }   
    4 F' a! [1 w  s; U: k( l" u
  60.    
    ) h3 F' L" k: a7 _
  61.        return $func($filePath);    2 Y' \/ J. M* S5 d; D
  62.    }    $ m# X& i3 p! z
  63.    
    1 p+ U# {5 C: \7 _
  64.    
      Y( _& w7 o: H- F, u  k# N7 b
  65.    /**hash 图片     i6 H! U' B% T) F5 }' B5 }9 _+ S4 \
  66.     * @param resource $src 图片 resource ID     X' e+ G" {! I7 i
  67.     * @return string 图片 hash 值,失败则是 false   
    " o- m  X7 ?. V9 Y6 c% a6 [0 D, q
  68.     * */    ; [; R' @7 C% f/ v) t1 f
  69.    public static function hashImage($src){   
    & n2 G" o) A; R" S; f! S- m
  70.        if(!$src){ return false; }    6 r! t" k$ G! R5 s2 l
  71.    
    7 h. B3 z4 p  j- b
  72.        /*缩小图片尺寸*/      e% Z' H3 M+ D7 z/ o% R
  73.        $delta = 8 * self::$rate;    * M; I- ?( O7 H' O# f- i
  74.        $img = imageCreateTrueColor($delta,$delta);   
    " u" r7 x# V) S
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    1 S3 n. S/ E0 {" U% L! N; Z( Q+ I
  76.    
    - r5 l# X) j/ o7 r' m8 ]0 O. H
  77.        /*计算图片灰阶值*/   
    4 d3 i( O" l& O3 k# z8 h0 D2 {
  78.        $grayArray = array();    9 [8 p& Z& c( a9 c& H- j# H
  79.        for ($y=0; $y<$delta; $y++){    , K! H9 n4 g7 \6 ^8 \. C% G
  80.            for ($x=0; $x<$delta; $x++){   
    ; O& `# m1 a& i
  81.                $rgb = imagecolorat($img,$x,$y);      n8 V% S3 c6 ]6 W, J
  82.                $col = imagecolorsforindex($img, $rgb);    + e# F4 k! ^( a- V- i
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    . q0 [* w9 M8 M# A5 G9 \
  84.     2 F2 q1 D: s( Y' O: `) G# R
  85.                $grayArray[] = $gray;   
    5 o8 F$ A, f0 B2 {1 L0 A. [, R2 |( I' d
  86.            }   
    ! [1 j+ _# u# D+ ^. U* j
  87.        }    $ e: _' |, S) a# i6 |% ^& ~
  88.        imagedestroy($img);    $ r& s4 y; ^3 F# x1 M5 V
  89.    
    9 [! M, K) @- a/ r% l5 m3 S
  90.        /*计算所有像素的灰阶平均值*/    4 Q% C: Q7 d! I4 a  O8 t2 E
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ) b, ~6 Q0 i6 m0 X) P2 s0 {
  92.     0 F" R! u/ i' E
  93.        /*计算 hash 值*/   
      c2 c& i8 L' M6 O8 C! p, S& a
  94.        $hashStr = '';   
    & R8 Q: I, _% E* x+ D
  95.        foreach ($grayArray as $gray){   
    1 P- }- D- g2 _& _: o5 I; k3 l9 X% f
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ' b6 t- c/ M" }
  97.        }   
    ' Y1 o: k2 D9 `, n, O
  98.     - z0 ]* b( z8 t
  99.        return $hashStr;    / {1 g% @4 D2 d
  100.    }   
    2 n- v% i  P( X! u/ i( `& z) k
  101.    
    ) {3 h' b# i" Y  M9 R9 n: W  `
  102.     3 w, p) L7 P! {  O. |* B
  103.    /**hash 图片文件   - _  j# g0 v$ N* N7 \& _
  104.     * @param string $filePath 文件地址路径     @4 v7 c+ ~' a1 u2 J0 A, J
  105.     * @return string 图片 hash 值,失败则是 false   
    4 R. [, p. k- Z, g
  106.     * */   
    ! W% ~5 u( M# S' |! p$ w) i2 l( s
  107.    public static function hashImageFile($filePath){   
    5 L/ T& l2 k7 }# v  t
  108.        $src = self::createImage($filePath);    , }: \" S; v5 z6 Y! p2 n
  109.        $hashStr = self::hashImage($src);    ; N% K1 J  y. a3 p
  110.        imagedestroy($src);   
    9 l$ B1 N: x; D4 a1 Q" S1 m) @$ W
  111.     / I7 a. n1 p9 V& v1 O
  112.        return $hashStr;    3 {, J/ z% D" G- [
  113.    }    4 ^  x+ |, |& H
  114.    
    " m. r+ h: E8 I! s( p1 \
  115.       @3 U1 @; h. I' O8 [; {9 Y# P- s
  116.    /**比较两个 hash 值,是不是相似   # N7 M4 }$ |% h4 B' R. H
  117.     * @param string $aHash A图片的 hash 值   
    3 c6 {, z$ x4 X2 K6 a$ V3 A) F
  118.     * @param string $bHash B图片的 hash 值   : p1 n0 K. v! I' w# o
  119.     * @return bool 当图片相似则传递 true,否则是 false   + \5 W! z. E0 V2 S
  120.     * */    5 ^3 U0 ^! O8 u; ]! h: }" X
  121.    public static function isHashSimilar($aHash, $bHash){    ) g+ I: E2 Y4 f
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    6 f# x% l0 _9 [! Q
  123.        if ($aL !== $bL){ return false; }   
    $ |$ I" B8 y# |- k: m/ u5 j9 @
  124.     : g" Q5 J8 k. ~
  125.        /*计算容许落差的数量*/    1 d1 n5 \! h  E% z' ^# Q* m, H
  126.        $allowGap = $aL*(100-self::$similarity)/100;    $ e+ _+ C- N) h% o8 W' W+ C1 R
  127.     3 a! u) N% t1 o  ~% e
  128.        /*计算两个 hash 值的汉明距离*/    - D8 N# c1 c1 _; e+ ~8 @
  129.        $distance = 0;   
    % n* B/ B* g* G7 `4 t5 W0 s% B
  130.        for($i=0; $i<$aL; $i++){    : y, W4 F1 u9 o% |# F
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    + {( F. x* c5 e4 y5 L. j
  132.        }    8 \+ L% L$ s4 {& G5 k2 R) t
  133.    
    ; w. ?( R- S$ h" F  d# j: e+ \+ `
  134.        return ($distance<=$allowGap) ? true : false;    ; F) v/ t+ }2 p
  135.    }   
    ! |8 |( k) y- G: B; o/ c
  136.     ! ~  V0 }5 q7 C1 f
  137.    
    2 z2 q  o$ P- y6 w$ c" X2 b
  138.    /**比较两个图片文件,是不是相似   
    7 ~1 k& e6 o  [+ d
  139.     * @param string $aHash A图片的路径   4 w2 z- p( n, _0 e
  140.     * @param string $bHash B图片的路径   ) Q/ c9 q" \. N& k: X3 u
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    / k! U/ s( x$ i. l. \& w/ U' ^" C; P
  142.     * */    - S: {6 j% e+ s. X: J
  143.    public static function isImageFileSimilar($aPath, $bPath){    4 l$ C7 U" u. ^) _2 e
  144.        $aHash = ImageHash::hashImageFile($aPath);    1 z$ M9 }' ^2 n0 U1 J
  145.        $bHash = ImageHash::hashImageFile($bPath);    * p$ [( W( `2 K- M: J( J: b( ~2 h+ u
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    . R7 U: O( E& r
  147.    }   
    , p2 y$ g! i7 ^: G
  148.     9 a% V# g3 H  Z; L6 h% h
  149. }
    , O$ G4 i; s' z& v$ e
复制代码
; I- {1 r0 @5 J+ v; f5 i! `0 t

/ t. v* [0 i+ D3 t( x" g6 J; Z/ c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 22:04 , Processed in 0.084818 second(s), 20 queries .

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