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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图% G3 a% Z2 A& W$ e8 ^  Y5 [3 B( D
: ]8 E5 V3 S! q0 O  j4 B

1 {. g4 l2 S+ G& o9 \由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

, U1 b% k& f8 q( P  Z9 P4 C2 W
  1. <?php   
    # v" Y4 M9 w/ [9 _, G
  2. /**   1 B/ T+ r0 ]( D) X6 q
  3. * 图片相似度比较   : g$ p- x% k+ e/ ]
  4. *   
    6 Z1 w7 a+ C& G* z4 q
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    2 X) C! c& Q" Q9 I
  6. * @author      jax.hu   ' y- ^; N; ~; y+ ?' c! V- T
  7. *   
    9 }9 l- d, c& f3 f5 Q! `
  8. * <code>   4 u/ A$ A0 b: H% W" P
  9. *  //Sample_1   
    . ^& @, f* _3 v- [; p
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   8 w# U+ g- G1 e
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    % j! R* B; S/ d+ p8 M& c- @1 A
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    & O# l3 k- c; c7 A
  13. *   1 f& f5 g+ m5 n: N( R: @
  14. *  //Sample_2   
    - \/ G$ z' W% j% ~: ^" g
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
      l+ P! X0 l0 M7 }
  16. * </code>   
    " a: {4 f" A' u
  17. */   
    $ I/ i" E9 W' U
  18.     2 P( u  }8 q/ }# I. K5 ?6 H
  19. class ImageHash {   
    $ O. d  @: l' J) e$ M& a4 ]
  20.    
    . I4 p' {: J! Q! A% T) Q$ o: _& M
  21.    /**取样倍率 1~10   
    ; z  n/ Y$ A1 r& W( I
  22.     * @access public   
    ( _$ Z  Z1 o- X7 l: i
  23.     * @staticvar int   9 x* u2 ?& Z; Y5 d5 ?  ?
  24.     * */   
    / p. g  P: z# D$ P
  25.    public static $rate = 2;    # x% B! l1 \) u/ P3 ?' Z* T1 t
  26.     % @* N* i& b: F
  27.    /**相似度允许值 0~64   
    9 s# K+ C& T- _6 A* S$ `
  28.     * @access public   
    - x) n$ H9 i: N
  29.     * @staticvar int   - F2 F* ^4 j) c* E2 m5 c
  30.     * */    7 l0 H' @* p' m: c  Y/ \1 |
  31.    public static $similarity = 80;    ( v9 m  z; [0 Q7 V$ ^) b
  32.     3 |- w! |: O& [3 r3 c& A# a$ j
  33.    /**图片类型对应的开启函数   # a; N% P9 r. s8 J& B
  34.     * @access private   
    & M: U7 ^5 O+ q1 L/ ^4 a3 ^) q, R9 Z
  35.     * @staticvar string   
      p, x* A/ j9 e2 G( j
  36.     * */   
    3 S# S: l" M0 j9 Y
  37.    private static $_createFunc = array(   
    % f# l- J2 |, C! g) f2 i
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    3 p7 i! G& g, z- W. Y7 s) u) F
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    . l# _% m' ~5 S. T
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    6 O) [* @" a4 Q4 ^6 m6 i5 \0 T
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    + r* b8 L+ H; Q  w
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',      _8 J' w9 Z% ?* P
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    2 B! T$ ^! o+ T3 J; h# u
  44.    );    6 m" E& c/ p4 Y% D! y) R
  45.    
    2 ~1 B) |/ ^0 W$ \( Q
  46.     ! P' k  ^3 C/ I5 {' G0 v* R
  47.    /**从文件建立图片   
    / H* b. j7 z+ h6 e
  48.     * @param string $filePath 文件地址路径   
    1 ^0 _; a8 S4 x
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ' f  R. r& P/ e1 K- e- m
  50.     * */   
    # d/ ~" `) k2 I$ v
  51.    public static function createImage($filePath){   
    ' \0 e: G6 `; R, d
  52.        if(!file_exists($filePath)){ return false; }    . t! W) b" g( G( |- ^
  53.     0 R/ C, S0 @! H4 Y! E( U
  54.        /*判断文件类型是否可以开启*/    ! t! W) T3 o7 t* p
  55.        $type = exif_imagetype($filePath);   
    8 q: z1 D# r4 A  v
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    , ~& t7 Q  H9 ?7 _1 {1 F
  57.     8 S/ o" I3 i$ U0 a8 Q8 L2 ~
  58.        $func = self::$_createFunc[$type];   
    ' G4 \5 V) h3 P: w% r& C' ?  z6 A
  59.        if(!function_exists($func)){ return false; }   
    9 O, [- G( h2 }
  60.    
    * _5 U, O) N0 ^. d5 F! X
  61.        return $func($filePath);    # F' h3 o  R9 l) h
  62.    }    3 W/ f- E  Y! w; u
  63.     5 E: _! w( r* g+ c
  64.    
    ) Z; x$ m! v& ~& s+ R$ c
  65.    /**hash 图片   , _2 b# f+ f; C% X1 y& L* B0 T5 `
  66.     * @param resource $src 图片 resource ID   
    ( k# j7 P7 b8 q6 J# A5 F0 c
  67.     * @return string 图片 hash 值,失败则是 false   
    6 I& g% t4 C5 I) A) N
  68.     * */    % M& {% n- D) G" j) X7 T# ]* r0 y
  69.    public static function hashImage($src){   
    # S& x8 D4 `' ?
  70.        if(!$src){ return false; }   
    * C% {: b+ B) F) g
  71.    
    2 A3 l; ~6 J6 }  ]$ l
  72.        /*缩小图片尺寸*/   
    ' Y& w" u! e$ X  b% l! S/ d) U0 R
  73.        $delta = 8 * self::$rate;   
    - `2 U+ M! J: v. @% [+ Y
  74.        $img = imageCreateTrueColor($delta,$delta);   
    5 b6 u9 R2 D7 H$ O
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    # g6 v5 G4 M: y
  76.     , a, R. o9 B: F8 b4 g9 v0 o) X
  77.        /*计算图片灰阶值*/    ; ~  U2 ?; ~: T: X1 K( z
  78.        $grayArray = array();   
    . s+ ^! C; F- z4 q0 W1 k
  79.        for ($y=0; $y<$delta; $y++){   
    " G! p5 j, \' C- q$ A
  80.            for ($x=0; $x<$delta; $x++){   
    ( A9 q4 g. x* v8 J2 K* j
  81.                $rgb = imagecolorat($img,$x,$y);   
    9 W3 O, t) G# V& \
  82.                $col = imagecolorsforindex($img, $rgb);    : s8 O) [+ p# R  Y! ^8 c
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    2 l- y/ V' F) \/ X1 t
  84.    
    ' o# p; n% O- W0 x  k. C. w
  85.                $grayArray[] = $gray;   
    5 r9 L2 w) U' W/ v) b8 v* D
  86.            }   
    , u7 j& q6 R: o2 G/ a, O
  87.        }    - n. U9 W0 [2 e! X5 T/ k1 V
  88.        imagedestroy($img);   
    4 D2 v# L3 E2 O# v" K
  89.     8 r3 Y1 D6 ^0 s& x
  90.        /*计算所有像素的灰阶平均值*/   
    1 |8 l6 s. @) e
  91.        $average = array_sum($grayArray)/count($grayArray);    ) V# j8 {* C* G* E# y
  92.     ) B( f/ p5 V2 q
  93.        /*计算 hash 值*/    # j' F; m/ E4 f' o* u
  94.        $hashStr = '';    , W- K* g( W2 C( L
  95.        foreach ($grayArray as $gray){    0 ?" L8 [! q2 E% a- w
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    0 o0 r, _; e" V  z0 Q, _* n
  97.        }   
    6 [1 U' `: z/ a- L0 R) Z- v; V
  98.     7 z5 M& b% a, i- z; ~& b
  99.        return $hashStr;    / i. s; q, H+ K& E" H
  100.    }    8 Z; G7 m# M  z9 e+ U
  101.    
    7 L. [& e) N8 ~8 M
  102.     ' y$ n! e% }& e
  103.    /**hash 图片文件   
    4 M6 I: j: F# D5 x9 I8 w
  104.     * @param string $filePath 文件地址路径   : g* W+ J# m0 s9 g
  105.     * @return string 图片 hash 值,失败则是 false   
    * [" h; ]7 b8 X9 Z7 D) p
  106.     * */   
    ; J5 x* ^6 j8 ^3 j, t
  107.    public static function hashImageFile($filePath){   
    2 k; c( d( g2 k
  108.        $src = self::createImage($filePath);    9 Z- g4 E0 s6 g1 `, W
  109.        $hashStr = self::hashImage($src);    9 P+ G  Y$ c. ]- I: Y9 V
  110.        imagedestroy($src);    7 ^0 x& c# t4 \
  111.     6 H8 `; o5 v4 Q  g5 s. W) J
  112.        return $hashStr;    5 V6 @, w8 b: _
  113.    }    ( Z3 B% l; L0 [3 o' V( ]5 K
  114.    
    9 v$ r- d6 ]9 x6 D) f/ Q
  115.     - F6 J3 j: r( q4 i
  116.    /**比较两个 hash 值,是不是相似   - q0 Z6 n# `3 x$ e9 Y& J
  117.     * @param string $aHash A图片的 hash 值   
    4 B# U7 Z5 Z5 V, T: ]$ U
  118.     * @param string $bHash B图片的 hash 值   
    7 \" o. Z$ I  |' S% ?9 c$ o
  119.     * @return bool 当图片相似则传递 true,否则是 false   # }$ P  i9 S* [, ~# s9 O: [$ W
  120.     * */    # H9 {( g( ^0 Z
  121.    public static function isHashSimilar($aHash, $bHash){   
    7 S1 z2 w: S4 l
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    0 Z/ T" k. Z* D% g
  123.        if ($aL !== $bL){ return false; }    $ D% J1 V; n+ A) u" M' R9 x6 e
  124.    
    - @% H" p& |/ }% q8 w3 c
  125.        /*计算容许落差的数量*/    1 `7 I8 R5 g0 r8 }# M0 a
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    4 ?3 x6 O0 r& X' W: p* [
  127.     " g% R) \. o  i5 S! \: |2 G
  128.        /*计算两个 hash 值的汉明距离*/   
    5 e, A# `+ Y4 f3 W& p
  129.        $distance = 0;   
    - C+ t$ x& [. [( Q
  130.        for($i=0; $i<$aL; $i++){    # ~( O1 b% C( C' [/ l1 G. w9 w
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    3 j4 K( v: y- @# I2 |) T
  132.        }    ) S& K- i$ X$ f8 m
  133.    
    " F- \, b, g5 K
  134.        return ($distance<=$allowGap) ? true : false;   
    , [* h4 g& i! s$ F3 S
  135.    }    " R4 [* p& k1 z5 A" Q6 [" D
  136.     : I+ T7 Q& L5 v7 I
  137.    
    5 T" J; |. j2 S
  138.    /**比较两个图片文件,是不是相似   
    4 }! ]. H; W1 m& e5 [
  139.     * @param string $aHash A图片的路径   
    # l5 v) }0 D6 W
  140.     * @param string $bHash B图片的路径   
    ' _" f4 Y; s: _1 T
  141.     * @return bool 当图片相似则传递 true,否则是 false   1 u" M0 A/ G& {4 I9 D  S. M) Q
  142.     * */    , e  ^& A" D4 ]/ _# M
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    9 p, f" M! H6 w5 C+ y, N3 Z% R. W9 ~
  144.        $aHash = ImageHash::hashImageFile($aPath);    . p7 e/ O1 a9 J- Q) \/ d5 R& U6 N
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ! Q; H# m0 t+ e0 S; l
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    + u( v) I. V5 `
  147.    }   
    4 \. w* _2 ~8 M$ }' e7 u- I
  148.    
    ( ~: A. l6 h4 l/ K; N( z, H, ]6 W: V
  149. }3 r1 n0 O( j5 T, m. f
复制代码

# ~9 J+ L! s% l$ r; L
" k) q. I: I  F- @) s
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 20:31 , Processed in 0.122493 second(s), 19 queries .

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