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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

" E( g7 Q1 M9 X: y" i8 I( N5 @

, w1 B8 [) x- r6 c. o6 j由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

8 u. p1 r9 \# ~/ b1 N% |
  1. <?php    $ M' ]4 l+ M2 L+ y
  2. /**   
    2 x$ E& i$ P# Q) l( U1 r3 s
  3. * 图片相似度比较   
    , c4 h8 C! s5 r8 t
  4. *   + M$ z+ P& C6 _" S, u
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    * X: Q, y$ F. ]+ K( E0 }: U  l
  6. * @author      jax.hu   
    : k9 A4 t7 V1 X6 e' p) r
  7. *   ! k% s# i3 x5 ^  }" u
  8. * <code>   
    & }" a) S( O" _+ B3 j5 c9 u' K
  9. *  //Sample_1   
    7 m* ]7 V- N5 O7 N6 V
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   2 _9 s8 E$ y: i# W; E; D# V) o
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   0 `; ^. S) u. _" R3 R* U2 f
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   & ]: u* o6 k, c$ R# j6 L' ]
  13. *   8 d4 L; J/ h7 g& G, C* _0 D
  14. *  //Sample_2   ' |2 _7 T: R8 o
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    2 r/ s, F. _2 Q3 g6 k& P, i$ C/ B9 X
  16. * </code>   3 u8 ]# I6 ^4 K7 i, r" H; S
  17. */    8 O# ~$ y- o( R
  18.     - i2 O5 d$ ?0 `2 m
  19. class ImageHash {   
    8 ?0 S, ~( Q* o4 j0 f5 w8 G
  20.       m& x' C. J" g1 t, D" z
  21.    /**取样倍率 1~10   8 q, @3 h# Z" T
  22.     * @access public   3 V5 R9 a. h. I4 X; `
  23.     * @staticvar int   0 e2 K& U- {# \7 }
  24.     * */    " R2 j% D. D' G
  25.    public static $rate = 2;    / N; B8 r8 n- i0 C# o/ o
  26.     / |* E1 j" Y3 P: G5 V
  27.    /**相似度允许值 0~64   
    8 N- u2 K9 O4 U4 P, O. K1 X# Y+ R' r& F
  28.     * @access public   
    % h& {* c  S) E
  29.     * @staticvar int   2 X) Q( E- X$ L. L+ p: C
  30.     * */   
    & G' e% K# E9 Z' @
  31.    public static $similarity = 80;    ( @( ^4 j2 `4 v
  32.     " z* k) H+ M' e* [7 q
  33.    /**图片类型对应的开启函数   
    ; L7 {0 d7 X& h: [
  34.     * @access private     G  Q4 ?$ o. O" u) s4 g
  35.     * @staticvar string   
    5 E) B% L% n) V- y
  36.     * */    ) P8 Y' E/ }! Q$ e: J( v" v. x5 `
  37.    private static $_createFunc = array(   
    ( m8 t6 {" I* Q- \- I6 d% a) B
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    2 R0 M. }4 E& G; y2 P) h  Y( @
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    7 L) b% V  X9 p
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ) K) ~) y) M# {& t: {1 I
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    % k8 M; f0 K' r2 n+ c! h8 E
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    - u4 E7 ?/ ?6 J; j1 @/ r
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    0 ~6 }4 O/ X- W3 B/ U! K8 o, `' E
  44.    );    6 t: v; j. Y. P' |! N; }0 d
  45.    
    2 m, D& m: Y+ a. \$ [3 v% v, N
  46.    
    9 M! F( T$ A2 [; b! I- k7 \/ [. m7 B# Y9 v
  47.    /**从文件建立图片   
    ' I0 a* o1 G! T" e
  48.     * @param string $filePath 文件地址路径   
    * o$ h: w' @7 F& {- |% ^
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   . H, M9 B' L( X7 h  F& }& Y# z
  50.     * */   
    ) T, t: `. G3 u8 z% y8 l: y9 r; j
  51.    public static function createImage($filePath){    3 B" o, x. `9 u
  52.        if(!file_exists($filePath)){ return false; }    ! F6 ~+ r/ P- |/ c4 V
  53.     " d2 m! L, e% U8 B9 e2 A
  54.        /*判断文件类型是否可以开启*/    ! u0 N; J) y/ i0 Q& t
  55.        $type = exif_imagetype($filePath);   
    ( b1 f) Z. z9 I* ?+ c
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    / ^( s3 p, L: Q8 `6 Q$ Z
  57.    
    ' n/ V3 J( h2 ~* n) a- Q% E2 A. S
  58.        $func = self::$_createFunc[$type];   
    ) K5 U4 S% P6 G0 u; F& U
  59.        if(!function_exists($func)){ return false; }   
    4 y% A4 j' Z3 Y/ U
  60.    
    . x% ~( A% p* N$ E2 |2 i
  61.        return $func($filePath);    ' w/ u3 O9 `' ]% p1 U+ v
  62.    }    + Y8 ]8 e7 S1 X2 u. C
  63.     8 G3 ?9 W* l0 ~
  64.     3 c! [+ f* z+ L' P0 e$ e
  65.    /**hash 图片   3 [3 a: n3 j5 {
  66.     * @param resource $src 图片 resource ID   - p; n% X/ s3 O
  67.     * @return string 图片 hash 值,失败则是 false   ! j$ P: f8 D- n" m3 @# @
  68.     * */   
    ; o* X/ U8 O+ C, j! I
  69.    public static function hashImage($src){      ]# d4 b" \* Z7 t
  70.        if(!$src){ return false; }   
    " o: r$ m  C, u" c
  71.     & I( g# y; ]# D# G5 {
  72.        /*缩小图片尺寸*/    9 g* {1 A0 `$ @$ ]7 z1 j) e, O. z# ^: L
  73.        $delta = 8 * self::$rate;   
    / Z" O; g- c+ }' m8 K3 A& O
  74.        $img = imageCreateTrueColor($delta,$delta);    8 U. Y0 Y1 R5 w
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    # D! E5 e6 m( i8 q4 s( F) m- S8 t
  76.     ) A6 ~. ~" P6 h0 v( h
  77.        /*计算图片灰阶值*/    / h$ C" d1 Z$ |: U/ j* e0 f
  78.        $grayArray = array();   
    * ?1 V; Y; K0 A* N8 V; F& t
  79.        for ($y=0; $y<$delta; $y++){   
    : x4 k0 z5 F4 r3 F4 a
  80.            for ($x=0; $x<$delta; $x++){   
    & t4 J$ I1 H. L1 V% c. L# n  ~
  81.                $rgb = imagecolorat($img,$x,$y);    , i% ]7 h$ n+ @1 y8 n
  82.                $col = imagecolorsforindex($img, $rgb);    . m6 q. y- w( @& S" L3 ~
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    : Q3 G& ]8 W% G6 F+ Q& u' z/ U
  84.    
    $ x) [8 f+ I& L6 T( ?; f
  85.                $grayArray[] = $gray;   
    ! O5 w& Y% j3 i/ n
  86.            }    5 o$ }$ z" k2 f  C$ w* k3 N! u
  87.        }    ( R) r- V3 C7 f2 ~7 H
  88.        imagedestroy($img);   
    4 J/ {$ M! r( G: i, r
  89.     ! n# h9 o. [  i" |0 o
  90.        /*计算所有像素的灰阶平均值*/   
    / v- O3 R, K% d3 `8 C3 L( Q
  91.        $average = array_sum($grayArray)/count($grayArray);   
    4 S# C  i4 R/ r
  92.     6 w% Y# G. G- o: c7 N
  93.        /*计算 hash 值*/    / ]: i  J5 _. t! g1 Z, F
  94.        $hashStr = '';    & o  _  `# l3 J9 Q" G8 L9 r
  95.        foreach ($grayArray as $gray){      U5 _, C+ k1 O5 F2 L' U
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ; K$ ^( N3 X& J
  97.        }    " K( [" z2 Z+ \; ~0 h9 h
  98.     ; {; z: Y* a2 ^, ^0 _* D( c3 S# d  U
  99.        return $hashStr;    8 t# |- J" g  ]$ d0 k
  100.    }   
    ; r" z% [, X! V8 v+ X
  101.     : U. e, G2 d9 @) M1 @
  102.     & J5 \) z/ A5 g) ?, a; \
  103.    /**hash 图片文件   $ C/ V1 Q4 ^: t: I! x$ h
  104.     * @param string $filePath 文件地址路径   
    % j) ^% Z" j; k( E
  105.     * @return string 图片 hash 值,失败则是 false   
    2 N7 A$ d+ e) ?& A
  106.     * */    2 I: m+ |" q. n) c* [' D, n
  107.    public static function hashImageFile($filePath){   
    $ }) |# B0 k: F6 Z4 i2 h6 w
  108.        $src = self::createImage($filePath);   
    6 s9 X7 G! {) V; G* b3 y# Y
  109.        $hashStr = self::hashImage($src);    * l' d) W% L1 l# `5 o
  110.        imagedestroy($src);   
    - }# g( l9 o0 L( v
  111.     ) k7 k2 y! @5 L8 L! K" t0 n/ ]
  112.        return $hashStr;   
    6 c6 c+ i+ }3 r. W- p
  113.    }    2 i% }5 ]5 z  N0 F& T" `! H; q
  114.     / s3 ^. {, a/ l3 A! [
  115.    
    , c% S$ l3 u$ r" b& f4 {6 n
  116.    /**比较两个 hash 值,是不是相似   
      y, |& A/ I" q* g$ A/ m
  117.     * @param string $aHash A图片的 hash 值   9 H7 X7 Y/ z& u9 i& Y. z
  118.     * @param string $bHash B图片的 hash 值   / c/ c4 X, k) |. i7 E; ~4 U
  119.     * @return bool 当图片相似则传递 true,否则是 false   2 z( n: }) X# K# h% \
  120.     * */   
    ( s  Y9 Z$ I& t( s8 j- A, [
  121.    public static function isHashSimilar($aHash, $bHash){    2 v( T0 T4 s, N: \+ J! i
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    ( X7 u( P5 M6 {. w% _. Y
  123.        if ($aL !== $bL){ return false; }    4 [- ]3 u7 A& b/ o6 r
  124.     4 j* D5 Z3 X- n  Y1 C
  125.        /*计算容许落差的数量*/   
    ! T- \% e# g8 Q1 r* l6 i/ O
  126.        $allowGap = $aL*(100-self::$similarity)/100;    * E( L1 `9 s3 d' I- z6 X  w! E8 Y
  127.     : R) b) r; o% _2 R4 F8 @3 I: }
  128.        /*计算两个 hash 值的汉明距离*/    * X2 ~) E- @7 k" _
  129.        $distance = 0;   
    # O* ?, N: q; J3 C5 b
  130.        for($i=0; $i<$aL; $i++){   
    2 f$ a8 t, d5 g; v/ T
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    3 Y$ d5 j& u: y% o4 w1 J
  132.        }   
    : l9 H, [# w7 r7 \
  133.    
    7 B3 L7 R3 G* F5 }8 b+ M6 D
  134.        return ($distance<=$allowGap) ? true : false;      @! A. r, G. K+ h* A- l% p
  135.    }    ; G3 K# A+ B5 S( [% v4 N
  136.     : g, Z% Y, d! ?, Q2 s
  137.    
    8 p, V5 U& C; P* K: V! |
  138.    /**比较两个图片文件,是不是相似   
    . X- |/ [+ R5 O/ p* t6 M
  139.     * @param string $aHash A图片的路径   
    1 j+ _% D' R  J6 m+ ]  a
  140.     * @param string $bHash B图片的路径   
    ; O& [% \2 s+ I# v4 }) `8 q( N9 R8 g  A
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    " d# k# }8 ?0 G5 y. h  y! f; a+ x
  142.     * */   
    7 g* q2 u) o" d+ k1 {4 n
  143.    public static function isImageFileSimilar($aPath, $bPath){    ) [+ h1 _' h' V
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    8 |6 X# Z( u. v+ [
  145.        $bHash = ImageHash::hashImageFile($bPath);    3 C* Z9 @4 t$ w7 N
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    9 ]% X% k0 h' [) R
  147.    }   
    / M# q/ c% E7 D3 r9 j" d
  148.     ' }4 t7 y; }9 J
  149. }
    $ |; C; y. ]: W% u$ p
复制代码
! y  W) E5 L3 |/ A% Y2 H1 M
( g! o6 k! c. ]% D! G8 T
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:00 , Processed in 0.108715 second(s), 22 queries .

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