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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图, V% g7 O* ^0 _$ v
% ]8 x9 ?% f) [: S$ t
6 h( ?1 r" B: S) S1 g5 c
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
; @6 C& p. ]; Y7 {# ]/ k% j
  1. <?php    6 H% n6 A! d0 M
  2. /**     {; R  E  f+ i6 C7 e- c
  3. * 图片相似度比较   
    : A+ P3 ]5 x/ |, C
  4. *   
    * e4 k7 l! x; J- G' n" u: m
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;    L7 T# x9 t+ Y# m- F5 E0 k
  6. * @author      jax.hu   
    7 F  o( j5 \: z# m
  7. *   # h/ a. U8 x3 z# ~' F0 C! j6 p4 P0 ?
  8. * <code>   
    % `6 G4 S, \/ d& C- w" d
  9. *  //Sample_1   & V9 R- D1 h  b; P7 u+ p4 d0 K" x
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   # a; x) q6 O6 V9 [/ P- ^9 \
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   8 }/ f3 F  e9 E6 p; Y& j0 a& ]
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    5 g8 M% \- b) g# h/ l* ^3 S
  13. *   0 h$ ^# {: S4 R/ ]- H. @8 G
  14. *  //Sample_2   
    + Z* V2 L% G3 _5 D- z* Z2 N
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    + A) ~9 s0 M, V% t' A
  16. * </code>   
    1 J  ]$ n4 o; x" z& z, C& z1 S
  17. */    4 E3 p: t8 j$ `* }0 R, E; X
  18.    
    # ~) E0 J/ \9 D& R
  19. class ImageHash {   
    3 S7 D+ f. [: k. Z' f
  20.    
    & Q& v/ T9 l" A, q. D7 h" F* l
  21.    /**取样倍率 1~10   4 }7 C3 F1 o# N) I* r& O
  22.     * @access public   , C( W' N) p) s5 k* d# a; {8 j
  23.     * @staticvar int   
    ) r; ^0 Q8 l7 N7 A$ O
  24.     * */    1 }+ F, W' t7 V  p1 ?* f7 b
  25.    public static $rate = 2;    7 N, d* J- N) m# F, G+ L+ w
  26.    
    . Q9 E+ K" X; _; q7 w. g/ O$ s, G
  27.    /**相似度允许值 0~64   
    - m  B& l8 T( ?6 v6 E: B; r, K2 A* T+ B
  28.     * @access public   ( p) F& x4 ]$ x: X- n
  29.     * @staticvar int   * Z! `# `, \( S8 i
  30.     * */    5 ^  y: }' M4 j
  31.    public static $similarity = 80;   
    0 n! K4 G& p  I$ M3 I
  32.     3 E& H2 P( I8 Z' q
  33.    /**图片类型对应的开启函数   
    # _/ t0 o* k2 |3 p
  34.     * @access private   - k2 ]2 |4 a4 I3 X
  35.     * @staticvar string   
    ( F' |' _- m: G
  36.     * */   
    : w$ A! R7 q$ W3 U) p
  37.    private static $_createFunc = array(      [; `" P" i$ l& G* f2 g- i5 D; V, t
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    " E+ h8 L* P. }& C8 e
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    + b5 X) s0 M! H9 `( j( O, e: k0 V" V
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    ' k' G# R7 _9 T, O% i
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ) d1 \7 `" }; B; C9 u
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    % y1 m  L" e) k! e5 H
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    6 \, U, r% e# P8 s  `  i
  44.    );   
      g, O$ @) Q* J$ q7 v, d
  45.    
    9 S9 q! B: a- U
  46.    
    ) K& Q3 w0 M7 U% b% x
  47.    /**从文件建立图片   
    / N: X( c) u% p; J: a7 w
  48.     * @param string $filePath 文件地址路径   7 `6 g( H! r6 q9 H, H+ H
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   5 e: \/ F/ Z' d- x1 ]5 \' N. _
  50.     * */    / y1 k5 t+ l% a) y- z
  51.    public static function createImage($filePath){   
    : S. M( `* R# g/ H" I
  52.        if(!file_exists($filePath)){ return false; }    # Y  D% }7 l( P4 T( {
  53.    
    0 E) ^1 V9 B8 O) I3 u1 J
  54.        /*判断文件类型是否可以开启*/    * f5 M8 D4 F4 X8 `) H# d; n
  55.        $type = exif_imagetype($filePath);    2 Z+ W: H' O- Z: Y$ X5 ~/ J
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    : ]7 T3 ^) h$ l+ b
  57.     2 l, S1 g8 |! `/ f! F7 \
  58.        $func = self::$_createFunc[$type];    ( [+ q! A& B0 a& _
  59.        if(!function_exists($func)){ return false; }   
    , k# w3 F$ j) D# b
  60.     ! f: I7 e+ Z9 l. I: r
  61.        return $func($filePath);   
    5 p) ~$ s( ~. x0 U
  62.    }   
    * g& `( |3 f; u' W/ j" o
  63.    
    5 X% O/ R/ k- S! L4 X$ a
  64.    
    + d; m3 m/ U4 ^
  65.    /**hash 图片   
    ' u& R; f# w$ |2 B
  66.     * @param resource $src 图片 resource ID   3 q4 O1 Y7 V  V) \
  67.     * @return string 图片 hash 值,失败则是 false   
    - T, n# }1 P; Z% B1 a1 o
  68.     * */   
    0 [- X) e2 i3 W
  69.    public static function hashImage($src){   
      Y0 T, ^' m( F& L" B% g
  70.        if(!$src){ return false; }    9 V/ v1 F0 A" c
  71.     9 M  D" a( T7 z1 R
  72.        /*缩小图片尺寸*/   
    0 F+ y* U- P5 B
  73.        $delta = 8 * self::$rate;    # P8 ~- W' B& ]! H
  74.        $img = imageCreateTrueColor($delta,$delta);    ( X9 v, j1 Y- V% n
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    7 O: E5 L$ y* F7 ~6 F* G
  76.     + p& i" I4 g. V, d9 p# w
  77.        /*计算图片灰阶值*/   
    8 n, }) F: d: u
  78.        $grayArray = array();    & a2 p" O* I# ]' K5 S+ @# m! z+ F  {6 S
  79.        for ($y=0; $y<$delta; $y++){    % y1 ?2 \0 V9 D3 H9 O- U; k; }, w; n
  80.            for ($x=0; $x<$delta; $x++){    ! f8 G+ C# O# p' M& ^# C" C0 D; g
  81.                $rgb = imagecolorat($img,$x,$y);    , v, X& H' U; @+ v, y
  82.                $col = imagecolorsforindex($img, $rgb);   
    2 h, U4 G4 C+ B( y7 b2 O/ r( a
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    ' h! c8 L- h6 V* v- t
  84.     : J5 I& a3 q  `( P6 S- }) r5 D
  85.                $grayArray[] = $gray;   
    9 k+ {. t; |' |- [6 S% P
  86.            }    & s" H% z7 \. g2 ?6 t
  87.        }    6 O; P" p0 z9 V' P% f% `
  88.        imagedestroy($img);    + w8 }9 ^6 |; L$ y% [/ J  }  d6 V& g: n+ d
  89.     0 s. u+ t# ^/ ^4 j: W4 k
  90.        /*计算所有像素的灰阶平均值*/   
    : G' X3 X+ h  t9 m; u" z
  91.        $average = array_sum($grayArray)/count($grayArray);   
    2 R& q$ G4 ~8 w: _4 ]* R! X0 S* ]
  92.     * ]0 J! n0 P3 U; f
  93.        /*计算 hash 值*/    5 {, A% F9 q/ d7 r/ x
  94.        $hashStr = '';   
    9 }- O/ n+ K& [! G1 h' i. \) i
  95.        foreach ($grayArray as $gray){   
    2 V) X9 g9 o5 t# K2 Z) p+ d' \
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    % R- ?- O3 \2 A/ \1 M" S
  97.        }   
    % ]0 S6 {( W2 M7 {/ [9 \
  98.    
    3 \$ ~9 C4 @; [" r5 B- m
  99.        return $hashStr;   
    , f1 e9 s8 s: K0 @( j/ ^# D
  100.    }   
    # P1 X/ i; T# `* A$ p
  101.     * Q* a5 u1 @8 |8 D0 A+ T
  102.    
    % [5 ?/ l- A- |" @6 E( R* ]
  103.    /**hash 图片文件   ) D+ Q" ^3 R2 B
  104.     * @param string $filePath 文件地址路径   9 A- t" F  I1 E, P4 s; P
  105.     * @return string 图片 hash 值,失败则是 false   3 c! U; o, @, m( H: n( |, r
  106.     * */      ~2 i' s. j2 k& h
  107.    public static function hashImageFile($filePath){   
    6 x0 w  S9 G7 o4 ]. J! y+ {, f
  108.        $src = self::createImage($filePath);   
    7 Q6 ]1 O) G" x6 k
  109.        $hashStr = self::hashImage($src);    7 x. V' e! I9 u: C( c8 @
  110.        imagedestroy($src);    * @4 X/ U8 b! W* f0 T- S
  111.    
    ) p: H+ H! E3 x
  112.        return $hashStr;   
    3 Z; |9 x8 A# n( L2 U" b  a$ k
  113.    }   
    $ B3 \3 g; n* ^. O
  114.     % Z9 C6 U  H% b" T0 }
  115.     ) u/ \. {! u% W8 i/ _
  116.    /**比较两个 hash 值,是不是相似     E4 f1 |3 g/ E
  117.     * @param string $aHash A图片的 hash 值   
    , E$ a( m0 w" e
  118.     * @param string $bHash B图片的 hash 值   
    5 f. A( c+ w8 i. i, i+ q, r$ e
  119.     * @return bool 当图片相似则传递 true,否则是 false   # T& X( ]% d+ O, v* j6 Z
  120.     * */    4 d( h, ?% A- I% j4 t
  121.    public static function isHashSimilar($aHash, $bHash){    , s& F* [- f) ]) l
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    & b. r% Q4 X) B" E( n, Y2 M
  123.        if ($aL !== $bL){ return false; }   
    ; w) w8 l% _! c: \1 H( c
  124.    
    2 X8 p" L: @# r% t7 J, M& F
  125.        /*计算容许落差的数量*/    7 g$ e9 N" b& \' K
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ( j3 n' P* j& F; g( c& T
  127.     ( ^; m% l4 u$ N$ W) g0 N- v5 M
  128.        /*计算两个 hash 值的汉明距离*/    + z/ c' S1 v& w; ]8 t4 a5 }: H
  129.        $distance = 0;    ( Z! q" G8 G3 Z
  130.        for($i=0; $i<$aL; $i++){   
    9 D/ a$ d6 K! }. D; I3 H
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    ' L9 N' d" [4 m1 k6 ~
  132.        }   
    / `( M/ F0 M$ e7 P9 V2 O
  133.     5 r. ]+ t4 C/ x0 _
  134.        return ($distance<=$allowGap) ? true : false;    ' `$ ?8 l! b4 J
  135.    }    / l( Q/ F1 n% G# R9 n2 h6 w
  136.     , B5 P# B! f2 @. ^
  137.     9 i& P8 s# D% g8 n; a8 q) I& g
  138.    /**比较两个图片文件,是不是相似   
    ; o6 A0 }6 U, m$ `/ _4 t" L
  139.     * @param string $aHash A图片的路径   & }: [) q9 w; Q2 {( J2 l' E! a
  140.     * @param string $bHash B图片的路径   
    ; y. l6 m8 i6 Z5 E7 ]
  141.     * @return bool 当图片相似则传递 true,否则是 false   ( Q  X( B( P1 j- ~- s6 |+ q2 F
  142.     * */   
    & k1 K, N% k( A. I0 e5 R
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    * d( C7 o$ Y% R/ ^% Q6 y) B+ X
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    # |  a! y6 z7 F1 r1 L1 s
  145.        $bHash = ImageHash::hashImageFile($bPath);    3 r6 ?8 S; W/ K0 [' i
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    * E( F2 U* d+ {3 l
  147.    }    + p/ y* Z3 Y( o5 d3 z: P5 y
  148.     4 H* K5 P) U. W. P
  149. }
    - H- Q0 z, P7 y% ^8 G
复制代码
4 y& [6 z( J/ Q8 s$ V* S+ k

- o" L/ _, b) s9 Q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 05:39 , Processed in 0.066461 second(s), 20 queries .

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