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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

( s: e! ]3 V* k
9 b  N' Q& I% i# ?  |" _
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

; M) y8 l- S( H% v# N4 K
  1. <?php   
    9 @& V* |8 r4 M  S
  2. /**   
    8 d9 b* w/ R6 J0 h- o! u
  3. * 图片相似度比较   
    & m3 ]/ b8 d: H2 z5 J. [3 Q( |4 C
  4. *   
    - g/ {. {/ o+ u  v# }: Y9 q
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    " w4 V/ w8 W( c% B0 a' C! |
  6. * @author      jax.hu   7 X+ q% ^6 z) a$ M3 D) r
  7. *   1 _1 U: ?+ R" G8 C! T6 Z! N8 ~0 F
  8. * <code>   
    ( ]2 v4 J# h* A8 r
  9. *  //Sample_1   . z1 u4 _. ~8 a) c5 n# s
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    - }. e* q- H. m4 c
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ' a  @- y1 V2 o
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ' Z2 q$ L+ i9 e. P- V1 T  T) `7 y, u
  13. *   
    & E7 Z/ b1 f2 y0 ]: a4 X; p/ P# p  q
  14. *  //Sample_2   
    % s! A; C3 f) I7 l
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   ! N$ x0 y8 R: t  H: A; `
  16. * </code>   , t, L  f, `; H' ]* h& o9 W2 t
  17. */   
    ) a  N1 V5 f; b% h2 z% p' T" C/ X
  18.     - k% ~% i% z( c+ w& l* A/ r" ]
  19. class ImageHash {   
    + `; ]! m* j$ _0 Q, ~5 T
  20.     # e" T( R9 k4 ]9 O6 V4 I
  21.    /**取样倍率 1~10   # z6 u* j: A/ p: ]& n
  22.     * @access public   
    2 n) f7 T$ G' W1 |" L
  23.     * @staticvar int   4 q' g! }1 B9 Q  O) a2 U/ n
  24.     * */   
    ! b5 y/ u/ A6 m7 X, N/ D: K
  25.    public static $rate = 2;    # G( G5 c) G  l
  26.    
    ) J" z6 d( |/ Q5 P) u
  27.    /**相似度允许值 0~64   
    1 X& [. l( _' V+ D* R
  28.     * @access public   7 E2 s. j: [8 x) D. c
  29.     * @staticvar int   0 \, T5 x$ s5 O8 N  n) Q4 Q
  30.     * */   
    2 V* v, }- q: u/ _3 C
  31.    public static $similarity = 80;   
    8 M, C  f$ G5 m4 v: {. f
  32.    
    4 h5 \( I+ P7 Q; O
  33.    /**图片类型对应的开启函数   
    ' m% o: p9 e' g6 }+ F
  34.     * @access private   
    + Z& f' `: A. L' a% L3 i# k
  35.     * @staticvar string   
    9 j6 A& C: b1 X
  36.     * */   
    : Z/ I3 n: A9 {# T
  37.    private static $_createFunc = array(   
    3 N/ G" S, |! w+ [8 C1 S
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    * L& Y. Y- j" {( y
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ) ^9 D7 C! R! n) M
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    5 k2 f8 v! k; `$ t& c! i; w! X# B
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    , ^, t: v8 W& j. J
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    - S% e/ \1 g6 x7 c) {
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    ! f/ D/ \3 q% g6 X/ G# a
  44.    );    - F7 c( o2 g! ?0 L/ v( V. G& Z  [
  45.    
    / `( U( k2 p4 s' g7 z
  46.    
    , M$ I; T/ M  _5 ?( U* H/ K
  47.    /**从文件建立图片   2 V2 a: ^0 G! M+ i8 b
  48.     * @param string $filePath 文件地址路径   
      }' _; r4 U% z7 y  _8 e$ G
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   6 |% _; q" I  L# x8 R  T
  50.     * */   
    2 h9 \& K8 x; m) ~" M9 u
  51.    public static function createImage($filePath){   
    6 v* H% e! b6 f' I! |! \0 d9 J2 x
  52.        if(!file_exists($filePath)){ return false; }    / {' d& {- X5 x% B( ~- F( _
  53.     0 ^4 a. ^$ j9 D3 x0 T% a1 I: e5 f
  54.        /*判断文件类型是否可以开启*/    ( `) R2 L: F+ A: v/ g
  55.        $type = exif_imagetype($filePath);    % b5 r$ a2 Q# K$ t8 `& S" }
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    + p. C# R' k( l5 G
  57.    
    ( [' E( i% a& J& ~
  58.        $func = self::$_createFunc[$type];   
    ( m2 {0 j9 |+ C' j' o- E
  59.        if(!function_exists($func)){ return false; }   
    - B9 N" |& N% S$ f8 C7 t
  60.     , R" l( i3 D+ f  Y3 c! @2 N
  61.        return $func($filePath);   
    ! M+ b  x( v  p" d' X/ y# l0 V1 F
  62.    }   
    ' E0 v8 ^8 L8 l; O+ T
  63.    
    2 W8 y& q! w1 n# q: o
  64.    
    2 v1 Q. L9 w) D- f0 W' {
  65.    /**hash 图片   
    + @+ e1 Y$ r+ c
  66.     * @param resource $src 图片 resource ID   
    8 O3 ^' h) i" D) o; P3 L
  67.     * @return string 图片 hash 值,失败则是 false   
    . K' p  K8 ^! X  ^* S1 a0 @) u
  68.     * */    / C- i' R0 N/ T
  69.    public static function hashImage($src){   
    ' X- ?# ~+ Y/ E
  70.        if(!$src){ return false; }    / v3 o  p; q* q+ k9 p# z
  71.     & i  i  F# y) D- a; f- Y: c
  72.        /*缩小图片尺寸*/   
    8 L, U9 C4 ^! ^% I
  73.        $delta = 8 * self::$rate;    6 U) |6 c, J3 l' D2 |# q
  74.        $img = imageCreateTrueColor($delta,$delta);   
    . u  r& s; Z; B+ f3 ?
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    * t& C& |" \. s/ b* T
  76.     3 f' p8 @+ C' Z1 q
  77.        /*计算图片灰阶值*/   
    3 X- B6 W7 M* d* s" C0 R5 l) G# v
  78.        $grayArray = array();    2 |  h& ?4 ~1 @! U
  79.        for ($y=0; $y<$delta; $y++){    ' z8 c! r- r  v+ Q9 ]: p
  80.            for ($x=0; $x<$delta; $x++){   
    . k  G1 _( L, c8 ~- b) U
  81.                $rgb = imagecolorat($img,$x,$y);   
    . v# V1 W3 {5 X
  82.                $col = imagecolorsforindex($img, $rgb);    7 b4 J; K4 K0 B3 d; i6 H3 P
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    # m5 X5 l$ i4 l- r: [
  84.     , j# n9 |5 ^/ e: @+ Z
  85.                $grayArray[] = $gray;   
    2 Y7 h, ^. H- P: p/ p0 ?8 r* F
  86.            }    3 e- h2 _2 u' P4 X' K' I
  87.        }    $ Q& l2 r" U3 ^! U2 I
  88.        imagedestroy($img);    2 |% ]% T2 B3 c
  89.    
    / R8 V/ ^0 Z, Q+ T# s/ Q8 L( ?
  90.        /*计算所有像素的灰阶平均值*/    4 {5 \- A+ ^( N- `( a$ W3 q+ N
  91.        $average = array_sum($grayArray)/count($grayArray);    , P6 H! |, Z6 r
  92.    
    % U6 D# r; O9 f$ X$ g
  93.        /*计算 hash 值*/   
    1 E# O3 z; b5 p, k
  94.        $hashStr = '';   
    , P* g0 h/ D: _$ ], @
  95.        foreach ($grayArray as $gray){   
    ( u3 d3 u; P. N- B
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    " q' \! l2 T8 R9 F
  97.        }    ( D9 u# ]% F2 ~
  98.     / [4 k" U. k/ M# R, W: B
  99.        return $hashStr;   
    1 u  Y6 r2 L! W. U5 y9 n
  100.    }   
    0 `2 C) d* P4 Y' |/ m, W6 n
  101.     " x  c$ C7 O9 y$ n/ Z: Y! p
  102.     9 E& L8 t7 t" @
  103.    /**hash 图片文件   / z& |/ ~4 w9 N* q! X8 q: Y
  104.     * @param string $filePath 文件地址路径   
    ! g& _4 u/ K' N3 R
  105.     * @return string 图片 hash 值,失败则是 false   8 F* G6 H9 [; l" i, b& |+ Y
  106.     * */   
    - M0 l6 A# q" U! R% q
  107.    public static function hashImageFile($filePath){   
    . N( g% P6 N! h+ j4 [% m
  108.        $src = self::createImage($filePath);    ( i% ~. H1 P2 a1 P1 ^% f
  109.        $hashStr = self::hashImage($src);    % x& P5 @: b: T& H$ n
  110.        imagedestroy($src);    1 J0 ?1 u+ o- X0 z1 w. W
  111.     ' b9 G# ]( ?1 c! z( V
  112.        return $hashStr;    7 |5 f) ^; W6 E& T* @8 y  V
  113.    }   
    & F5 X" ?* ~' G# U
  114.     " A' s( }( s4 s7 e, f4 T5 ~
  115.     $ k8 Q' k6 T( |" N
  116.    /**比较两个 hash 值,是不是相似   
    . ~! ~/ j' {  h% P% ^1 {8 f/ C
  117.     * @param string $aHash A图片的 hash 值   
    # q( s5 _/ q2 e' i! l8 i* g& S0 U7 a
  118.     * @param string $bHash B图片的 hash 值   
    + G5 Z6 V. i: n# q' z0 u
  119.     * @return bool 当图片相似则传递 true,否则是 false   ( z: X. y; H# d+ w% q
  120.     * */   
      d4 i( c* ~$ S1 L  S: I; M" F
  121.    public static function isHashSimilar($aHash, $bHash){    / I3 l" L* z; h2 X
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    1 r7 l' r6 {7 ~8 Q
  123.        if ($aL !== $bL){ return false; }   
    8 {6 @" J  u" ~' ~6 c+ `- j9 n4 ^
  124.     2 E+ C  h  o+ d
  125.        /*计算容许落差的数量*/   
      ~* d3 e' @  a
  126.        $allowGap = $aL*(100-self::$similarity)/100;      s/ d) o, \% g2 p
  127.    
    $ a$ D& S2 U$ O! `9 \& Q# D
  128.        /*计算两个 hash 值的汉明距离*/    : X  l2 B  g9 E6 f7 j
  129.        $distance = 0;   
    : W: [. V% T. o: r
  130.        for($i=0; $i<$aL; $i++){   
    7 P# F# T3 v0 j! w# Z/ R
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ) t) e! u" v& N) ^: q# N" U. L" X
  132.        }   
    " d5 t$ P/ ?2 P4 f' r
  133.    
    , J( K1 d, x. m# I0 k# G
  134.        return ($distance<=$allowGap) ? true : false;   
    1 ?4 m1 }, w! U- F+ n/ A
  135.    }    & J4 M2 [9 I- P
  136.    
    ! S- ^+ j- U0 @* N
  137.    
    - e  D4 H( @: g0 L: U! ~# a
  138.    /**比较两个图片文件,是不是相似   
    % Q" x" |8 R0 A: |, A
  139.     * @param string $aHash A图片的路径   
    - ~+ N: h6 ]+ c$ {# u
  140.     * @param string $bHash B图片的路径   
    7 t, [  Z$ ^5 a, ], Q; h
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    * ?! J( [7 E8 Q9 k: N& x1 X
  142.     * */   
    1 J2 _2 e1 r% {+ D7 p
  143.    public static function isImageFileSimilar($aPath, $bPath){    ) l4 E# ]  q0 n* m
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    3 K; \6 J9 {6 U% v* Q, V
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ' |  D/ ~# o2 @- }
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    6 m$ U) o, g! U
  147.    }    + \/ ~8 {1 m% Y. E
  148.    
    8 e4 G4 D) _0 \1 r  z+ @. E
  149. }
    9 o5 |: D; Z" P9 p
复制代码

; ]3 p$ v$ O3 D8 T' Q
3 l& a$ ?( G( @
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-2 11:50 , Processed in 0.142062 second(s), 21 queries .

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