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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

, |5 I# z* M2 ~* Q4 ~5 a- a
. G: c# t5 {2 `; i+ ^  i/ [
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
1 ^0 L% H: f0 {0 a% F2 [
  1. <?php    5 Z/ G, }! x! q- E
  2. /**     `. C) F- d4 l+ v' J1 }; X
  3. * 图片相似度比较   
      n, ]" T+ o7 ?1 I  k! b* u' R
  4. *   
    ( [  ]& [0 n: C
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  0 ]6 ]5 {! o$ k* {% l
  6. * @author      jax.hu   7 n6 D/ s# c: }) ]1 u
  7. *   
    8 h  p- v$ Z7 ?! [" \" I( b' n
  8. * <code>   
    ) c# x$ h6 R, v8 }7 P
  9. *  //Sample_1   8 k4 E4 C8 L: i) w( e' z+ x' b* v8 X" g
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   ! U( C6 j8 f/ Y6 z  H
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ' k% n# D+ \& A: u& B) i
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    . e) r, g! c3 y9 n5 F+ b
  13. *   
    * k. }: d' X; c
  14. *  //Sample_2   $ p) ~& t; i4 u
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    ! R2 v" D( S% I' C- T
  16. * </code>   
    # U. x( y4 s" s5 C1 \7 i' X
  17. */    7 R9 m' S* Z+ l8 B
  18.     + I- V" J4 R) \, Z5 d
  19. class ImageHash {    - Q/ E  b" B" s
  20.    
    3 a0 L: v3 x. T0 H* E
  21.    /**取样倍率 1~10   
    5 O0 i$ D0 X, e& Q
  22.     * @access public   # a+ t: ^# p! m! r8 B' U
  23.     * @staticvar int   + m" a0 I9 e  B* W9 H
  24.     * */    / M) g3 T1 u" p! j
  25.    public static $rate = 2;    1 T, ^8 P7 Y# J7 L8 c
  26.    
    1 R+ W4 _6 A: G: f
  27.    /**相似度允许值 0~64   . |0 |6 L7 n( f/ b  Z7 }. ^2 `
  28.     * @access public   ' U3 U0 z; m6 X: Z: N
  29.     * @staticvar int   ) Q# a$ z* c/ Q5 o" R
  30.     * */    - P4 c; b4 S; J3 ^8 [
  31.    public static $similarity = 80;    1 S* S7 c; o) ]; @
  32.    
    6 Y5 U* ~7 \9 Y6 l1 j
  33.    /**图片类型对应的开启函数   
    3 N5 D( N: N( y4 n1 p, E
  34.     * @access private   8 W1 O" |& m1 ^4 }
  35.     * @staticvar string   
    2 L5 l$ r1 x2 N) h: B
  36.     * */    9 {! ~* f' e5 c
  37.    private static $_createFunc = array(    " T2 I' z0 O" u" G- h
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    & W1 n2 f+ v: k
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    ' G( y% ^3 l2 g( M
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    3 q: l+ {2 a0 s" g& X
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    + a; g1 a- \# Y/ \6 e% l, p1 B
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
      S2 x; o9 v% A; Z( o+ {
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    ) `$ B: y: @) r  X( z
  44.    );   
    5 t; k! U. I; s5 a
  45.    
    : R" B2 O$ i' E" S3 {( H; Y5 L
  46.    
    7 Y* d8 m' }1 P( L# B+ t7 z
  47.    /**从文件建立图片   
    ) A! U- X2 X' P0 Y6 ~$ t
  48.     * @param string $filePath 文件地址路径   
    / F9 I& ^) X  `9 |% o
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    9 i) G5 p, S8 o
  50.     * */   
    : s- [) {3 r* P+ n* ]
  51.    public static function createImage($filePath){   
    * |9 p8 e, D! O9 u0 ^& n
  52.        if(!file_exists($filePath)){ return false; }   
    # \% X" ~$ M- C. S- ~+ W
  53.    
    , m( M1 }1 _/ ]! [$ _
  54.        /*判断文件类型是否可以开启*/   
    $ C' H/ P5 _/ N8 ?1 N! E
  55.        $type = exif_imagetype($filePath);   
    3 k) O( @. y  T7 |1 k
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    ; i( G. F* F: S& w% T
  57.    
    3 R2 b7 A1 G  [5 _+ ^
  58.        $func = self::$_createFunc[$type];   
    ) l% b% J" N8 {$ I8 R1 v6 \
  59.        if(!function_exists($func)){ return false; }    # s+ s$ y) u  E& X
  60.    
    4 ^3 m. F' \$ u) V7 M
  61.        return $func($filePath);    5 g8 Q3 V2 e9 ~9 v& B; ^
  62.    }   
    / J% s4 m1 y7 ~
  63.     8 Y, |: B6 I7 i1 Z1 e
  64.     . J7 |+ s- [) U& y0 v- S& K1 L; o
  65.    /**hash 图片   
    ( F8 P. p7 R, V5 L+ l! I- g: b
  66.     * @param resource $src 图片 resource ID   / \9 v  [+ [' ?/ H$ U7 ^0 h; e
  67.     * @return string 图片 hash 值,失败则是 false   % G1 {; a1 S4 }# Y6 G' ~5 l
  68.     * */   
    6 d7 p. L' y. X; J  d! n; R  V
  69.    public static function hashImage($src){    7 e' D1 B1 K  ~; R# }2 \) h4 i
  70.        if(!$src){ return false; }   
    + g- m! r0 ]2 p& M
  71.    
    - e) Y; F2 \2 ^( Z
  72.        /*缩小图片尺寸*/   
    7 z) o" }2 E6 U( }( Z% b
  73.        $delta = 8 * self::$rate;   
    1 N! v8 `- F0 T1 o
  74.        $img = imageCreateTrueColor($delta,$delta);   
    % Y$ G! g  c! U, r; r6 k$ G
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    9 S. |+ C. \* I3 j* I) i4 X. M+ o
  76.    
    9 O0 _; T5 l4 v, k' \% T
  77.        /*计算图片灰阶值*/    " x8 O3 S; B: E: x2 J! O* f" A
  78.        $grayArray = array();    0 ?3 y) k1 k9 r6 p0 |
  79.        for ($y=0; $y<$delta; $y++){    9 h6 c+ I1 e& x& I; m8 w
  80.            for ($x=0; $x<$delta; $x++){   
    # S9 I) w7 W/ C) p
  81.                $rgb = imagecolorat($img,$x,$y);    ! N5 a4 D: N* l, v- l9 ]
  82.                $col = imagecolorsforindex($img, $rgb);    - r; R7 I0 C3 ~6 E- H3 R' r
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    / W5 S8 V- l: ?  Y. d- K
  84.    
    0 B  W% z$ g: u. ^8 d8 t% I* p
  85.                $grayArray[] = $gray;   
    - M' W. s" ]% ]/ P- w. D; A: N$ h
  86.            }   
    0 _! g6 ?8 t" j/ w. z, Z2 @
  87.        }    * n) j* h0 i, O1 T4 b. V9 P' W
  88.        imagedestroy($img);    : j5 d; T1 j  K
  89.     : M1 T& l( L$ o9 {0 k. C; K
  90.        /*计算所有像素的灰阶平均值*/   
    7 x0 a. T' I7 ^3 _$ D- d
  91.        $average = array_sum($grayArray)/count($grayArray);      W, n( v, Z( W- |4 d
  92.     1 e8 d# k# @5 f: n! d/ e
  93.        /*计算 hash 值*/   
    * x+ {7 T9 ^3 m) h# E
  94.        $hashStr = '';   
    ) l5 W  Q2 I9 r% Q
  95.        foreach ($grayArray as $gray){   
    / E5 _! |1 q8 |& @0 j
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ; {5 p) M' ?, _: \7 [0 u
  97.        }    ) Z" _" U7 K& G2 g! N
  98.    
    8 g! C. j' F0 R# O/ U
  99.        return $hashStr;    % t8 U8 f3 |# U, f. w% N7 T
  100.    }    ; s: B4 J3 X& j1 M8 Z% R/ P/ r
  101.    
      E" x+ N# I* w# [5 D0 L
  102.     . q. B2 N; l: |) z3 g  r) j
  103.    /**hash 图片文件   
    - i) S, ^7 D9 f. A! m0 m8 C
  104.     * @param string $filePath 文件地址路径   
    # Y* g. P) J# {  s1 i$ C
  105.     * @return string 图片 hash 值,失败则是 false   2 o3 w3 U9 V7 b! a9 r, M
  106.     * */    ( x1 G; z5 s$ @2 c/ a
  107.    public static function hashImageFile($filePath){   
    ) b0 O( k. t8 c  u
  108.        $src = self::createImage($filePath);    : S: ]8 w! k% e, d" D
  109.        $hashStr = self::hashImage($src);   
    * \! |1 T$ U5 E: b$ x4 V
  110.        imagedestroy($src);    7 I; C9 c6 ]+ ]+ y9 z
  111.    
    # m* d' |, I) t' V, G6 ]7 \4 G# R2 L, {
  112.        return $hashStr;   
    6 O  g7 E' R( V* _
  113.    }    / g+ }4 O5 E$ a# ]6 U4 X
  114.     . w( R8 V! }1 E4 a9 A
  115.    
    . g7 R; K0 l$ S6 L  m$ d" R
  116.    /**比较两个 hash 值,是不是相似   
    & r' g! ^4 K- D$ Q( `" _. e
  117.     * @param string $aHash A图片的 hash 值   : B0 k6 E4 F( M9 B
  118.     * @param string $bHash B图片的 hash 值   , p& Z& n; V! k  B
  119.     * @return bool 当图片相似则传递 true,否则是 false   ; y: H/ n0 e) M' W5 w) x2 p1 W
  120.     * */    % ?' ^1 c( n/ `  p3 p( R
  121.    public static function isHashSimilar($aHash, $bHash){   
    ! c& F- ~% ^" Q5 ~6 u' X
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    , P0 H6 d" ]  Y, |; m8 S
  123.        if ($aL !== $bL){ return false; }   
    8 [; }( |; N$ c! z
  124.     % s) u2 C" a+ ?4 ]
  125.        /*计算容许落差的数量*/    5 F: m  V+ o9 u( C- _; o
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    % ?# S+ C! X; z$ I3 Y& B1 n0 Q. c
  127.    
    . U& q; o, E/ j+ G: o0 o
  128.        /*计算两个 hash 值的汉明距离*/   
    0 _% C6 {) n5 E1 T: V  w
  129.        $distance = 0;   
    % i) k# Q1 l( Z" P
  130.        for($i=0; $i<$aL; $i++){   
    * H. d9 I' |' [- F! t
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    , ~+ ^9 S" j. |2 X3 ^
  132.        }   
    2 J; |7 O$ m  |+ _
  133.    
    / W# ]1 L4 r: Y1 I8 z! l" n( i
  134.        return ($distance<=$allowGap) ? true : false;    ) T1 X' O- x2 `
  135.    }   
    1 x& j3 t1 B. R( b5 T
  136.     ) V' f5 R( b. V0 i) t) f
  137.     : x& P2 p3 J( U8 H
  138.    /**比较两个图片文件,是不是相似   
    ' `* A; u/ P8 O0 v$ X6 \# _% F
  139.     * @param string $aHash A图片的路径   1 \8 @% V3 a2 O5 Z7 Q" }0 g
  140.     * @param string $bHash B图片的路径   
    & J( C; K5 b" D% P: w9 \: _
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ) Z. N, O  z+ A$ S8 ^
  142.     * */    : A& O: D3 G# y; T* W, j) k
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    - ^. z9 O4 b" u2 I2 s7 j; X6 |! l
  144.        $aHash = ImageHash::hashImageFile($aPath);    # e& B! o9 D3 o4 z+ \3 o
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    ) z5 `1 b! K( F& M, b' k
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    $ ^# o- k( y& x9 x6 C) @
  147.    }    1 b% i9 J, K0 g
  148.    
    0 z* Z- ?/ s7 D  j* Q
  149. }
    ; i- i% E- m4 r" U  [
复制代码

! @% G; }+ K$ o+ y
$ \5 l- i1 N1 K* O6 p% I
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 17:51 , Processed in 0.082816 second(s), 19 queries .

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