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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

7 h' V7 b8 t" ]  G( g由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

: k+ x8 \. i8 ^$ h
  1. <?php   
    : X" b  G" G2 S) [" j( r  Y
  2. /**   4 S, w2 V9 b. Y; g) B1 g8 X
  3. * 图片相似度比较   ( _/ L+ w3 `5 f2 C% R9 M5 X
  4. *   
    3 r( o3 p( c' M0 f5 C
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ' u- l4 r1 Y/ z
  6. * @author      jax.hu   
    7 ^! l7 t* G2 Z5 _" t
  7. *   ) |- Y' k* |+ ^% R
  8. * <code>     h: i" p% k' X9 R
  9. *  //Sample_1   
    ' J& _& O, l, ]. K; T8 B
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    0 B* G# F; J8 J0 p  b- {( k
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    , O" H; Z, t/ V# e0 b" e7 V
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   3 K! C  u  k* L* u/ l
  13. *   + d# m5 H# ]- o3 u( M9 q
  14. *  //Sample_2   
    : ^- s- G) s1 \
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    2 o9 M& q* P7 |6 M
  16. * </code>   2 V+ w3 a* f$ t& ~
  17. */   
    7 K: J8 W& v5 n6 g# o5 d6 G1 m
  18.    
    ; b- `" G  J7 Y3 ]- C* I* h, M- X
  19. class ImageHash {    % ^9 _% m+ v* ~
  20.    
    4 w: j, C1 J4 I1 y8 U: p
  21.    /**取样倍率 1~10   ; J9 y$ A3 ^* K8 Y
  22.     * @access public   $ l9 \5 l% ?) H4 r% i
  23.     * @staticvar int   
    & L& c2 S9 R+ g5 j$ \, o- v
  24.     * */    / B! O9 g) E( k6 X( N1 X3 a
  25.    public static $rate = 2;   
    - P5 _4 G6 Z/ V* w9 H( R
  26.     . |) m$ [# A0 z2 |
  27.    /**相似度允许值 0~64   4 U4 w; D+ y2 I7 O3 R7 T- G; O
  28.     * @access public   
    / A7 P" X9 O1 O6 n  ~3 z
  29.     * @staticvar int   5 ?. ?4 y+ w1 Y. k. H
  30.     * */   
    : H% a, G* Y& n
  31.    public static $similarity = 80;    / T4 X$ `) N3 I( `# K! M
  32.     , [+ ~" W+ H* ^3 N- H
  33.    /**图片类型对应的开启函数   7 j4 @0 b4 V4 }# W6 j9 x
  34.     * @access private   % K" U( `& G$ J
  35.     * @staticvar string   & f1 i# E& h) a# @. p
  36.     * */   
    * W, @1 l: ?9 Q% X
  37.    private static $_createFunc = array(    + p$ Z5 _/ J$ O- q: V5 }  X
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    5 U! }; P* w6 a
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    . h$ U, ~- e" ~8 f
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    0 b% P" Y+ y6 W
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    / k& k( a& I9 v$ J1 V. L
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    ! q2 j/ ]6 P& i* e* t: s9 V/ ^
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    . J- w8 F& a, U; s* }$ U+ n
  44.    );   
    ) e( O& J. z0 C# D' Y3 Y) ]
  45.    
    % c2 D4 E# y% s8 G  R
  46.     3 c' n+ y) |' G* f+ e& o, M
  47.    /**从文件建立图片   : {1 z7 {; n) m  F
  48.     * @param string $filePath 文件地址路径   ' ?9 d1 y+ s- U' u( z" E! s) q( X
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ( `/ |5 D# }5 L  t  G; Z5 _( V
  50.     * */    * Z5 [5 Q- s9 M
  51.    public static function createImage($filePath){   
    " @3 H4 d3 c- r2 A
  52.        if(!file_exists($filePath)){ return false; }    ) c, C8 s+ Q$ q6 N" |  `
  53.     1 \0 L% F0 N$ y. j; \* o# w
  54.        /*判断文件类型是否可以开启*/   
    ' |, }( |; j* U4 P5 A5 f
  55.        $type = exif_imagetype($filePath);    + A* ^: Q6 x  R% u. ^6 I$ U4 D+ z
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ( R$ }/ e" e$ o
  57.     0 r4 \1 x" `/ {: O
  58.        $func = self::$_createFunc[$type];   
    & @% M- E$ Z5 S0 N( [* Z0 i
  59.        if(!function_exists($func)){ return false; }   
    5 j! i8 I5 R+ u! B$ `+ y
  60.    
    * m0 u6 D( B7 Q8 f7 r/ O( c9 M
  61.        return $func($filePath);    . h, D$ i; D5 H9 s9 s) a7 z9 _0 [
  62.    }    & M: ]7 Z: \: `' f+ i" y
  63.    
    0 S/ q8 i3 p) }
  64.       M- q1 J. r, }$ M, r
  65.    /**hash 图片   
    1 T, T, ?, K" Z$ T9 T) U6 s7 @
  66.     * @param resource $src 图片 resource ID   
    & Z/ O. s1 G& f& @: Q  S
  67.     * @return string 图片 hash 值,失败则是 false   ; a, z( r5 d* C; I! ]! S4 @
  68.     * */   
    1 I) J: M% e1 z5 z) S1 W
  69.    public static function hashImage($src){    3 ^& {2 Q& J2 W+ Y) ]
  70.        if(!$src){ return false; }   
    # e8 {% c1 ~" v! J
  71.    
    0 m: [$ x+ i3 r, u. X! ]* ]
  72.        /*缩小图片尺寸*/   
    ( V. y0 ~* y* Y+ L$ j+ Q8 ?  H
  73.        $delta = 8 * self::$rate;    6 j+ @- ]6 M# N, l
  74.        $img = imageCreateTrueColor($delta,$delta);   
    9 n0 p6 n, x3 g* O, |$ w/ W
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    8 Q9 U) r. i4 e# o. `7 f
  76.     - \2 s- n2 Q* v
  77.        /*计算图片灰阶值*/    8 g9 j+ k* ~9 f( F5 K
  78.        $grayArray = array();    - \& M2 g3 v* h/ N4 D, a$ U
  79.        for ($y=0; $y<$delta; $y++){   
    / D9 z( }# R6 M8 c& i* H5 C
  80.            for ($x=0; $x<$delta; $x++){   
    , z/ @# _: P* q
  81.                $rgb = imagecolorat($img,$x,$y);    4 \5 p) Q: I5 y, ?; y8 _# E
  82.                $col = imagecolorsforindex($img, $rgb);   
    / N  W: ?, E# y, |  }: `, \" g
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    5 e. D2 v0 g5 b5 o3 S+ v" x
  84.    
    ' T. R% O( B! O7 k$ e: b) w" c
  85.                $grayArray[] = $gray;   
    8 o+ H7 h+ _* X1 c8 C7 ^
  86.            }   
    % }/ C! X: L8 ]" X4 r; X
  87.        }    # y% J7 M9 o% d4 d  B1 G! B
  88.        imagedestroy($img);    4 v: I) }7 ^& \6 m
  89.     6 v: T- H. g4 g& l
  90.        /*计算所有像素的灰阶平均值*/    5 T6 d( K. J0 R
  91.        $average = array_sum($grayArray)/count($grayArray);    & t( y5 @: d; t9 o8 ~4 J. q2 A
  92.     4 Q6 _5 o! q8 ^! i' P
  93.        /*计算 hash 值*/    4 u  t8 y6 @' v! W: ?# [
  94.        $hashStr = '';   
    2 J% Q" F) k! J# A' N$ D% U
  95.        foreach ($grayArray as $gray){    & Y" J: ?/ z& u% k2 g, C& Z- Q& u7 b  f
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    + g+ r+ n( v( k1 t: S: U8 B
  97.        }    : z% P6 ]( ~1 T$ k( [
  98.     & W/ B, w4 L) C  ^; k5 R
  99.        return $hashStr;   
    ( J3 j; r7 s0 c' Z
  100.    }      j. h* J3 u! e# Z
  101.    
    ' V( a- s3 m( w. I9 H! Z) g( i
  102.    
      |! b% A# W" W( D
  103.    /**hash 图片文件   
    4 h  X  F( |) X  s0 p# r: Q
  104.     * @param string $filePath 文件地址路径   
    3 V5 q4 F' e; Q1 O
  105.     * @return string 图片 hash 值,失败则是 false   
    - G4 L1 b  u( v; g% m
  106.     * */   
    ) ?+ h/ W: B& u5 b: D+ X7 ?
  107.    public static function hashImageFile($filePath){   
    + A" J5 I: b( p/ y. C3 p
  108.        $src = self::createImage($filePath);    # w" V1 |" \( p0 O' c( p3 m7 @5 O
  109.        $hashStr = self::hashImage($src);   
    " ?1 o2 C0 k# f2 j! R
  110.        imagedestroy($src);   
    " r% E; ~( k* ^. @
  111.    
    ) @1 \0 ?' W* j
  112.        return $hashStr;   
    & m8 b/ F1 v: ^
  113.    }   
    2 P; d9 v& k" X8 j. W
  114.     & `  K# M( N# [5 P
  115.    
    ; X! e* J, r& h5 {' {
  116.    /**比较两个 hash 值,是不是相似   
    4 ~2 v7 }0 v7 X' x
  117.     * @param string $aHash A图片的 hash 值   5 }1 \7 d) ~2 M( r% Q
  118.     * @param string $bHash B图片的 hash 值   ) N; P7 w1 d& Q" C: [. X$ n4 s4 c) H2 e
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ( S' S' m. Z' B  x9 g( R4 {6 `
  120.     * */   
    # t) O$ ]; F; x, C
  121.    public static function isHashSimilar($aHash, $bHash){   
    ; `! L  D3 Z! v5 G% h
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    2 D) o/ k5 {4 y  t! a) l8 b1 Y
  123.        if ($aL !== $bL){ return false; }   
    ! B/ M$ f/ }/ w
  124.     ' b( p# _+ a4 x* R4 T# p! e
  125.        /*计算容许落差的数量*/   
    8 q0 ?1 ?& \; Q1 @3 p
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    2 E; B5 N: R- d. g5 k
  127.    
    - Z& N1 f7 |9 X2 f( K# ?3 v& Q; _1 p
  128.        /*计算两个 hash 值的汉明距离*/    + @8 e0 }3 {- R+ Z* ~! ?
  129.        $distance = 0;   
    3 A5 U* N* y. L6 @' `8 T+ J
  130.        for($i=0; $i<$aL; $i++){    1 a* a% ?/ ~3 S5 k
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    3 f1 ]) ~* Z0 H0 a
  132.        }    8 h- K. ]# h. J& I  [% l$ W
  133.    
    7 P+ Z6 p. q  X1 D2 l
  134.        return ($distance<=$allowGap) ? true : false;   
    + F% {: b: Z9 G# [' z% j
  135.    }    0 o9 {; w3 }- n) q. g# ~
  136.     * E! U% Z' f  j5 T+ Y* G1 H+ W
  137.    
    + t% H% K- y, W; {' z( T" r
  138.    /**比较两个图片文件,是不是相似   1 f, u4 e* e+ Z: J2 V0 R
  139.     * @param string $aHash A图片的路径   
    6 e6 f& E3 v- c3 T' Q
  140.     * @param string $bHash B图片的路径   
    + Z; i" b, T2 b
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ' _% d+ [6 }! l3 f  }
  142.     * */    $ B7 K& D& F" G% R4 ^3 A
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    0 E  Z& j/ }! e* _; M
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    / R  n! D# G1 _; ~6 B) j( p& Z8 R
  145.        $bHash = ImageHash::hashImageFile($bPath);    ' ?# {: ^7 u0 n
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    + Y0 Y' Y4 u3 ]6 O# J
  147.    }    / k, s7 l: R/ q$ C8 ?4 \9 K
  148.    
    # l1 w0 c7 `& x8 Y6 {: Z$ a
  149. }
    . ^! X& w: s$ c8 [1 p) F
复制代码
% Q: Z: o2 R6 T5 Q
! s# }8 r# f  K$ D5 x# _' A+ Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:46 , Processed in 0.059024 second(s), 20 queries .

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