cncml手绘网

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

作者: admin    时间: 2018-7-7 23:06
标题: 分享一个PHP简易的图片相似度比较类
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
3 P8 x' ~9 _3 j; u( `4 w3 x8 F8 W# S

1 Q0 T' E5 `4 E) L1 x由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
( E" z/ q' g" e7 ^6 s* E
  1. <?php   
    ! V0 T& ]0 y2 t+ i2 G
  2. /**   
    : N$ R) ^% f' t& L. g9 ~, E; T
  3. * 图片相似度比较   $ w( i. }* Q; ?2 ?# r+ M5 f
  4. *   2 ?0 E7 g& m* R
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ' a1 X+ Q8 o+ F. K# p
  6. * @author      jax.hu   6 I2 ^' F# e  x9 ]1 F1 i
  7. *   
    1 M% i9 J" n3 _) M: J$ U
  8. * <code>   * c( h, V9 R: f* M/ B
  9. *  //Sample_1   , ?  c7 g# T, H+ z
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   ' u) c& z, f5 e8 o. R, r1 O0 k" l
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   ' y3 D" M' A7 L
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    0 I7 s4 e/ f6 G7 Z, l% T: v. v, P2 i
  13. *   , |8 q) P/ ]! K$ F" c( B& c
  14. *  //Sample_2   
    ! n" U8 D( Q# T, Q) Y$ F: b2 o
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    & ^5 R: W/ K; A* A) M
  16. * </code>   - j$ }1 }( j: W9 Q* D6 V0 A
  17. */    8 r$ \) }  W) G) ]# g
  18.     + D- x0 y! }0 d* ?$ o" }& `
  19. class ImageHash {   
    ; {& ?/ _+ b' D5 g+ S1 o+ x
  20.    
    ) g$ p. L4 n8 r( n, X( @
  21.    /**取样倍率 1~10   , U1 e6 j% y# R" ~( s
  22.     * @access public   
    / \4 m% ^9 `" b$ U" V" J
  23.     * @staticvar int   
    7 i8 Y  n' m  N5 q7 `0 d- m& b9 ~
  24.     * */    3 K: G* {9 }& [
  25.    public static $rate = 2;    7 o' g% E  r8 v7 [( ^& c
  26.    
    # R4 T/ I( m: D- A3 w
  27.    /**相似度允许值 0~64   
    # S" X( p% g+ O( U( j
  28.     * @access public   ) y2 ?2 S' I1 e5 M0 @
  29.     * @staticvar int   
    8 \9 M5 I5 r; Q% y; W# K
  30.     * */   
      J; s! h) ?1 {& i3 K4 A8 @1 v
  31.    public static $similarity = 80;    & g& v! L9 @2 [% _
  32.     & E- m, c- E& V- X$ ?7 m. E
  33.    /**图片类型对应的开启函数   
    8 p. w2 v/ H# y0 c! R1 N
  34.     * @access private   
    ' u/ k. Q6 b! G- p  R
  35.     * @staticvar string   1 s& z  }9 D/ n3 K% Q9 X
  36.     * */   
    ' e: h4 U0 Q- @, t1 w! o* R
  37.    private static $_createFunc = array(    % [6 B4 s" z+ J" d+ h4 i
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ' I( a: C( q1 U4 N- ^
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    ' K8 `  J- {2 a* B8 E* L
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    1 a& b1 c' k) o! d( n8 w$ i& `
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    9 T# t% t; g  M1 N% u
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    ; {3 w6 V. z2 |' z7 t! a
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    8 U- f5 Z( [" X! f) k  L0 y% \$ ]4 v
  44.    );   
    1 y# j2 z6 H. G+ u7 b
  45.    
    & u1 n, q) C. D5 N9 @
  46.    
    1 y* U  r- I- m
  47.    /**从文件建立图片   9 B& [- P" n4 Y' N6 o
  48.     * @param string $filePath 文件地址路径   , y/ l( H  M, y7 F: ~. m" G& b. R% o
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    * l  g0 y) a" M3 N8 X* o
  50.     * */    + {/ ^& Z$ e; l" o' q
  51.    public static function createImage($filePath){    0 a+ W! u$ B+ x0 n
  52.        if(!file_exists($filePath)){ return false; }   
    " _$ ?* x  P0 N: q. p6 k! R' {# k
  53.     * r+ P' u5 }( S
  54.        /*判断文件类型是否可以开启*/    & @$ x: y( g1 N& A
  55.        $type = exif_imagetype($filePath);    . D3 T$ S* C" Y# [1 U& P
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    2 }+ L4 W3 X; e  S+ o
  57.    
    ) N# a1 `: W+ e+ \8 B% G3 Q2 R5 g: `# R
  58.        $func = self::$_createFunc[$type];    , ?. E. L: F2 r! W+ w: \
  59.        if(!function_exists($func)){ return false; }   
    6 j* v7 a& T! C+ D$ R7 _5 M
  60.    
    0 M/ u7 E6 R* h
  61.        return $func($filePath);   
    / u, _7 g5 |6 M. V7 |* \
  62.    }   
    7 u2 ^0 E1 }! B  ?3 {7 Y
  63.    
    - T" P# `5 T. z* R, \. |
  64.     ) B" w8 ]8 c# J% g" U
  65.    /**hash 图片   
    ! B' J: p  |( g- ], D
  66.     * @param resource $src 图片 resource ID   
    # I6 ^5 }' h6 S+ ^$ u9 v
  67.     * @return string 图片 hash 值,失败则是 false   
    6 l- O7 w5 d& H1 e& M' q  Y
  68.     * */   
    ) A# g& H0 N; c, O$ a1 e7 E
  69.    public static function hashImage($src){    : i: T' T6 _4 f+ p& D
  70.        if(!$src){ return false; }   
    % Z! x& m: _+ }0 E8 b) a
  71.     7 X  @$ g& E8 \. ]
  72.        /*缩小图片尺寸*/   
    " L4 q5 _7 J6 A% A
  73.        $delta = 8 * self::$rate;    7 u  C1 A+ z. T9 n
  74.        $img = imageCreateTrueColor($delta,$delta);    0 ]& K1 S1 G3 a7 E2 G7 h5 N, {
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    ) `  P' J) U+ f  G: A, B
  76.     . d' l$ {* {/ K2 Z7 s
  77.        /*计算图片灰阶值*/    8 D6 O% W# Y- E0 _; v# c; E+ V3 Y
  78.        $grayArray = array();    6 p3 Y% i1 C( P. W. T; D" j- Q
  79.        for ($y=0; $y<$delta; $y++){   
    0 |% l0 {0 S( Q5 f6 S9 a
  80.            for ($x=0; $x<$delta; $x++){   
    5 ?/ E. a* k4 v2 m1 e
  81.                $rgb = imagecolorat($img,$x,$y);    6 a: C# v) k# h9 X
  82.                $col = imagecolorsforindex($img, $rgb);    ! b/ A6 J. W# z
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ! H' i2 }9 }2 Q# p+ Q/ O
  84.    
    " C$ ?' w. n" q  ~
  85.                $grayArray[] = $gray;   
    : L1 X: Z0 c6 z) O! u/ D3 ^3 r
  86.            }   
    & @* J# s. |3 |& L7 q% _) U6 V
  87.        }   
    ' e: s8 G6 W3 }
  88.        imagedestroy($img);   
    9 r/ U, k2 A+ l4 Y1 |8 u
  89.    
    ; n* A" c; V/ R
  90.        /*计算所有像素的灰阶平均值*/   
    : ^  B. A2 n% |6 a  s3 c
  91.        $average = array_sum($grayArray)/count($grayArray);   
      f+ o+ `: m9 H. J8 @9 F+ r
  92.       m' c9 R$ U2 D! l
  93.        /*计算 hash 值*/   
    9 X& ]2 U" r9 E9 P; y1 [0 t
  94.        $hashStr = '';   
    : m2 W% t; Z' p0 c
  95.        foreach ($grayArray as $gray){    ) s* Y5 K& C) n3 l3 t/ s! v
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    3 o9 E5 J+ ?! o
  97.        }    , ?8 w8 U) w' C8 t
  98.     0 @7 m2 g% `6 I
  99.        return $hashStr;    9 l0 D3 _3 T& g& T
  100.    }    ' c- w" p) g! Y6 n# _
  101.     & o0 ]: m6 L* Z  x2 ]
  102.    
      @! C* n/ h! r3 H
  103.    /**hash 图片文件   
    ! Z7 I& @: [3 s9 u3 J) o
  104.     * @param string $filePath 文件地址路径   
    + U- S6 y- a" N* p5 [( R$ n' w5 X
  105.     * @return string 图片 hash 值,失败则是 false   
    & w) ]% d" B& k; e, f. Y2 w
  106.     * */   
    # b9 Z- G( J9 p) m
  107.    public static function hashImageFile($filePath){    ! b4 X0 b  u' O1 I4 A! q' Z
  108.        $src = self::createImage($filePath);    + p  K' o7 I; K4 k
  109.        $hashStr = self::hashImage($src);    3 F1 L7 |9 I6 L3 p
  110.        imagedestroy($src);    0 G9 z1 S9 i- E/ j/ \& _4 A
  111.    
    * A/ X9 a9 O( {( C& W1 G- ^7 O  n
  112.        return $hashStr;    7 _6 W+ ~0 l" k% s7 W
  113.    }   
    4 g9 D4 m- b4 Z5 e
  114.     % D- f4 Y! n' R; W
  115.     5 Z/ z  r3 P8 ?% W+ {
  116.    /**比较两个 hash 值,是不是相似   ; w$ q9 y8 r5 p9 T# Y
  117.     * @param string $aHash A图片的 hash 值   
    . u# z' I  B/ ~) c- \
  118.     * @param string $bHash B图片的 hash 值   ) u+ V5 |! V! h# J
  119.     * @return bool 当图片相似则传递 true,否则是 false   5 L/ m" k3 `9 b: j
  120.     * */    4 \7 f6 v3 a( R( l0 O# Z# x1 T' @
  121.    public static function isHashSimilar($aHash, $bHash){    % c2 {  B) ]6 g9 j: V4 T/ K
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    . ?) ^' {  O, d
  123.        if ($aL !== $bL){ return false; }   
    ) I5 L( U. b: g: A) J! J
  124.    
    / q% Z1 I$ t3 Q+ {
  125.        /*计算容许落差的数量*/    5 u7 O& {# D# O, D5 t
  126.        $allowGap = $aL*(100-self::$similarity)/100;   
    ! F, o  H! o. L% d3 O' Z8 q4 p
  127.    
    ! y: U9 R( ^% P$ o3 A: X
  128.        /*计算两个 hash 值的汉明距离*/    7 O' t" B9 I5 U" V
  129.        $distance = 0;   
    5 J0 a3 ^- @: m- P4 ^6 C* S$ L
  130.        for($i=0; $i<$aL; $i++){    , w6 `6 {: _' |# S2 \) p
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    $ K& d  x7 V) x, a0 h
  132.        }   
    3 W  z# F, l5 {# h% @
  133.    
    8 y$ ?: Q; E4 F4 V0 [9 D8 a
  134.        return ($distance<=$allowGap) ? true : false;    9 k8 U3 u+ ?7 Z: f/ j
  135.    }   
    7 ]7 Z& t3 ~  }4 m) l# y8 A: U1 n9 }
  136.    
    / h" m4 |+ T' d2 [5 j5 O8 i: t
  137.    
    8 @! U; @/ i. v. r$ p$ W
  138.    /**比较两个图片文件,是不是相似   ' l$ F: Y% Z' F$ \' a2 a) j+ R
  139.     * @param string $aHash A图片的路径   0 ]! J3 m/ q4 b; s0 n
  140.     * @param string $bHash B图片的路径   - N/ W& p/ L& }& s
  141.     * @return bool 当图片相似则传递 true,否则是 false   ; A. i7 Y6 P) X9 {* W
  142.     * */   
    ( i; ?  k! Z5 [0 J$ X
  143.    public static function isImageFileSimilar($aPath, $bPath){    $ T: j+ ?1 N$ L! F3 S% z- S8 w. n* g
  144.        $aHash = ImageHash::hashImageFile($aPath);    & x/ P) l6 N9 J# L7 C  F7 x3 O4 m
  145.        $bHash = ImageHash::hashImageFile($bPath);    ! p+ ^3 i; k, }2 s
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    1 F- O- g+ ]6 m
  147.    }   
    * ~$ D2 Q! l( Y
  148.     5 K! r+ A, P* t0 a5 @5 R
  149. }" }. R$ U2 ~# A2 E, E
复制代码

+ \/ L$ I9 O# m: A. B+ b
# n3 h: J) Y1 h3 C2 {




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