cncml手绘网

标题: 分享一个PHP简易的图片相似度比较类 [打印本页]

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
) r& ?( ]) y' ^  I6 L$ p1 o- E
. u) ^$ O1 C( _. s8 w

& [0 }' l. i2 ]  z! M/ ^由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
& |. s% \8 e, z; h
  1. <?php   
    5 C( e8 ~, L% b
  2. /**   
    1 T. }0 p4 v5 k0 h, X
  3. * 图片相似度比较   0 A6 `1 L4 l# [0 n. X: j
  4. *   : I: W/ h% l: e" g, \2 D
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    1 q) [" o3 s, \, ~& B$ p8 T; S! y
  6. * @author      jax.hu   0 k: u' F- O, u: n& q6 D0 \, u7 I
  7. *   * O2 o  U) c6 |0 l  |2 R( z
  8. * <code>   * j$ o4 J/ X$ w: }
  9. *  //Sample_1   
      T  F3 F& i2 @+ M# Q
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    & p/ |! a  |) v" |( e6 h0 P, a
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   # g0 F% j. k& d9 e7 `
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ! o+ M. L: j& r$ v1 M4 d4 o  ]
  13. *   
    ! h- O; H# C4 Y6 m9 J9 ^
  14. *  //Sample_2   
    + ?. y, A+ u" \4 h8 Y2 u
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   + `. v5 P2 E  |' K" \0 u  p( I0 p$ L
  16. * </code>   ; o: u+ h" S! J
  17. */    2 _0 a, [4 v* {, m8 u
  18.    
    5 S0 Q8 B$ k1 }. H* G% ~2 P
  19. class ImageHash {    $ V; D- j& [. H& h& H4 f# H
  20.    
    - A' J: b: ^5 Y6 s5 U$ b
  21.    /**取样倍率 1~10   6 a+ w5 P! ?, z4 p. B. w& |# ^
  22.     * @access public   
    5 V9 ]/ {& }, r& x" f) V6 W& X  y
  23.     * @staticvar int   
    2 C% f0 Y0 k) V* p9 T# \" L& d: n
  24.     * */    ! x6 t7 k! m7 G  b( n
  25.    public static $rate = 2;   
    / r7 K+ B9 R4 P4 I: f  n& c
  26.     . S  c5 K3 ^9 a, ^( ~; Z! D" t/ p
  27.    /**相似度允许值 0~64   0 q, |% ?3 J+ D8 w
  28.     * @access public   
    % s( F: l4 t5 `2 {0 k/ N# t
  29.     * @staticvar int   3 H' p" v7 {. o* X5 M
  30.     * */    : J$ ]$ a0 _* h) ?
  31.    public static $similarity = 80;    / u2 {& E. s% k+ t+ ^' b" R
  32.     $ B/ d9 b$ V- o' `2 r) p! @+ S
  33.    /**图片类型对应的开启函数   * ^$ I7 |; d) y/ a
  34.     * @access private   0 J7 z4 [3 \  p3 f
  35.     * @staticvar string   9 b$ \! F4 n7 B( S
  36.     * */    8 _% [; N( n- R; F8 \
  37.    private static $_createFunc = array(    5 c3 }9 T. p( i
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    8 }3 |+ l# ]) i. z
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    + l; G) z: N2 q+ W4 ^+ h! k  G
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    & N) N$ |+ y: M" N, C/ Z
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    ! V/ [" {7 k- z" v6 H( S. Z$ }' t
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    # O8 S# M/ N+ w2 e4 r
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    , v0 T3 l" O# ^9 z2 [
  44.    );    8 m& Z4 o- u1 V* P8 u
  45.     8 I6 L0 f# Y% q% `% I
  46.     2 d1 P9 k' C) r' `$ f7 M- `$ O8 c! x
  47.    /**从文件建立图片   
    . z" |9 }! y2 u  D( Y' |& _
  48.     * @param string $filePath 文件地址路径   
    , o& T  W* @# E4 i2 W
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ' j& r0 Y/ i7 G' X2 r
  50.     * */   
    8 \8 Y: J2 O& a* g
  51.    public static function createImage($filePath){    5 m9 p, c) v4 X) b
  52.        if(!file_exists($filePath)){ return false; }    & h4 _% Y- \! `" B6 Y( s* I
  53.    
    ! v$ e& u; B* n+ [1 l: b1 E; y
  54.        /*判断文件类型是否可以开启*/   
    1 g9 J, o- ]0 k% P3 U0 d5 B
  55.        $type = exif_imagetype($filePath);    ; Y* M3 |' v  b2 h9 u2 d
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    * J0 y9 {- D4 x
  57.     ' T  \3 J/ B/ Q/ ^9 {
  58.        $func = self::$_createFunc[$type];    + k7 ^* E! i/ |6 L
  59.        if(!function_exists($func)){ return false; }    $ N9 b9 M' Y  v0 @* Z3 @+ p
  60.    
      X8 S& H$ c& [2 T
  61.        return $func($filePath);    . \$ Q9 g- x$ C) H$ d) }# @
  62.    }   
    $ w3 G6 I2 Y( }
  63.     ! \+ d0 L6 @5 G7 f( n- ~
  64.    
    2 B) x# l; h- B3 R" ~1 e, N
  65.    /**hash 图片   * K9 h- a. [5 C! ]& y. C' r' h/ k5 j
  66.     * @param resource $src 图片 resource ID   
      {* a' j' x+ Y" n6 E3 B
  67.     * @return string 图片 hash 值,失败则是 false   
    7 w% s2 P4 w6 g+ i, U
  68.     * */    : Q% t, D# C. Y# H( l$ T
  69.    public static function hashImage($src){    7 M6 U% Y/ ^. w9 }4 @1 D. {
  70.        if(!$src){ return false; }    $ Q; J3 P$ ~; P
  71.    
    ! [8 [$ C" [' @" L1 Q
  72.        /*缩小图片尺寸*/   
    1 J0 ^. U" y" q6 e! a0 T
  73.        $delta = 8 * self::$rate;   
    5 u/ J% J9 X9 H  C5 Q9 V$ ~
  74.        $img = imageCreateTrueColor($delta,$delta);    " p0 N$ d( R1 U# F1 \: h) k
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    # k, [6 d( M" ^, }8 G1 ?
  76.    
    ' y. X- ]' ?1 K
  77.        /*计算图片灰阶值*/   
    + a' d$ u8 F. f( [5 {* {
  78.        $grayArray = array();   
    6 Z5 f1 a6 o5 m: H* D
  79.        for ($y=0; $y<$delta; $y++){    % }% ~0 X5 M1 y4 e! Q
  80.            for ($x=0; $x<$delta; $x++){    & v0 c+ Q2 D* b5 e5 ^
  81.                $rgb = imagecolorat($img,$x,$y);    % q" O( ~) o9 Q) f2 ]' w; g' Z4 e
  82.                $col = imagecolorsforindex($img, $rgb);   
    7 ?/ t7 t' d5 n8 b* w: w
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ; _& r( I7 ^8 M" F
  84.    
    + Z: s& F* n$ Y
  85.                $grayArray[] = $gray;    + U3 z5 r# T% v7 v; Y
  86.            }   
    ; j5 K; B& X! J2 d( o8 L, k1 R
  87.        }   
    $ b2 k: m4 _( `; q: A! k0 M2 R
  88.        imagedestroy($img);   
    ) K4 N3 w; H+ v) X- Q1 V* @! s
  89.     : d% p  O* j, r  w6 n: @' q
  90.        /*计算所有像素的灰阶平均值*/   
    3 i+ v" ^" Z6 u, L# C, ^, T
  91.        $average = array_sum($grayArray)/count($grayArray);    , V1 |7 I. f& _: G, E' Q
  92.    
    ' Z7 ?" h7 g8 m, N# m' C+ k2 S+ L
  93.        /*计算 hash 值*/    $ @: v1 J4 M1 t. F  I
  94.        $hashStr = '';   
    7 g: k- ~8 v" w' u
  95.        foreach ($grayArray as $gray){    7 K! N/ }, E6 y2 V
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    % k+ B0 i8 p- M. D0 Y0 X
  97.        }    ! N. A/ W! z9 f! C" e1 S' A
  98.     5 z% d* O$ m, s
  99.        return $hashStr;    ) J# c% a3 S! z( m( p) p! {( U
  100.    }    2 H. ]1 a/ b( w+ P% X  C/ D/ ^
  101.     2 ^; T0 U* m" _/ w
  102.    
    * O& g7 n7 m/ W
  103.    /**hash 图片文件   ! o' r1 U2 p, {- Q5 d9 D
  104.     * @param string $filePath 文件地址路径   
    7 M' Y5 _+ _$ L' b- P9 {
  105.     * @return string 图片 hash 值,失败则是 false   
    & X0 |7 h9 Z$ s: ^
  106.     * */    3 S; C% L# K" \+ s# e# ]( J
  107.    public static function hashImageFile($filePath){    + x$ D. q! m! h) _' d# U# N# `2 W3 o
  108.        $src = self::createImage($filePath);    ( u- a! C" s+ X+ s3 Z. Z( W
  109.        $hashStr = self::hashImage($src);    7 F2 ?- ]: U, G& l; j
  110.        imagedestroy($src);   
    4 Y& ]* y/ ?7 D$ T* b
  111.    
    ' j$ ^* Y2 }; h/ z3 Q
  112.        return $hashStr;    $ a& {. @- S3 X* d8 J4 _, x
  113.    }   
    # ^3 g" m+ I  v( {. c0 p
  114.    
    $ {/ [0 G# D7 A8 S* `; t/ d+ R& E9 _
  115.    
      p) B# }* ~5 l7 n. y
  116.    /**比较两个 hash 值,是不是相似   
    ' [& u! t3 ?) I% J* A: ^) M
  117.     * @param string $aHash A图片的 hash 值   
    8 G. ]' k% U, L3 q( h6 X
  118.     * @param string $bHash B图片的 hash 值   
    $ t, _, l3 a9 s; X7 f+ c. A2 k: Z
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    : I6 F& ^- W2 l# S2 i+ T
  120.     * */    1 U) N* ~. j& w9 S0 p) g2 c
  121.    public static function isHashSimilar($aHash, $bHash){   
    6 [3 D" B  d" K+ ^- F2 N4 ?
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    ! {, V9 X1 E6 ], N& f% o& r/ W% k
  123.        if ($aL !== $bL){ return false; }    3 Y! A& A- X& U5 ^/ u- W( a  z2 y
  124.    
    3 L2 S! x7 M7 f) [" u* |! }- l
  125.        /*计算容许落差的数量*/    7 h6 @5 d/ }1 @9 f7 A) z) i& B
  126.        $allowGap = $aL*(100-self::$similarity)/100;    ' `$ g; N7 q9 X
  127.    
    7 x+ E& C) y. |0 U  n$ o- h6 a
  128.        /*计算两个 hash 值的汉明距离*/    ) `/ v& E  Q+ v- C( a" }+ x& J
  129.        $distance = 0;   
    ! R$ J+ E* o9 N
  130.        for($i=0; $i<$aL; $i++){   
    2 e  i. K& G% C& t- {! H% ?
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    & T5 G2 {# r, f
  132.        }   
    + c: T3 Z8 o1 ]* M5 g3 F" y
  133.     9 ~  s0 S& ?/ i$ j
  134.        return ($distance<=$allowGap) ? true : false;   
    5 \$ [: s' p5 k* S' G
  135.    }    : a' P( g  w% s9 w5 D4 B5 x
  136.     1 S( d, ^- Q; h% R
  137.    
    9 Y  ]% ]1 }) b. \  V# w8 X+ [
  138.    /**比较两个图片文件,是不是相似   
    4 V. P- n) }4 O+ {
  139.     * @param string $aHash A图片的路径   + P3 \' z# Z6 F7 k" l
  140.     * @param string $bHash B图片的路径   3 \: o% a1 y3 h
  141.     * @return bool 当图片相似则传递 true,否则是 false   1 T; w8 n$ [: j
  142.     * */   
    * g  b1 w  D+ J, \' b
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    ( \3 X0 n) @, Z2 a- [4 h
  144.        $aHash = ImageHash::hashImageFile($aPath);    ; y" J" k  u- U, u" J( C
  145.        $bHash = ImageHash::hashImageFile($bPath);    ! `) _' v2 G# J( ]! x3 N* ]2 C6 T
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    " k  t/ t. r9 f2 ?" k
  147.    }   
    3 x) o! F! l+ m) C7 U: p: U
  148.       A( z7 m+ ^, ^5 `+ z& b4 P
  149. }$ v6 a: X; E) w0 k0 x6 u
复制代码

3 y6 V/ A8 O1 G: ^$ R+ ]+ l- }' L$ J1 Y. W





欢迎光临 cncml手绘网 (http://bbs.cncml.com/) Powered by Discuz! X3.2