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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图' R" n1 w; A3 ~7 o/ e
1 _# ?1 t( v5 _% C: `& X7 L. i
6 z) A4 {: ?0 [, S8 l4 @" n$ r
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

5 }) Y! s. ?* c
  1. <?php   
    . H6 s# k6 ]5 _6 m% K* f$ @
  2. /**   . ^; I8 }/ \1 N+ U
  3. * 图片相似度比较   
    6 m& H  d, q4 _: e3 d. C' N
  4. *   , G/ B; A$ i. y
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    # `4 w/ h, H& H2 K2 P+ W* O" s
  6. * @author      jax.hu   
    ) Q/ [4 c; F: P2 V. S, q7 {4 K! X( @
  7. *   + m2 L: q! E. q" q  j$ Q
  8. * <code>   1 p; E2 _+ |, O- n5 x2 k
  9. *  //Sample_1   
    4 N1 ]- U0 ]- G) c
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    - H3 \2 w7 O! M& N/ j! f0 E% K: L
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    , _" X# _: N. b* X9 j
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   ! z: `# G( ?/ v- O1 g" [
  13. *   
    * d9 ~2 z; ~% R3 h5 ~+ c4 B: u
  14. *  //Sample_2   ( g* }, R+ {( F) ]! B0 R0 W0 T
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    / q5 b/ U6 o( U: U
  16. * </code>   
    0 U5 Z- W6 E/ ]
  17. */    4 P0 P, i$ f5 h2 j
  18.     3 L. x& `1 y# M! u5 E4 J+ H
  19. class ImageHash {    $ i4 M* `+ F; q1 h3 T2 u
  20.     ) X" Q; o/ T$ }7 G* ~
  21.    /**取样倍率 1~10   . K& i3 V9 V3 G/ Y3 b3 a) ?
  22.     * @access public   
    ( S  G' r+ W2 C/ m. V
  23.     * @staticvar int   ; Q+ h3 }9 X4 ]+ ]' F: W. G5 M
  24.     * */      i( O+ K6 {  ^( X1 @# e( u# d* A
  25.    public static $rate = 2;    6 {2 z0 J/ t9 v
  26.    
    * E% z; ?8 S$ @
  27.    /**相似度允许值 0~64   5 e8 y3 g6 h& k% _8 e% R
  28.     * @access public   ! s1 c" A+ P8 v" d% ?0 C
  29.     * @staticvar int   
    $ ~% T' V7 |4 o
  30.     * */      B. p  x) Z6 q3 g5 L: Q% N
  31.    public static $similarity = 80;   
    ' R8 O4 h. N/ {- H5 j2 ^3 R  l
  32.     1 u8 x1 F( y6 y) s0 j
  33.    /**图片类型对应的开启函数   
    & ?! f' a% y4 H9 ~7 m8 Y
  34.     * @access private   6 F# ^6 e, o/ H+ v3 Y" l
  35.     * @staticvar string   
    # ~  ~. G$ l, C5 }* K% G/ e& E
  36.     * */    $ @( Q1 O0 ^% y/ I
  37.    private static $_createFunc = array(    5 i/ E  ]* G8 e' S3 b
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    $ W: O; [2 {* ~
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ( R3 ^2 d" e3 U3 a! `3 s
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    1 n# i; Q) A8 ]6 R, N
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    : E2 j) G7 o; k+ I/ \: G( a
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    3 x9 p# x4 j# v% H
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    9 t% r$ i, ^) m5 [- i8 G: y6 l7 P
  44.    );   
    ' }5 Q5 K! @1 k
  45.    
    $ v7 R: P! }# H8 a# `' S
  46.    
    : c, N1 f+ Z6 s/ k" |
  47.    /**从文件建立图片   
    & m3 R2 Q5 V8 O  Q1 p: a
  48.     * @param string $filePath 文件地址路径   + q, c& E# X6 M$ S! A
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   4 J' A# y& X8 }
  50.     * */    & e( C: J+ u- [* B) N
  51.    public static function createImage($filePath){   
    1 v/ ~) U3 e0 S) O
  52.        if(!file_exists($filePath)){ return false; }   
    ; B/ C! N0 m! P  `3 T
  53.     5 h6 l5 A8 s% o2 c" o. s; [1 p
  54.        /*判断文件类型是否可以开启*/    1 Z" q: o& w, |2 K3 o/ d
  55.        $type = exif_imagetype($filePath);    % W5 R: `, {: W0 F$ i
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    5 b" {6 g: ^! ^2 P
  57.     & e/ H* n" X0 U7 X  H
  58.        $func = self::$_createFunc[$type];   
    ( L. C/ P9 ^, A/ g. ?1 n5 h# T
  59.        if(!function_exists($func)){ return false; }    2 y: w, \& _2 h' g' T; g, ?; h3 O* U
  60.    
    ; c6 E! W  I. ]* D$ e( m- {6 a
  61.        return $func($filePath);    $ r( d& u# P$ G
  62.    }    7 B5 x8 d4 y2 I2 |- {, K1 r
  63.    
    7 b5 N+ l6 u* ~, U: U. b0 k( y
  64.     - R5 v4 S1 ~6 W& W8 E' l. Q
  65.    /**hash 图片   
    & w9 Y( d1 K6 ]# i  R) H
  66.     * @param resource $src 图片 resource ID   
    & O" X  [$ Q; ]+ G5 Z" S
  67.     * @return string 图片 hash 值,失败则是 false   ' B1 E0 H) {1 q" Y7 Y* C5 y: W5 g
  68.     * */    # q0 f" A9 p" O3 s2 D: w
  69.    public static function hashImage($src){   
    5 r; o; y: X9 a+ I( x3 b! r4 x+ j% U
  70.        if(!$src){ return false; }   
    # S3 h5 `4 I0 _9 }7 D% a" y
  71.    
    , Q( o+ _* f% \- J
  72.        /*缩小图片尺寸*/   
    * @0 ~; ]1 ^% N1 r- E( a8 z
  73.        $delta = 8 * self::$rate;   
    5 ~6 X& u2 x& g4 C$ d
  74.        $img = imageCreateTrueColor($delta,$delta);   
    ! r! V3 x) ]% Z5 u6 ]9 q$ V
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ; b% ]( p% {: f0 y- J. ~: Q" H
  76.    
    2 O, a; S2 f  q* c
  77.        /*计算图片灰阶值*/   
    . @2 ~! ]* H: S  S$ m/ D/ T
  78.        $grayArray = array();   
    ( R6 g3 k) d2 C( d0 U. j) ?4 F7 v
  79.        for ($y=0; $y<$delta; $y++){    ( m: ^3 }' N, F# R2 W) \; V
  80.            for ($x=0; $x<$delta; $x++){    ) R, o; g( j+ n0 S1 [
  81.                $rgb = imagecolorat($img,$x,$y);    ( f* L0 k& c/ X7 S  Y
  82.                $col = imagecolorsforindex($img, $rgb);   
    . n1 B: x0 p; B$ u1 z2 [
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    , I0 [  @; S0 V. {/ {+ N& T  K
  84.     ' v8 p2 F- k/ H/ w6 N
  85.                $grayArray[] = $gray;    & g6 g- e. h8 ]9 m7 F) y9 x
  86.            }    * E- I& ?' L8 y# [( }
  87.        }    ; n9 ~4 ]# V! x+ U0 z
  88.        imagedestroy($img);    5 F9 U2 [9 T9 L" O% F$ v
  89.    
    / A& r( [1 s+ t7 y5 B( m
  90.        /*计算所有像素的灰阶平均值*/    ) E& `. p! [  D1 Y
  91.        $average = array_sum($grayArray)/count($grayArray);   
    & ]9 G& D1 R% y8 v% Y) E4 j' i
  92.       @, U  R$ N- C
  93.        /*计算 hash 值*/    + `- H, }1 {# z6 i" S1 `6 P4 s
  94.        $hashStr = '';    ( Y. V8 X6 n2 `  B1 T4 I8 `
  95.        foreach ($grayArray as $gray){   
    7 b% o1 a7 B$ n& w9 S  F
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    7 b+ \3 ?( D5 J5 t8 m1 J
  97.        }   
    9 ]2 q& }! P$ P1 `7 S
  98.     2 x+ z, N: ^+ ]& J# j# X- Q" Q
  99.        return $hashStr;   
    : ?1 }( z  ~; u( j; f, O
  100.    }    5 [( ]. U  u3 n
  101.    
    5 X4 y4 v: R3 i: g
  102.    
    % Y+ J- A3 C, h" m8 p% A* x0 O
  103.    /**hash 图片文件   * h6 S# p- W! T6 ^5 m! `% ~
  104.     * @param string $filePath 文件地址路径   - m& `5 |* K9 m+ ]: _# E) P
  105.     * @return string 图片 hash 值,失败则是 false   % K( O) x. |% _8 v3 q9 V# S- W
  106.     * */   
    5 r( C8 t* A' K6 C' l, G) c
  107.    public static function hashImageFile($filePath){   
    + e1 D# D1 W+ L+ ?, f; E6 _' D
  108.        $src = self::createImage($filePath);    8 X' {7 l. Y$ d+ N8 e" e
  109.        $hashStr = self::hashImage($src);   
    / R& s! c% b, G$ q9 ^/ d# V4 L
  110.        imagedestroy($src);   
    : t8 m$ Y, }  K% {( k& U% s
  111.     8 T0 _# t! |) r8 k
  112.        return $hashStr;    1 O3 o7 ?$ i& D  O9 r" u
  113.    }   
    + R# j* Q; S1 E8 M+ W. f/ S1 F
  114.    
    : d: F( }$ F) l; ]9 V. V
  115.    
    * Q- ~7 P! o! I& J9 b5 U5 J8 Z$ R
  116.    /**比较两个 hash 值,是不是相似   ! n8 {1 N' x$ Q( f$ N
  117.     * @param string $aHash A图片的 hash 值   % R0 g& ?) e; o4 K# A5 V( |
  118.     * @param string $bHash B图片的 hash 值   
    * k3 H/ H/ k8 \* T. O
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    * |- q* o9 e- l* m2 i/ l3 L* k
  120.     * */   
    1 S8 R3 p* G4 K2 P) ?
  121.    public static function isHashSimilar($aHash, $bHash){   
    9 p: n0 c& h2 X
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    8 M7 M! L  x3 a: a5 I) F3 \
  123.        if ($aL !== $bL){ return false; }   
    1 z( H3 z5 l* J4 n8 y2 Q& x
  124.    
    ; O: M4 B' p, D$ [  Z; J$ ?; W
  125.        /*计算容许落差的数量*/   
    2 l! D- Z' X6 M7 [3 G
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ' X$ I) v7 l) ~% b% \2 g
  127.     / C; g& P" C! R0 H' i3 C- {' `: }0 u
  128.        /*计算两个 hash 值的汉明距离*/    9 h: ^! _+ D% _" ~3 j- R; e0 C
  129.        $distance = 0;    : ~6 Q" l8 `' U
  130.        for($i=0; $i<$aL; $i++){    % m! A: T9 R* v7 ?+ _# p. G% v- `
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    + p+ M6 V9 V1 r& B5 Y2 w' j% w, s
  132.        }    " ]+ h5 {1 e! ~8 O, ^
  133.    
    ' O+ |8 S: D8 M& H5 L& h* i
  134.        return ($distance<=$allowGap) ? true : false;    ) `0 `" N' C. ?' i( V
  135.    }    2 |  M1 I( {4 |1 v
  136.     ! {. R/ h, T# B  P
  137.    
    # g5 U+ K2 ~+ X. S5 [, W: J
  138.    /**比较两个图片文件,是不是相似   + N; u) j: Y# D6 _! E
  139.     * @param string $aHash A图片的路径   ) ]# V" s* d  |4 T
  140.     * @param string $bHash B图片的路径   
    " ]* K, J8 j1 e( x" O
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    " ]# T, m8 \  G! R4 c) G- r- j, d
  142.     * */   
    0 @$ c; b6 W5 n  w, y2 r
  143.    public static function isImageFileSimilar($aPath, $bPath){    7 C5 ]3 r5 L: f
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    ) w( N  Y# e0 B  K6 n
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    & d, W% {1 ~. p6 N8 s
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    1 M. _3 I. a& A1 h' M
  147.    }   
    : N0 ^2 D# v8 o" @* g1 U* N
  148.     % w: O) }( i3 x3 H2 b7 v
  149. }7 \  R0 S5 J; y# i0 ?- \
复制代码

. a% w6 r- I' {) I; @, C: F% u& \" T6 }6 ?4 k
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:47 , Processed in 0.104480 second(s), 22 queries .

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