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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

9 X+ `4 a3 z+ H$ L$ U6 j$ w, P9 P5 H

# n$ s& e1 |, p  v" l+ _5 |由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
! P0 k+ q! ^: m) a4 I- n8 Z
  1. <?php   
    & E( k% U% J4 U6 E- O/ g2 }3 X
  2. /**   
    / [' Q5 A+ i' ]8 k9 B1 s
  3. * 图片相似度比较   " m, o7 A2 J7 ^8 z4 m
  4. *   & c( G! h1 L- t+ J+ H. e7 E" t0 j
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;    v7 L) ]- ]8 X2 @& u' k
  6. * @author      jax.hu   
    . P1 n8 C% v) L1 Z3 w1 G
  7. *   
    - [4 X4 ?, I# B4 W2 |7 W7 L
  8. * <code>   
    . O9 i& r* z% e* r
  9. *  //Sample_1   1 f; `& P. ]; o5 A
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    1 ~* O1 ]. t/ \8 @! t
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    1 G9 y# o  d8 c( s7 D
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   2 x" E4 V1 o" u  z* S3 F
  13. *   
    5 D1 y# S* I& G
  14. *  //Sample_2   
    ' |. w. K- Y: ^( p& t- M
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   4 \2 @- o- w  O
  16. * </code>   
    # x- V1 ]) j7 [# E
  17. */    + k- ]; J! `: e: _, _7 j4 O3 ]# A
  18.     ' U' C$ M' v! q1 j9 A
  19. class ImageHash {    & |* O0 F* l) l9 `
  20.     8 r' j( K& `0 y2 `( \% c) s8 \
  21.    /**取样倍率 1~10   : r% Y" [! `5 p
  22.     * @access public   * P3 C( w' c! p0 B& V
  23.     * @staticvar int   
    ( D) a3 \1 t" [  o# O- G) o. {4 K
  24.     * */    4 ^4 H, p, O  n4 n. T
  25.    public static $rate = 2;   
    & i  w1 Z9 ]: z: r- d
  26.    
    6 P! N9 C1 ~3 ~- L7 C5 f# B/ u
  27.    /**相似度允许值 0~64   
    4 N0 Z3 n7 Q1 Y5 X0 v1 R+ Q3 K
  28.     * @access public   
    " z- E" o$ w7 C
  29.     * @staticvar int   
    # t6 K) @/ }! i) Z: z; r2 k. ?$ r
  30.     * */    * k- d& r) {! ?" l
  31.    public static $similarity = 80;    & ~" B, t* ~% y8 U$ A
  32.     " V0 G4 v/ O/ R' z5 R7 K% A
  33.    /**图片类型对应的开启函数   1 s0 R+ C+ O6 v& H* P
  34.     * @access private   
    . V) z) R; S7 R) P5 b! w3 V
  35.     * @staticvar string   5 Y# S! \7 L/ \* ]* a( v# p
  36.     * */   
    . X7 _5 H% }4 Y2 V& Z
  37.    private static $_createFunc = array(    6 R  p  s$ d' ?) T' Y. E$ c
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ; @6 p7 h: V3 Y* Z
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    2 N3 Y4 {8 C8 P. S, B
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    4 q4 V  _6 y2 A( z9 l3 t
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    9 \* t  Y  k3 J8 D$ w, _" I
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    & f6 h" K8 b! E6 m$ V/ \/ L
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    7 l; U! R" c2 `* G5 }# f9 x
  44.    );   
    ; _9 g3 c8 ^4 K. C; B- i
  45.    
    " u5 I& t: w* q+ z! n& b2 K
  46.     4 ]/ y. A4 [2 O6 X2 {/ w
  47.    /**从文件建立图片   ) E$ e$ W6 P9 X4 ~) f; Y  Q# y& X
  48.     * @param string $filePath 文件地址路径   
    1 y  d* {+ a5 N' ^9 }
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ! }/ [5 n4 b. M) D# Q' x
  50.     * */    ! a/ w8 y6 \$ V6 s% U' U
  51.    public static function createImage($filePath){   
    * w5 L) T" B" t% V  P) d5 _+ N
  52.        if(!file_exists($filePath)){ return false; }   
    7 h  a+ [% L8 x9 p0 B5 a/ M
  53.     % P3 p& u& j% K8 Y( W2 ~! q
  54.        /*判断文件类型是否可以开启*/    ; k4 c; L+ s/ O
  55.        $type = exif_imagetype($filePath);    3 G: p: Q9 b8 U
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    . y8 w7 n0 E5 E4 }
  57.    
    - D: ]2 f; G0 k
  58.        $func = self::$_createFunc[$type];    * o2 z) H( |1 Z9 D
  59.        if(!function_exists($func)){ return false; }    & i0 ^; S" r. D, ^4 i& ]' d
  60.    
    4 g! @5 f* t! S/ k* a& G
  61.        return $func($filePath);    4 d2 @! j, _5 g: |' g& P: r- W1 y
  62.    }    7 m8 m* }  ~( J; f$ ^* Q
  63.     . Y7 C% p  I4 V
  64.     + a, X- X0 c% Y4 e
  65.    /**hash 图片   * @* ]* S4 U5 j9 h/ Q& |6 G
  66.     * @param resource $src 图片 resource ID   
    0 W" |! ^% E& ?4 w8 h
  67.     * @return string 图片 hash 值,失败则是 false   / S' ?+ l0 j$ F: g
  68.     * */    ' k, {. V  ~; R3 B. G" t8 w  _
  69.    public static function hashImage($src){    . v' Q2 D& x8 P2 v% r: M
  70.        if(!$src){ return false; }   
    2 ?4 c  f& h7 }8 M4 l# Z" Y' Z
  71.     : W; x1 w4 I$ K. f! a. m* p- d
  72.        /*缩小图片尺寸*/   
    % _( ?9 C5 q) b2 V* B3 V1 n( x; O
  73.        $delta = 8 * self::$rate;    - g9 D0 L" A* ~3 F5 |1 g; p7 r
  74.        $img = imageCreateTrueColor($delta,$delta);    0 _4 A$ ]+ n" P9 M2 K0 Y
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ( a2 o$ @' `: Q
  76.    
    $ H; K& e0 Z$ \" w8 R: |
  77.        /*计算图片灰阶值*/   
    * d+ f- z+ C5 d$ w+ `& @
  78.        $grayArray = array();    * h2 \9 h8 X( i0 \. C) S" f$ R
  79.        for ($y=0; $y<$delta; $y++){   
      v. O  E* j+ y. n- W4 X
  80.            for ($x=0; $x<$delta; $x++){   
    : P; J; V; s- D- _0 m* `8 O
  81.                $rgb = imagecolorat($img,$x,$y);    - Z3 t0 L% d' `/ J5 I: e& C
  82.                $col = imagecolorsforindex($img, $rgb);    $ R, y$ D; k( u8 q2 c* l5 k
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    0 n$ G5 ?$ A, n
  84.    
    6 L' E! h+ f$ \9 b0 U' E2 k& d( Z
  85.                $grayArray[] = $gray;   
    6 @% j& q4 F( w4 a  N
  86.            }    & U% P; B+ U6 \. H3 h
  87.        }    8 B! e+ c( f  D$ ^; e) U
  88.        imagedestroy($img);    4 E# A9 b/ E  y1 f
  89.     4 {- D- f3 y5 ^2 f2 q
  90.        /*计算所有像素的灰阶平均值*/   
    8 j- y3 c0 z, C1 J/ e
  91.        $average = array_sum($grayArray)/count($grayArray);    " X) e5 _, J2 g* J1 T
  92.    
    0 n& ?. x* V. P
  93.        /*计算 hash 值*/   
    ! [/ c* e' i6 q1 D$ R4 W0 N
  94.        $hashStr = '';    & ^! V: F! v: J& V9 {
  95.        foreach ($grayArray as $gray){   
    + c1 E, e4 R/ L# o+ b! l( u+ R
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    * Y  N  o6 H% f) j9 x" s
  97.        }   
    - y4 c" e3 ~: d1 C( h
  98.     5 c! |3 G% r: @' N' J8 V
  99.        return $hashStr;   
    4 z  |- e9 O9 a0 d
  100.    }   
    ' `; H  _" X* q* n* \" A! t
  101.    
    9 S$ H( y  K7 O& I$ R7 C
  102.    
    2 Z0 }- K7 ]9 U. a; n. o
  103.    /**hash 图片文件   
    4 f" K7 c0 B. J' b4 L% y) X
  104.     * @param string $filePath 文件地址路径   % a( F9 {: T( ]+ {- q
  105.     * @return string 图片 hash 值,失败则是 false   
    ! e9 e2 T: |2 [
  106.     * */    ) f( R3 ^# t( [7 z" d
  107.    public static function hashImageFile($filePath){    : c7 s8 [+ D0 [  [0 x& n: P
  108.        $src = self::createImage($filePath);   
    - S/ Q+ w3 x- f+ K
  109.        $hashStr = self::hashImage($src);   
    * E! Z: z  r* S* Z& V* }' x) V
  110.        imagedestroy($src);   
    / c' i/ g1 h& L  O1 o; f2 u
  111.     ( O- N4 W4 Y; p/ Z' R+ f
  112.        return $hashStr;    & W* d) M  b0 Q5 A6 g) g
  113.    }    4 R6 }- a: o  t  Z' n
  114.    
    ' T  I# U( `' K$ k* i8 A$ S8 f
  115.     ) _* S: b3 o( w) z
  116.    /**比较两个 hash 值,是不是相似   
    " w  T+ z. C. \/ _: R4 J5 r
  117.     * @param string $aHash A图片的 hash 值   
    6 D. V; t& c8 B
  118.     * @param string $bHash B图片的 hash 值   
      s) l2 M  X% s. h( s- a& S# o
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    7 t" J9 g8 a3 O( C% P: ^5 |& T! D$ j, G
  120.     * */    ) Z) Z5 f8 p% N8 U, }8 i
  121.    public static function isHashSimilar($aHash, $bHash){    7 Y' Y% ]  I2 y. g
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    6 X1 N* n. l. r* x4 @+ o
  123.        if ($aL !== $bL){ return false; }   
    7 S. \. I4 Y1 P8 @5 ?6 j# B$ A
  124.    
    ! D$ _8 \$ D8 ^0 R. R% f1 h5 W
  125.        /*计算容许落差的数量*/   
    , z2 h5 I! A" l" _3 ^; V" r: C% w
  126.        $allowGap = $aL*(100-self::$similarity)/100;    + r8 y% _5 |9 l. `# X5 r
  127.     , I  \! [0 h% W6 J" k
  128.        /*计算两个 hash 值的汉明距离*/   
    3 u5 F- g) Y( o3 p: l
  129.        $distance = 0;    " @/ @5 C5 p! I- d: M
  130.        for($i=0; $i<$aL; $i++){   
    5 l% {+ ?! L( [0 Y; O! ]) f4 v8 o
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    1 Q" _6 \, d+ [& e$ d$ y4 o. W
  132.        }   
    9 V4 |& r, S8 b5 Q, e
  133.     9 F. Z. A! C7 @" o1 [* s* i
  134.        return ($distance<=$allowGap) ? true : false;    ) M- Z. x6 J: b6 j1 l
  135.    }   
    + o, P% |. a: q5 \
  136.     " |, Z/ K0 V* q: s
  137.    
    7 y0 Z5 a" r7 `) [; x
  138.    /**比较两个图片文件,是不是相似   0 ~7 q; e& P  l% U4 h; i
  139.     * @param string $aHash A图片的路径   
    : j" U/ V3 I$ @4 y: d) X$ R9 x
  140.     * @param string $bHash B图片的路径   
    5 T( S& `2 u$ H, |! w6 z
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    9 F7 t& I* \7 T# ?4 c  z2 |
  142.     * */    - g8 V, L3 F$ L5 O3 O  q* `
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    6 [3 p' }/ Z  Q( {; q7 W
  144.        $aHash = ImageHash::hashImageFile($aPath);    4 R6 [) V$ O. }( t
  145.        $bHash = ImageHash::hashImageFile($bPath);    $ Z8 N" U: Z" r& A, h
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    / S% y9 }. Q1 n" y2 c7 j/ G7 }7 w
  147.    }   
    ! @: A1 S% v# w3 x  B* Z8 y. x
  148.    
    * D/ h. G6 ~8 E* J
  149. }* }' H# y  v! S; T0 m. a
复制代码

1 r# Z, L; A& e) B; P. S+ z# z# S+ r( F$ n
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 16:37 , Processed in 0.061164 second(s), 19 queries .

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