cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
4 }7 N. m" \! P- J7 ]% H! G" M9 N* C" F1 t
9 I5 {* v( ?5 N- E3 T& \
- N5 d  K+ W5 b# p* t, A
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

% E# e2 }2 `) B
  1. <?php   
    . `; K0 S0 ^! T' m* g
  2. /**   ' l+ O( E- _. t4 h$ M$ C
  3. * 图片相似度比较   
    1 |7 {7 R4 d; X
  4. *   
    ) U5 Y3 O) g$ I  ~
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    2 z3 @* t* X) J& T: z( K% H/ c
  6. * @author      jax.hu   " _/ \; C+ ^# Q9 O: J
  7. *   
    4 Y- I9 `7 M: O8 |/ g; k; j
  8. * <code>   
    ' q6 l$ _# x' I2 x
  9. *  //Sample_1   
    7 s5 B# t# R1 Y6 i+ Z4 H- Z6 P
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    9 F  r: c# N1 e% b$ y: c: N0 g
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ' o; Q, G" O2 H
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ' V  x( t2 L. `7 t
  13. *   0 ^5 U6 ?, j1 }8 Q2 L9 P/ c
  14. *  //Sample_2   
    ! t# d+ N4 t! _# t( b+ a
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   # Y1 ]6 ?( p2 x) O
  16. * </code>   / W3 y- W: |' H- Y* x, P1 n
  17. */   
    . n1 A( k7 v1 |; s7 s3 M
  18.     / H3 l" u# Y3 \% N
  19. class ImageHash {   
    8 j6 g/ b  }  I' W" w
  20.    
    3 P( G2 H  d9 f; ?! v0 a- T
  21.    /**取样倍率 1~10   
    " J0 T: J4 z1 r5 W3 @0 H
  22.     * @access public   
    # \# o9 j) m0 Z: m2 I
  23.     * @staticvar int   
    * `9 \) K' X6 Z7 p8 J& y- R7 f5 T
  24.     * */   
    7 _5 Q' O, e- [- O
  25.    public static $rate = 2;   
    ( k) s9 ]1 V' w0 L: Z
  26.     ' {/ R. l/ d. d8 T/ Q
  27.    /**相似度允许值 0~64   $ Z+ Q" n# _0 k! w' @
  28.     * @access public   
    , _, N! V( [% j6 o" _
  29.     * @staticvar int     q+ s5 ]* w9 D2 d2 D
  30.     * */   
    ' `2 Q* m- ~! V8 `7 b
  31.    public static $similarity = 80;    7 M- x/ w8 E% V2 g+ S4 L; L
  32.     + a: F9 C2 f- ^. i* X8 f
  33.    /**图片类型对应的开启函数   
    ) R" B! `0 h. D' R) f/ L) N3 A
  34.     * @access private   # t$ d9 b! U/ j3 v( Q& l
  35.     * @staticvar string   : t" J: L: Q3 o/ h. u, O3 M+ u
  36.     * */    % S* T( e' f, u  _/ y
  37.    private static $_createFunc = array(   
    ! t" v# c9 N2 _9 m/ n8 q
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    $ W& |, b1 ~& m! d
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    7 d" T# U3 f: M6 j) P# N+ v
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    * E% w; Y6 P  V. t$ t$ H5 ^0 @
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    - p8 _6 I1 ]% \! [- P- b" C9 U( V( n
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    , A' _1 I. u% n2 h/ Y# X! v
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    0 x2 m8 k2 h' ^( q# H5 ~5 Q
  44.    );   
    # `: D( T9 q/ ~' N
  45.     ) q( w9 w) c& i2 c4 z" ?. k) n5 U& ?
  46.     ! o7 N+ U/ x# \7 i" ]
  47.    /**从文件建立图片   
    - |+ I* r0 M& |% j% w
  48.     * @param string $filePath 文件地址路径   4 M( o4 O' S  q& G% v
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   : e( F: k( d+ l0 H" C
  50.     * */   
    ! @& _5 \. y- a, Z0 f
  51.    public static function createImage($filePath){    - ~! {  N  v# Y% x0 \5 I* ^
  52.        if(!file_exists($filePath)){ return false; }    8 I4 z/ p/ D! j' O3 i
  53.    
    4 A' b/ i1 V& Y! x# g6 U
  54.        /*判断文件类型是否可以开启*/    6 X( L9 T) i" X( v- [
  55.        $type = exif_imagetype($filePath);    + Y7 j1 Z7 n3 Y
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    : C  {4 @) m7 m# n) N, ?' U( d
  57.     1 J, O8 H: H7 A5 @6 N8 M+ t
  58.        $func = self::$_createFunc[$type];   
    0 h$ U$ {5 Z( l* _3 A9 ^
  59.        if(!function_exists($func)){ return false; }    ( [1 F7 h, ?! Q: p$ d$ W  z, M
  60.     * g, B) O0 ~" a7 M4 |8 a
  61.        return $func($filePath);   
    . L: G. K; q$ U9 h1 H  @
  62.    }   
    ' E3 F" u7 n4 u6 v5 I; B9 H4 m
  63.    
    - f' B: ~* |0 |- T
  64.     + j- r2 U1 D# n) F/ O
  65.    /**hash 图片   
    : C% f& h1 a4 g+ y# v
  66.     * @param resource $src 图片 resource ID   
    # i0 k" I9 S6 N2 s% r/ {5 `6 Y
  67.     * @return string 图片 hash 值,失败则是 false   6 L- D4 Q$ c' F  c3 d0 W
  68.     * */    7 s/ W  h& B2 O. Z5 T
  69.    public static function hashImage($src){   
    & p, o' h1 K9 P) z+ I( ^3 |
  70.        if(!$src){ return false; }    7 }9 g+ |; f! [; X  O, ~# L  a
  71.    
    ! d! y7 F; c4 ]0 \1 ?" S
  72.        /*缩小图片尺寸*/    0 j' P; w. G# Z0 k; U3 V1 W
  73.        $delta = 8 * self::$rate;    . ^# q: Y$ ]: d+ r
  74.        $img = imageCreateTrueColor($delta,$delta);   
    ; A: S: C9 o% z& v; S# G! @4 ~
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ! t3 q; H5 Q, x6 R2 R# c
  76.     ' |7 |( g0 b& @* u( y# J, k
  77.        /*计算图片灰阶值*/   
    / g* a' C3 S/ s/ f
  78.        $grayArray = array();    ; `  e' V/ X# v, ?& v# p3 ~
  79.        for ($y=0; $y<$delta; $y++){   
      t. b4 N2 |8 v
  80.            for ($x=0; $x<$delta; $x++){    ; |. n# d+ @" L4 ~2 J, {* A- @
  81.                $rgb = imagecolorat($img,$x,$y);    9 F  q" |' e, \: M5 T: p
  82.                $col = imagecolorsforindex($img, $rgb);   
      y; H$ y" ?9 {
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    3 U9 g4 T6 f" o, r3 r
  84.    
    & B0 e9 s( G1 Q- _& o8 L/ ^) S
  85.                $grayArray[] = $gray;   
    ' u# \+ a1 A) r" y: V
  86.            }   
    % `) D! {5 I/ w6 q/ ]
  87.        }   
    : e: H9 N: V6 y
  88.        imagedestroy($img);   
    3 D# E( G3 X! X# Y$ k* o; ~) M
  89.    
    6 v& f2 f* M6 W. `1 G; m
  90.        /*计算所有像素的灰阶平均值*/    % g# o2 o" [; L, w8 Y- R6 Y
  91.        $average = array_sum($grayArray)/count($grayArray);    - d# Y# H3 X  l  l8 E' ^1 z0 N
  92.    
    ; k* w- G) R+ \. ^! i1 O. A# c
  93.        /*计算 hash 值*/    9 V8 I" k: b8 U  R9 X: f# }
  94.        $hashStr = '';   
    0 n# ~- b) J( A. z. H5 p
  95.        foreach ($grayArray as $gray){   
    ( z, {0 [9 B% b5 Q
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    7 ^, W# U# ]( N
  97.        }    9 a  ~$ h# y% d6 Q! C1 }0 A
  98.    
    3 ~9 P. |! R0 p0 y7 P2 X
  99.        return $hashStr;    4 t# W. l( `  U( s6 c& N& o$ }
  100.    }    4 {, G; ?( {8 J* {
  101.    
      [+ u* W& \% g3 i
  102.     8 t6 v2 Z/ ^" S$ q+ l
  103.    /**hash 图片文件   
    9 l1 y" X4 O7 W
  104.     * @param string $filePath 文件地址路径   4 c3 D# a+ T% S9 U1 g# {  `( Y
  105.     * @return string 图片 hash 值,失败则是 false   
    9 T: D$ `4 i2 k
  106.     * */   
    ! D! \6 v* ?# U) G: P! H, M' @$ b
  107.    public static function hashImageFile($filePath){   
    2 Y3 q3 v) g, S
  108.        $src = self::createImage($filePath);   
    % B! B& }' I' t2 z/ E
  109.        $hashStr = self::hashImage($src);   
      H! k4 \/ f+ k
  110.        imagedestroy($src);   
    ; p3 W& x4 I7 J9 S2 t3 N
  111.    
    : u% y! x- E/ W/ F$ I8 C3 ^  [
  112.        return $hashStr;    + w# u6 Q6 ]2 G5 ?+ o# ~
  113.    }    ! s0 \, r/ k1 `8 C
  114.     ) n' ?  S/ G" W1 a! g1 C& c! l
  115.    
    : L: \2 h# L% u) c* u2 m" ~0 f
  116.    /**比较两个 hash 值,是不是相似   
    3 q" ^- {" w/ O2 w5 T# n3 F
  117.     * @param string $aHash A图片的 hash 值   
    - N: ~! i0 m+ l0 E
  118.     * @param string $bHash B图片的 hash 值   
    . b* i0 o5 Q0 W% s2 ^0 t) E$ N
  119.     * @return bool 当图片相似则传递 true,否则是 false   1 r8 w9 b& D* V& k
  120.     * */    * |$ W( ]* }4 R4 y8 I$ N. }' f; F
  121.    public static function isHashSimilar($aHash, $bHash){   
    % f& p" e$ K) v' U2 n! t* q
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    - d+ V. N0 m7 T" w
  123.        if ($aL !== $bL){ return false; }    1 J' z8 _3 J4 I  B7 g
  124.    
    5 \( c% H( L( |! n( O
  125.        /*计算容许落差的数量*/   
    3 S" t$ E' P1 L3 ~4 ]
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    / O6 L5 \6 H: t0 Z" X1 ^
  127.     - A+ _6 M  W- A6 _
  128.        /*计算两个 hash 值的汉明距离*/   
    * W$ c$ B/ `) A1 [3 r% B
  129.        $distance = 0;    ( x" ~1 [0 V+ n4 G" U- g
  130.        for($i=0; $i<$aL; $i++){   
    6 P5 o- m! A' J3 I
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    * c; @# t  v( |: p: f! R+ i
  132.        }   
    ; Y  J# v$ ^5 v  E, ^7 o0 `
  133.    
    % ]  z7 f# u' }  E* P- Y
  134.        return ($distance<=$allowGap) ? true : false;   
    . p# R0 W) r0 J3 C+ U8 X6 l, _! w! Z& j7 N
  135.    }    # i8 B5 u1 q# C; x' b
  136.     ' A; W8 }" s. c0 E
  137.     0 Z/ _* z1 T( M) v& h! t- ]- s
  138.    /**比较两个图片文件,是不是相似   
    3 S- N& ^' A* f( z; b8 l
  139.     * @param string $aHash A图片的路径   ( ]  h2 K5 Z6 U$ [+ ?
  140.     * @param string $bHash B图片的路径   4 j) p& b. i" T3 `
  141.     * @return bool 当图片相似则传递 true,否则是 false   - W, l0 S0 [: i) o/ ?/ ~
  142.     * */    8 y: m& I% C! K* `
  143.    public static function isImageFileSimilar($aPath, $bPath){    6 _9 B8 Q) o2 P, m2 I$ X
  144.        $aHash = ImageHash::hashImageFile($aPath);    . @! t' r+ {8 Q- L  E+ |
  145.        $bHash = ImageHash::hashImageFile($bPath);    7 `5 t4 u$ G! b! N+ H
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    ( ?: |9 ]: h4 }- v. M8 B6 t
  147.    }    ; W8 J7 |+ _+ z; T
  148.    
    $ G2 P5 Q$ o: y9 i5 [; }
  149. }" i2 i3 m9 l" F' }# C% K
复制代码
/ S5 v( c+ D6 [
2 A9 {6 ~! k$ p6 p, u5 t- X





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