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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
5 r! }6 _& x( ~/ G  y$ Q! E4 u- d* H' ^% ^$ }0 \" I
, l' A% |; g9 o1 d. W
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

& R. V9 F9 a6 X. K3 x, L
  1. <?php    2 x) A8 `. r6 A
  2. /**   & ^# o( C- z' m9 @8 e7 I( A' E4 f
  3. * 图片相似度比较   
    # J8 w* Z8 b% K+ M& b
  4. *   
    ' |, L/ P2 J* D( k8 i: Y" J2 j
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    * V  y' g, n: ^
  6. * @author      jax.hu   - S4 W0 o3 b+ ?! M$ }
  7. *   " {  k. M( Q* T- W1 J7 @
  8. * <code>   8 o: N: e7 Q0 \
  9. *  //Sample_1   ' t% i3 @, |9 O4 ]! }8 {
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    : e  M, r+ A& s) k) |
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ) x! j/ C; p( G: a9 ?- {. r
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   4 M+ l7 |4 }6 ~4 n* W
  13. *   / {3 ~. {1 {7 J/ W
  14. *  //Sample_2   % `- s$ P. E( c8 \
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   : _  S* E. I; x% c7 N$ H
  16. * </code>   : P5 L! I; G' o& j# P3 e. U8 @( T6 R
  17. */    ! g; b  X) l, W
  18.    
    4 t6 L) ]' o5 l/ D/ j6 [3 b
  19. class ImageHash {   
    % ]/ K' T& x4 \! m" V
  20.    
    . N0 Q& _& e, M( ^$ |( L
  21.    /**取样倍率 1~10   
    " n$ @3 z5 x9 F" {$ I. a* f) J
  22.     * @access public   
    ' F8 A6 o/ ~% i3 i% p" x8 {
  23.     * @staticvar int   4 j$ b" _+ d- \3 Q) L5 Z8 R2 ?
  24.     * */   
    # I% z, ]% h9 ~1 Q; I
  25.    public static $rate = 2;   
    - r1 y& y4 p2 @+ `
  26.    
    " d5 h% Z7 @7 c& _' m5 `( X
  27.    /**相似度允许值 0~64   4 U' B0 u/ C, A& F0 ^
  28.     * @access public   , k4 V. O7 V, V7 @
  29.     * @staticvar int   
    % i* P7 V2 d+ N; V. p
  30.     * */   
    ) ~9 r7 W8 W6 u
  31.    public static $similarity = 80;    & z7 l% E8 ^& B1 c9 u  j4 D+ k
  32.     / e5 k! B2 W0 J" @; [6 J
  33.    /**图片类型对应的开启函数   3 U! E8 w9 F- l  M0 [
  34.     * @access private   # S: z+ R, C8 Q* R3 O: [# Z- x, d
  35.     * @staticvar string   4 |* ^# P" w. f. n+ B
  36.     * */   
    : I/ `5 W3 s! @# c+ S; y
  37.    private static $_createFunc = array(   
    4 O6 K8 `$ B, c* d- B2 }$ f
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    / k! U$ Q' v9 W# o" I- J, ]; U
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    4 o, u0 A& {; V% D
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    - g) U8 I; ]" ]
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    . `6 E) v7 g: D; O
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    0 `# e, U) @) f2 D1 D0 W" A
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    0 H+ ^; s3 X' @$ l$ t3 ~. V9 ^
  44.    );    3 M$ B. [& h3 j# T
  45.     * D+ H, b6 q6 W
  46.     * p; c) Q# ?1 B, e  }
  47.    /**从文件建立图片   3 @# |6 N. |% G- `/ o) p# u
  48.     * @param string $filePath 文件地址路径   & a7 `: i6 _3 R; m4 C' X
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    - Q+ @$ R( ]6 s. Z# _
  50.     * */      P. \5 V2 e. ~! f
  51.    public static function createImage($filePath){    / U+ p& S0 H6 Z2 i% G
  52.        if(!file_exists($filePath)){ return false; }    # ~, `4 N! k6 T1 e& U
  53.     ; C. H( G8 H. M* o
  54.        /*判断文件类型是否可以开启*/    : H. r- H* V1 \/ P- z! B- T
  55.        $type = exif_imagetype($filePath);   
    $ t( B: `: ^1 C2 H9 v
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    ; W$ _4 v" J3 x6 _
  57.     9 Q1 U5 M% m* O) h
  58.        $func = self::$_createFunc[$type];      b8 I$ Q; _" ]0 w# Z
  59.        if(!function_exists($func)){ return false; }   
    5 m- b$ F6 L2 c# I. [) ?
  60.    
    * \" K- {7 h9 R
  61.        return $func($filePath);    4 {. T5 p* w% W7 j  ~
  62.    }   
    4 g1 S$ C' A4 n* F# Y
  63.    
    % w; t* c+ r- Q" _
  64.     & A3 G7 ^0 N. u; B/ T
  65.    /**hash 图片   
    ! p- e% o$ r  W+ w
  66.     * @param resource $src 图片 resource ID   3 g! T0 t1 p5 Q/ ], ~; e! _
  67.     * @return string 图片 hash 值,失败则是 false   
    1 o+ @. c- G* E: J
  68.     * */    ; d9 y! M' Q9 r
  69.    public static function hashImage($src){   
    8 P6 G5 o' r  ?+ K, G* d5 d, w
  70.        if(!$src){ return false; }   
    ; }6 @, W* i& K0 W; o! P+ N8 C
  71.     # n. Y+ D- j/ @" {  W# M
  72.        /*缩小图片尺寸*/    4 L7 V+ t# ^6 Q$ H8 J% i
  73.        $delta = 8 * self::$rate;    ) y, p9 u3 ^% R& \2 S* v" C# {( ?
  74.        $img = imageCreateTrueColor($delta,$delta);   
    ! ^$ ?/ G4 U, s* K0 l( A0 s
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    3 F: ?4 h; ?- I% X. Y. |. s
  76.     3 \1 H. B/ v2 K
  77.        /*计算图片灰阶值*/   
    9 _' P3 ?* V, a
  78.        $grayArray = array();    & C! k1 l8 c. |" z/ x& v
  79.        for ($y=0; $y<$delta; $y++){   
    9 d7 x; c/ _# q: `& p# I
  80.            for ($x=0; $x<$delta; $x++){    % Q, {/ t- }& l6 X
  81.                $rgb = imagecolorat($img,$x,$y);    ( B# [, M; K1 X4 S
  82.                $col = imagecolorsforindex($img, $rgb);    : _+ {3 J) K- N; b) i2 n$ w
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    6 `, W& K" ]2 Z% {, J, \
  84.     5 r) b+ I% }  d5 {1 \) v  ?$ u4 D
  85.                $grayArray[] = $gray;   
    7 n# L$ \$ S4 r' b
  86.            }    . @% k+ T  w. c" [, ]8 P# d3 |
  87.        }    * G1 M. z8 E- K
  88.        imagedestroy($img);   
      n! w+ y" I- f! ~
  89.     8 d4 T5 [' n" B
  90.        /*计算所有像素的灰阶平均值*/   
    0 i# L$ W1 [2 k- o; a
  91.        $average = array_sum($grayArray)/count($grayArray);    ; y- A8 V4 J, e
  92.    
    # U3 U  r, r# q0 c
  93.        /*计算 hash 值*/   
    8 A, V2 ~& ^) o; ~( ?& q4 e: i
  94.        $hashStr = '';    3 C; P4 L, t# ?" d9 _8 L
  95.        foreach ($grayArray as $gray){   
    5 |6 i' A+ n9 U8 z
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    1 k0 M2 s9 o/ t5 N  [
  97.        }    2 b, x5 }5 \/ {- |  Q9 u- ~# ~
  98.     ' @0 r) n3 G2 n) N3 G: c
  99.        return $hashStr;    ( k2 q/ w. H% `$ k7 K4 d: f" t
  100.    }    2 I6 x3 X, t0 h: G) Z7 t
  101.     2 q. ^: [1 Z" M+ J" h& V: V! j
  102.     ) y6 u5 }6 ^3 a4 \( B" _) d
  103.    /**hash 图片文件   & q2 o0 w% ~# |: ~2 O( J! K( J
  104.     * @param string $filePath 文件地址路径   : {) A8 [  u5 _* ~) r0 R* v$ E+ Z
  105.     * @return string 图片 hash 值,失败则是 false   
    0 D+ }3 N4 }  ~$ }
  106.     * */   
    5 o/ i# C2 g, G5 Z: E8 `
  107.    public static function hashImageFile($filePath){    4 h1 y+ T: j/ `: O' z/ r
  108.        $src = self::createImage($filePath);   
    5 M# ^8 I8 t; M4 o& P$ H1 x$ _
  109.        $hashStr = self::hashImage($src);   
    ( y% D- X* V8 M
  110.        imagedestroy($src);   
      [. u+ h! ]" k" s+ s2 `
  111.     0 L0 U9 V: T& [
  112.        return $hashStr;    & R9 b% Z$ i. Q
  113.    }   
    - E- D. }" X' I8 l/ J" m: {+ g
  114.    
    ( V2 e3 i0 D. N  ~3 G
  115.    
    2 [9 [' I7 Q1 e) o
  116.    /**比较两个 hash 值,是不是相似   2 b3 w2 Z& e; z, X8 E% }8 I
  117.     * @param string $aHash A图片的 hash 值   ) i' s2 x8 w7 x, u1 _0 [
  118.     * @param string $bHash B图片的 hash 值   
    7 e  g  N6 m9 ^5 q( v1 ~
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    % k5 N/ [$ z/ d/ `! Z5 b
  120.     * */    3 w* z. W" n  y: W/ H
  121.    public static function isHashSimilar($aHash, $bHash){   
    . ]; d. w8 c' H: x1 [  a
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    : q& O$ C( O% W) Q
  123.        if ($aL !== $bL){ return false; }    2 d, U# k1 f/ L' l
  124.    
    5 D+ V. Y$ a4 n. [7 G, _( y
  125.        /*计算容许落差的数量*/   
    6 E9 x6 Z3 ]$ Q' b/ S
  126.        $allowGap = $aL*(100-self::$similarity)/100;    4 a5 ^7 o4 u4 R0 B, }$ h4 |  J
  127.    
    / k6 W* R0 F8 p- b; k" ?& T7 [
  128.        /*计算两个 hash 值的汉明距离*/    8 U% N. I% {/ Y, p( D
  129.        $distance = 0;   
    7 y0 C+ r1 [6 P* Y' S& }3 G  t
  130.        for($i=0; $i<$aL; $i++){    " x' I0 J' N$ h, o# q
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ' w: }& [4 h1 u: q  ]
  132.        }   
    2 R/ ?& y) U$ k: q; h) e0 b
  133.    
    : N7 Z; C- [$ }2 Q
  134.        return ($distance<=$allowGap) ? true : false;   
    + d7 C- [/ p0 A; p: `: ?9 ~- _
  135.    }    0 x, _& Z7 r$ g+ T9 t5 c
  136.    
    + r/ p$ v9 B7 P0 M0 s7 s4 w
  137.    
    ; B  m, e. m2 V2 v; b) A$ m
  138.    /**比较两个图片文件,是不是相似   
    8 B! {' @4 ~% [/ O: V
  139.     * @param string $aHash A图片的路径   
    3 g) U0 Y3 f- [+ L
  140.     * @param string $bHash B图片的路径   
    2 b- J" l# @6 @8 O: \; z( W
  141.     * @return bool 当图片相似则传递 true,否则是 false   ! b. v4 b. C; `7 {+ D
  142.     * */    + C2 P+ r' G, |5 n7 ~! o
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    4 J4 \. j' {" p5 F/ K
  144.        $aHash = ImageHash::hashImageFile($aPath);    ) P+ b' f. l8 G" r: I
  145.        $bHash = ImageHash::hashImageFile($bPath);    % [$ L; ?3 v4 f: f. ~) K
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    - F5 a& `* z* r! e- j7 k
  147.    }    0 @2 j' W9 r" u
  148.    
    + a  \& S$ d8 A& Z; O
  149. }
    * F, H! M! o: J; _. a
复制代码
, M# q6 }3 r6 h* g
+ n  O) I. `) l" C+ i  I; [+ a
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:03 , Processed in 0.105441 second(s), 19 queries .

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