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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图/ N6 H: Y! _' m3 j% Y
( ?8 G8 V1 J2 e3 J& ?, E" g
; R( C. V0 ]0 D; [* i/ E8 ?0 f" T
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
  B1 B! g! m0 \) L4 U# M
  1. <?php    - ^% ]) Y) Y% ^' e2 v" h5 Q: g
  2. /**   3 A# m3 ?* w- ?7 R
  3. * 图片相似度比较   6 D! B& `2 ^( g
  4. *   , Z! [3 G$ r( Y' K
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    1 o2 k$ i& t) w4 h$ |: L
  6. * @author      jax.hu   % g* s/ ~; Z3 b9 v9 i$ k
  7. *   
    & L9 H" ]' H) j/ Y1 M9 e
  8. * <code>   
    ( d& T( r) v( ^  D
  9. *  //Sample_1   
    + y$ B$ J$ |  ^- h
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    / F7 S) t, V/ v( w/ W
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   6 o; k8 S. a% G( r1 p/ q* e) t2 Z: ~
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    5 {3 N5 _7 b' o  d7 [4 y
  13. *   
    ' p. o9 o5 A5 r2 ~& b& [
  14. *  //Sample_2   
    9 O; T7 _9 R" x8 U0 I7 [4 m3 }! {4 x
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    " g' {. o6 Y; E: o2 B* E
  16. * </code>   
    ; ^) [8 P5 z/ t6 z
  17. */   
    & a; W! C- [2 Q- P2 K
  18.     ( P0 ]# w( v  s0 i. j
  19. class ImageHash {      X: A, d% I# s4 Y+ }5 i) e
  20.    
    / L, j, `4 {. O
  21.    /**取样倍率 1~10   
    1 \  B* ?6 [) w: I. Y0 `: B
  22.     * @access public   * M+ v, O5 C+ m: S3 w9 O: x: _
  23.     * @staticvar int   
    ) m' C* s3 f3 q$ o
  24.     * */    ) H- s8 }. G/ ?( R4 w, X
  25.    public static $rate = 2;    * B9 l- G9 s/ g' l2 s9 N' L5 h" G$ p
  26.     3 a7 U3 J' |0 m( U# t+ f
  27.    /**相似度允许值 0~64   
    . R  ~' q! I' s" X2 J* O  B
  28.     * @access public   
    - q6 }) S; B9 _$ G: P! ^. Y9 q
  29.     * @staticvar int   % b" o8 j7 [% `& d+ ^
  30.     * */    8 Z4 R2 P& g  h5 l% V
  31.    public static $similarity = 80;   
    # v( \, n( \9 i8 V7 Y* I
  32.    
    . I" e8 R8 m( r" F8 B% y: s1 H4 \- ~
  33.    /**图片类型对应的开启函数   0 m2 O4 W# @; l5 {5 L  m: @! R. A
  34.     * @access private   % b, K( \. K1 H7 C# _5 p
  35.     * @staticvar string   ( _! w9 h4 v, w) U; p
  36.     * */    9 z) q' h! }& S9 b9 d
  37.    private static $_createFunc = array(   
    $ f6 `2 G% n( x% o% n
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    1 K! C6 p% t1 T2 v8 P
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    5 x8 ^% J2 q# v' v" N& i
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    7 w$ z! `2 r6 r
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ; Q2 K, X7 f* A$ }  \" G, y7 S7 P  L
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    * w; R4 y6 w) L& ], j  Q
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    8 g0 {. x- |9 n
  44.    );   
    + _' h6 R" w  I- N" O' R  ]) U
  45.     # q% M; D5 ?5 [3 i
  46.    
    7 d5 D! N4 G' b) p5 K& i
  47.    /**从文件建立图片   
    3 p/ c" x3 s/ C7 f) T: T
  48.     * @param string $filePath 文件地址路径   
    6 |5 M; u$ A5 ]- e) d7 J
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   " v9 v* V: H2 |" Q+ J
  50.     * */    8 `, G; B2 y, a# i) E/ y
  51.    public static function createImage($filePath){   
    4 I( N; m4 ]& z( K  {( i
  52.        if(!file_exists($filePath)){ return false; }   
    4 a/ y. h. [9 N' K* {8 \2 z- O
  53.     " C6 `5 `7 n/ [* Q# r
  54.        /*判断文件类型是否可以开启*/   
    2 ]3 D: _8 l" _& {' f$ F1 z4 a
  55.        $type = exif_imagetype($filePath);    5 v. O5 v" D. l5 R' M  b! Z" x
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    / ?' L( y4 w) H# ]
  57.    
    * p8 G* {) W# A" q9 \
  58.        $func = self::$_createFunc[$type];   
    & D6 T, c1 A- _: n) f4 l5 G2 i# v, q$ u
  59.        if(!function_exists($func)){ return false; }    , d, z, \: H7 b6 {( j9 F
  60.     2 U8 S8 Z1 o* D# K
  61.        return $func($filePath);   
    ; ~1 ~$ K% ]) c- N
  62.    }   
    ) p+ S9 R0 Z; D
  63.    
    2 m$ V# l# ?$ ^; x) s0 i
  64.    
    8 q: A! T* z' |4 }
  65.    /**hash 图片   
    5 D5 X/ e. B& j
  66.     * @param resource $src 图片 resource ID   
    ; S0 k+ G0 n1 W% A7 K, b
  67.     * @return string 图片 hash 值,失败则是 false   
    ( ?( V2 N/ e9 C0 V) y
  68.     * */   
    . S+ d. d: V& [7 {( O! Q9 ^
  69.    public static function hashImage($src){    1 [% m0 t' v$ E/ S! ^
  70.        if(!$src){ return false; }   
    9 |1 f1 f, J% ]6 p8 z! H
  71.    
    & v  e8 ?; K4 [
  72.        /*缩小图片尺寸*/   
    6 i* A% V3 Y3 X' F5 \
  73.        $delta = 8 * self::$rate;   
    & U9 v4 J% ]! R3 ?8 R* u
  74.        $img = imageCreateTrueColor($delta,$delta);    # g9 H$ x5 b( ~
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    ; k) ^+ W# U7 E) O1 N5 R
  76.     9 M7 f! K/ P4 ]8 d
  77.        /*计算图片灰阶值*/      X2 n/ s( j5 P
  78.        $grayArray = array();   
    + I: }( y1 W. ?% W+ x
  79.        for ($y=0; $y<$delta; $y++){    . a5 p8 J0 V! p. f
  80.            for ($x=0; $x<$delta; $x++){    ! D' A6 R8 G4 w
  81.                $rgb = imagecolorat($img,$x,$y);   
    + i0 T$ e4 H+ B
  82.                $col = imagecolorsforindex($img, $rgb);    9 C0 M5 w' h7 V$ M
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    5 F* h& ]& ?% y% y9 A3 y% m* ^
  84.    
    + U- _- m) J( r3 ?* W0 E! @/ ?
  85.                $grayArray[] = $gray;    % I5 p$ `5 d% q2 q
  86.            }   
    & @5 o) ~* w" b; n8 U
  87.        }      D% D4 v5 R7 e0 [6 Y/ Q
  88.        imagedestroy($img);   
    7 \3 c( O- ]7 I+ ?% \. F1 ^; o
  89.    
    8 }7 c, I" f9 K' ?# w
  90.        /*计算所有像素的灰阶平均值*/    " a7 c# {( X& K% H
  91.        $average = array_sum($grayArray)/count($grayArray);    # n5 c! v4 k% _" P! u: D
  92.     2 D$ i& D3 D+ A/ D; V* i% ]% f/ z
  93.        /*计算 hash 值*/   
    $ G" o; n: y2 l; _4 c
  94.        $hashStr = '';   
    " e% E" ]  Z. _
  95.        foreach ($grayArray as $gray){    ( T( X! g3 y- U' d0 ~: K4 g
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    / M6 t; A/ G* Q+ x) c, Z( Q, y
  97.        }    8 V- {! \+ E' a+ b- Q
  98.    
    - `' a5 t. j& f  D# R
  99.        return $hashStr;    2 X% @: d2 \( Q# A, ]
  100.    }    0 N4 I0 q2 }2 R# |
  101.     + z% V8 R: n. d4 J6 Y/ U
  102.     + L+ j+ |6 D5 V; E* J8 H5 ?9 v2 t
  103.    /**hash 图片文件     u: O4 L- R* h, j$ k$ u
  104.     * @param string $filePath 文件地址路径   
    . Z6 ^. }: _. `: D
  105.     * @return string 图片 hash 值,失败则是 false   4 j0 G( {7 d! m% x! ?+ c: V" a
  106.     * */   
    : B$ m2 i6 b. A9 d# m! [9 x
  107.    public static function hashImageFile($filePath){   
    " x; ]) I( _  E
  108.        $src = self::createImage($filePath);   
    7 m2 J+ Z) |/ l/ B& E$ ?$ Y
  109.        $hashStr = self::hashImage($src);   
    6 c* z: x# e* Y* \9 |: m* ~. J
  110.        imagedestroy($src);    ' K# {2 C' I$ ?- T* |, q: w- `5 v
  111.     ' P3 B& q* `1 V- G
  112.        return $hashStr;    % J, k* R8 O* z8 p: ^" x
  113.    }    + Q# T5 _  U3 F4 c* J9 U9 {
  114.    
    , I, F$ Z) t  E- d# m4 N5 n
  115.    
    , R: b2 ~) Q2 q1 M, `7 {$ P
  116.    /**比较两个 hash 值,是不是相似   ! b" Z  G, y: g- h9 \# Y
  117.     * @param string $aHash A图片的 hash 值   
    9 v6 x" ^' Z$ {# F: B' `; L
  118.     * @param string $bHash B图片的 hash 值   . S" R8 V1 ~( A
  119.     * @return bool 当图片相似则传递 true,否则是 false   ( o& A8 L: K. G% ]; a
  120.     * */    0 I4 G/ E. z$ F2 ]( \
  121.    public static function isHashSimilar($aHash, $bHash){   
    . Z0 L& W% Y: K- S. L5 \; Q: w) c, m
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    8 w9 a( `, q) u  U4 g# o- H! m
  123.        if ($aL !== $bL){ return false; }   
    : x4 I! K' c) ]
  124.    
    # u* h& y, }: z  \$ [
  125.        /*计算容许落差的数量*/   
    ( F* x6 ]5 f, b3 i. X* B
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    5 R  S7 L7 F5 Q3 \6 N8 }
  127.    
    ! d& i( i& L$ O( ~6 H/ C. u9 W9 S
  128.        /*计算两个 hash 值的汉明距离*/    2 F9 ~: [) Q' Z# P; {: a
  129.        $distance = 0;   
    : K& q. N. O! t& J
  130.        for($i=0; $i<$aL; $i++){    : j: Z" f( v4 L- T, r# Q7 R
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    % S% V: w4 [: f# q$ E( S/ S
  132.        }    ( ?8 G! F* C* x6 R# o7 f" d
  133.    
    , i0 Q: x3 P* H( C
  134.        return ($distance<=$allowGap) ? true : false;    % C+ q% O  _% q% H0 V4 ?
  135.    }   
    , q' O1 w( M0 ?0 ?3 `4 ?0 ^
  136.    
    ' y  p& s: J2 n4 o& @" j0 z
  137.    
      F$ p! Z& ]' N! r8 v
  138.    /**比较两个图片文件,是不是相似   - V; P* d/ _/ A5 G7 z
  139.     * @param string $aHash A图片的路径   
    ) B# B3 j( R: V5 B
  140.     * @param string $bHash B图片的路径   
      V/ t5 p- B7 z: _% s; f- B( a
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    / h1 h" u" M9 _7 S2 b, m1 r' F- U
  142.     * */    1 u3 r% p# E, N& ~
  143.    public static function isImageFileSimilar($aPath, $bPath){    . ?. C! g1 j2 u
  144.        $aHash = ImageHash::hashImageFile($aPath);    / g+ c( D/ d6 A  U! V
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    : f0 j# |$ j2 b$ h2 ~
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    / J# A1 F. C3 X- J% [, `
  147.    }   
      J/ t% {2 Y- y" C* W* A
  148.     ' C: t0 x' e( @# }, G
  149. }
    ! O# V( d1 m$ s3 N8 A3 ?
复制代码
2 a/ x" C+ G) n4 g! z& m# \
5 A$ h- e( n) j1 k; O
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-9-27 20:16 , Processed in 0.147387 second(s), 21 queries .

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