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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
& e9 l0 D# y: w3 N( M& J5 o5 c7 u- p2 P" f9 A. M7 n7 m4 z
5 g3 Z. I6 G0 e% ^! M: X2 X
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
7 w7 `; j# u) }' i( \: t
  1. <?php   
    # h/ O* p! `5 I7 r( n
  2. /**   
    / k4 N6 D- z- B
  3. * 图片相似度比较   & D- ?* t) e  [8 D+ b7 i: n
  4. *   7 i7 V* m) r4 o2 ]8 [
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  8 g; m+ T0 s- E" v4 D$ k0 L; K
  6. * @author      jax.hu   1 S9 E2 `  p! p+ \4 F+ O
  7. *   
    ! f7 S1 Y5 G- U! Y( C. T
  8. * <code>   2 G) _# Y+ k: I# c& S
  9. *  //Sample_1   ! r* ]3 I! V3 C
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    + B* {  p! T- _6 O
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   , V2 b* |3 t7 ]1 o, z
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));     N) H1 [" `0 M1 A! [) F
  13. *   4 {# e: q& A0 o8 J& [" _' k/ B4 t/ D4 Q
  14. *  //Sample_2   ( j- v7 f2 N. ^: A
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   . J% U  E. x* n; A
  16. * </code>   
    $ O# t& r) B2 n- ?9 L  c
  17. */    * z$ k* D" n7 _4 F; g
  18.     5 h, x; f$ A4 A/ p# o/ [
  19. class ImageHash {   
    # t+ [- N+ Z/ ~+ I1 k+ y
  20.     , [2 Z, q2 S) q4 z
  21.    /**取样倍率 1~10   % e4 O+ b, k3 |
  22.     * @access public   
    # n; |$ x0 Q; ]# m. E1 X+ A
  23.     * @staticvar int   
    6 M  n- K3 M: p$ R
  24.     * */   
    $ Q6 F; O$ V, |0 z- \5 L7 b
  25.    public static $rate = 2;   
    4 i3 t' Y! S! F3 J2 `
  26.     ' P3 C+ }, x" b2 ~. \
  27.    /**相似度允许值 0~64   
    ) N0 [* i$ o7 T# a& C- T
  28.     * @access public   
    ( F$ \: y: p1 K2 R* f
  29.     * @staticvar int   4 `( ]5 r+ z1 p0 S- _2 h) s4 u5 R
  30.     * */    ' ~9 Z9 _: l7 D& ^1 _
  31.    public static $similarity = 80;    ; p5 X5 b9 T2 t' X
  32.    
    ( i) Q9 H1 W, F* S  q
  33.    /**图片类型对应的开启函数   
    + o9 a  h2 V+ ^
  34.     * @access private   
    3 k5 F6 q& B; N$ @& n  Q
  35.     * @staticvar string   / Q' G; S$ S7 M) B7 y' M
  36.     * */    ( |/ k9 f% }2 _: o
  37.    private static $_createFunc = array(   
    - J  U& U9 a, S. ^( v; J! [
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    6 j4 D) l  D1 o% q3 ?
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    + ^: ~! U4 f+ p7 @& }
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    . M+ [' d  z; |0 }: L
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    8 m1 y5 q8 Q  T# n* r" z5 A
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    ' [  O6 u' n1 w8 p% C1 n% {
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    " [  Y, ?' T  b7 x( v* g8 P- Z! d# |
  44.    );    % V% L/ h, T3 C3 P& l- G* `
  45.     1 a$ }! ~7 Q" q! V! W; n- w
  46.     . f3 S: _- H0 |! ~
  47.    /**从文件建立图片   9 T/ v/ _! p" G5 q7 n" J% U; T
  48.     * @param string $filePath 文件地址路径   
    , _" f- x" m- R4 b7 q
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ) V& g* K6 \9 [3 m! V" @
  50.     * */   
    3 T" K( Y5 c, ~. _2 y
  51.    public static function createImage($filePath){   
    % Z8 x4 f+ \7 p1 y
  52.        if(!file_exists($filePath)){ return false; }    + L, Y$ ^9 k& N* C2 L
  53.     1 l& n! C; \) m- g. \
  54.        /*判断文件类型是否可以开启*/    4 s; m: m! D4 _/ l4 u, K+ j
  55.        $type = exif_imagetype($filePath);    4 _5 |: `9 E- P
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    7 ^, n1 |& C5 z! s9 M1 y
  57.    
    3 Q3 ^) }& u' c3 q2 }
  58.        $func = self::$_createFunc[$type];   
    : z5 ~! w9 O: m' Z( Z: [0 }2 r
  59.        if(!function_exists($func)){ return false; }    $ ?0 ?: P" Y) b9 Y
  60.     - V" t, s' u. q4 O) s  ~
  61.        return $func($filePath);   
    ! W9 n7 ~6 q& q6 {6 R: H
  62.    }    ; p6 I1 E7 l( |$ Y- @
  63.    
    " U2 a8 j0 l6 x2 B1 X! v
  64.    
    3 I' s! P: o" w; o  b9 I
  65.    /**hash 图片   6 `: ?% P3 R5 a+ s" d
  66.     * @param resource $src 图片 resource ID   
    ) \7 {& ?" M% @8 w5 _$ L4 a7 M
  67.     * @return string 图片 hash 值,失败则是 false   ! [: V% w3 \# u0 _8 [
  68.     * */    % t+ O- B& C$ J6 v% K/ H# h; M
  69.    public static function hashImage($src){   
      Y$ K$ v: b0 a0 i  |, z" O+ N* G
  70.        if(!$src){ return false; }    5 r; q! ^2 q% T( D- H
  71.    
    ! p; Q: K  G; _) F/ y0 I
  72.        /*缩小图片尺寸*/    , t# v4 y4 j: C  q. P( J7 h
  73.        $delta = 8 * self::$rate;   
    ) s% I5 M1 d' F" O' A9 k% y8 R% |
  74.        $img = imageCreateTrueColor($delta,$delta);   
    9 o" U3 Y' ]: i) U# B& u5 M' X
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    5 ?. W6 ^$ V3 `+ h; }9 n+ _
  76.    
    / H) ?4 ]" r) m4 [
  77.        /*计算图片灰阶值*/    . X* ]# ~! t& t( u& ?* @
  78.        $grayArray = array();   
    $ }+ g3 S3 m! [" Y& ~  e' F
  79.        for ($y=0; $y<$delta; $y++){      @4 V( q$ X( H: o& A
  80.            for ($x=0; $x<$delta; $x++){   
    6 C- x3 w# e& Z1 r4 r
  81.                $rgb = imagecolorat($img,$x,$y);    , \' f1 w$ Q8 H! U/ T. O5 `
  82.                $col = imagecolorsforindex($img, $rgb);   
    2 o& M4 H! H; h% I# u$ p/ Y* \
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    - j. ]8 v7 Y" t# t7 \- w# |
  84.     " v) z' p" T& R8 n7 t& X
  85.                $grayArray[] = $gray;   
    4 H: M8 q( W6 ?  d7 F8 E
  86.            }   
    5 ?+ u( D$ Z% I6 g
  87.        }   
    - b& f" E( o0 n# Z, g: Z
  88.        imagedestroy($img);    ' j3 o: S$ a& v5 D
  89.     5 R  o; E) `+ n6 T  a
  90.        /*计算所有像素的灰阶平均值*/   
    ( Y- H1 S: H# o5 ~! ~
  91.        $average = array_sum($grayArray)/count($grayArray);   
    2 K. o; a/ e9 A& k  A9 h( _! ?4 G
  92.    
    " I! l+ B, k4 W
  93.        /*计算 hash 值*/    # y% n# t) N5 I
  94.        $hashStr = '';    9 l  {2 V" y. C( l7 P+ ^; f
  95.        foreach ($grayArray as $gray){   
    * q$ q# z8 c* _( I' \  B
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    # b* G; R  L) M+ J# L' ~
  97.        }    2 ?; `2 {/ ^% S# T7 J
  98.    
    ; d7 f  r) @1 m- i/ X, k- h; ~
  99.        return $hashStr;   
    $ S. g4 l$ E, u4 E  u
  100.    }    + [) s3 d# f4 p* ^% n
  101.    
    " i) w. q  J; P( k
  102.    
    4 G2 A1 A$ v! C! ]+ E
  103.    /**hash 图片文件   ! D! x8 ~/ _  c, N% g/ v' }  f, ^
  104.     * @param string $filePath 文件地址路径   2 h5 v1 r( }: I! `6 M
  105.     * @return string 图片 hash 值,失败则是 false   , l6 j" M( ], f, b' W, u
  106.     * */   
    1 E" R% I* I0 B
  107.    public static function hashImageFile($filePath){   
    4 {4 A; ]& X8 r! ]: I7 T5 L% s; N( Y3 U
  108.        $src = self::createImage($filePath);   
    ) F. w& b) h( C/ f- B, R8 E
  109.        $hashStr = self::hashImage($src);   
    8 \2 o8 X  S: p/ C
  110.        imagedestroy($src);   
    , i1 r) j7 y" \; a
  111.     ' l: Y/ O6 y9 A
  112.        return $hashStr;    - s5 j5 |1 N# v5 ~$ [' e1 [9 q" l8 E8 R
  113.    }   
    ( I& o" {' X% \* l1 }# a, y$ d9 X9 ?
  114.    
      R7 F4 Z! A+ L: U* \- w& K
  115.    
    - u! n- m+ z5 Z; g' t0 i' O
  116.    /**比较两个 hash 值,是不是相似     O6 a+ [6 q+ `+ l3 Z, J7 Q! ]
  117.     * @param string $aHash A图片的 hash 值   ' h' T; E; E) z! q( `7 c4 _
  118.     * @param string $bHash B图片的 hash 值   : A9 Y: {4 v  H: {
  119.     * @return bool 当图片相似则传递 true,否则是 false   1 `" @: L3 c5 j! I% n
  120.     * */    ' s/ ]4 Z2 N) W
  121.    public static function isHashSimilar($aHash, $bHash){   
    # ?7 n4 d$ T6 D
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    + v$ V1 x/ f& C& d. U2 N% l
  123.        if ($aL !== $bL){ return false; }   
    5 R3 a+ V; M! |& c6 H
  124.     ) ]* g! Q/ C: L9 o& s9 g
  125.        /*计算容许落差的数量*/   
    0 @0 s/ h9 @& o$ x& R
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    # V  H& v& Z; B& a$ g  [' n
  127.     6 `3 B4 V. }) S1 L7 T! c+ U2 a
  128.        /*计算两个 hash 值的汉明距离*/    ! x- e$ n' j$ M/ y) z$ p0 ~0 k, z
  129.        $distance = 0;    ; U" o3 v3 `2 ~+ |" Z; t
  130.        for($i=0; $i<$aL; $i++){   
      g2 i/ [/ E' u% `
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    - @5 L6 K# D  T* {* \& \( K
  132.        }   
    - E% ^7 a! L  Y; ?+ s
  133.    
    % [; k6 M3 L5 H- y5 o# u
  134.        return ($distance<=$allowGap) ? true : false;    ! o/ H. f8 G4 g2 U3 z( S) n
  135.    }   
    % ], i5 K) t! e4 E1 Z
  136.     : q5 P9 I& R" P% M+ ?) w
  137.     0 y  k1 o  p) i7 f! `) o! s
  138.    /**比较两个图片文件,是不是相似   
    ) ~. O6 u6 \/ W
  139.     * @param string $aHash A图片的路径   & e. B1 a4 @1 F( E" M) M' ]
  140.     * @param string $bHash B图片的路径   ) T' v3 n$ F, a8 m) p0 Q; P9 {
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    , X! S( V3 f) v% N2 b* `4 S
  142.     * */   
    8 I8 D: y# y: j4 K( C9 q( O
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    % ?7 d5 O$ t$ n, W1 ]# B9 N% C
  144.        $aHash = ImageHash::hashImageFile($aPath);    5 i$ v5 o9 ^; F" ^1 |
  145.        $bHash = ImageHash::hashImageFile($bPath);    # V. e+ Y5 Q+ u: S% {  F# j
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
      g! z% H' j$ B  `
  147.    }    ! E  V8 P! b0 W+ b7 E3 {+ P/ x
  148.     , Y1 m9 R0 j+ ?7 E7 y
  149. }
    2 s( b! [( y& S1 W2 h
复制代码

# `1 N5 w% U8 G/ w$ V. N% {6 `! [  z5 a9 t3 l0 _: D6 z# y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 20:14 , Processed in 0.055542 second(s), 19 queries .

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