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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

# u' q: C' `% {2 x& }8 P  L0 b: D6 |( G由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
4 ^& J- f' m0 o/ @. m
  1. <?php   
    ! l* M: o# n) G# g& C/ T/ m: `6 F
  2. /**   
    9 D8 n2 `% B; s# \9 [( X
  3. * 图片相似度比较   & A: T8 Q5 l; C/ T4 h* A/ @3 Y
  4. *   
    " L# t6 }, m0 H! D! ^% n& T  P
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    % A. g: m3 n2 ]5 h4 V' Q
  6. * @author      jax.hu   
    . F, V, w0 j% O% }: C5 q/ O
  7. *   
    : s0 ~7 l, R, J7 b
  8. * <code>   " O, W2 W% |5 G& q' T
  9. *  //Sample_1   & O# A# X& |8 q% a. o( n
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    % N- e3 |* B4 i5 U8 p! ?: i" ]& x
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   7 d3 s% ^! j: C' ^0 h  F! H
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   6 {$ Y  z4 \/ y8 q! n9 V# |4 s
  13. *   4 V: y5 l# a4 r& v0 Q9 X5 x* j
  14. *  //Sample_2   8 d4 x+ r$ Y& u7 _% C
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    $ i  p4 Y. C# t, _. Q
  16. * </code>   4 J3 ~0 _5 y2 ?5 l+ I" V
  17. */    2 t8 Z; Z  _' A" z' K! A9 O
  18.    
    # Z; {- b: q1 B2 ^& e" Z
  19. class ImageHash {   
      n: ^, {/ Q, {+ n& r
  20.     * e' _. B! W, f* I) I( J$ a
  21.    /**取样倍率 1~10   
    6 i) L; F0 w/ b- [/ M4 i
  22.     * @access public   7 R, [$ w3 H0 A# G/ X3 ]
  23.     * @staticvar int   4 l4 T" ?1 J) k5 \1 _
  24.     * */   
      a2 @2 U6 v; J
  25.    public static $rate = 2;   
    % A- S  ^/ F5 j; v# i
  26.    
    8 d* P  n, o3 X# C: f2 v; z
  27.    /**相似度允许值 0~64   
    ! u# o  b  A+ M# n+ `/ s1 {
  28.     * @access public   0 ^9 l  u+ P  ?+ h+ s. G8 U0 Y
  29.     * @staticvar int   / I+ P* D( b6 Q( p  d
  30.     * */    ( S) v- C* d, x2 g7 o
  31.    public static $similarity = 80;   
    1 p. C2 u5 B' |* h
  32.     6 i; a, y0 G% U3 |
  33.    /**图片类型对应的开启函数   ) X: v; W7 o* P% y! D) i, D" j9 c
  34.     * @access private   
    + F9 w4 t1 z% L/ n* a( @, [
  35.     * @staticvar string   4 y' Y, p( B4 q$ |5 d
  36.     * */   
    ' k3 S( ~3 T- b% d6 o; S% M
  37.    private static $_createFunc = array(   
    / Z3 X* S5 G1 o: W3 f+ x. f
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    : O0 `9 ]) ^# M+ P& q7 I. g
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    8 J7 p# `, M; k  E9 U+ U+ O4 G
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    ' }$ D) q6 w$ O% L% |* K1 U
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ; O1 a6 N+ A0 Y2 W9 C' m
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',      K3 k( X! n0 p$ b% @
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    ' G: y2 B; o2 T0 f8 T
  44.    );   
    8 Z# r% S; y8 A* k  [" Q( M% ]
  45.    
      q: X3 B+ U7 G, q) W* ]  `
  46.    
    3 ~+ v. U& _. E/ e3 T) W
  47.    /**从文件建立图片   " x' ]! f1 s# \* {; u
  48.     * @param string $filePath 文件地址路径   9 G% u" d6 W: [: S1 `
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   , ^& K4 q2 N4 S  H
  50.     * */   
    % G: Y# E5 v. x3 x5 \  Y
  51.    public static function createImage($filePath){   
    4 P' H/ E  v- n$ C7 U
  52.        if(!file_exists($filePath)){ return false; }    " M) w, l+ h1 w, E5 h! i5 g
  53.     % g+ i! i" b- I0 O) E" T7 x
  54.        /*判断文件类型是否可以开启*/   
    2 l0 I' S+ A  g; ]7 \
  55.        $type = exif_imagetype($filePath);   
    ' o+ ]8 k# ~: q! E4 r
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    : s; r1 {6 C  P2 m
  57.    
    + \9 ]! ^* Z* H7 P; t! T/ R; B/ A
  58.        $func = self::$_createFunc[$type];    % i4 Y6 D( I) l$ G
  59.        if(!function_exists($func)){ return false; }    % G" m$ \: g' W/ Y# `3 `8 t% q
  60.    
    ; v! ^% M2 @1 E) ]- T
  61.        return $func($filePath);    3 n9 }, L0 t; w3 G( U# z6 j) {8 \
  62.    }   
    + R+ h+ _4 n( y  W+ {0 W: e/ K- L
  63.    
    9 ], e$ ~0 H4 E7 {! X
  64.     1 f! h) }3 Z$ d9 v9 p; _8 N
  65.    /**hash 图片   
    $ n) W% k! a# U" R0 K. B$ v' j% F, w
  66.     * @param resource $src 图片 resource ID   
    & @# L5 X! ^2 o
  67.     * @return string 图片 hash 值,失败则是 false   
    ' }! t( \2 _2 P3 \5 A/ E
  68.     * */    ! J; P  U& l/ y! F5 ?9 m2 m
  69.    public static function hashImage($src){   
    ; i. b. M$ {0 `
  70.        if(!$src){ return false; }   
    - G3 A+ m3 p( W' M( ~
  71.     ( N7 U1 o. S9 p% R' I- ?, R
  72.        /*缩小图片尺寸*/   
    " A; f. r% ^) U7 I3 P
  73.        $delta = 8 * self::$rate;   
    7 X9 S4 i" k( h3 |
  74.        $img = imageCreateTrueColor($delta,$delta);    4 t# g+ N+ a+ ~2 p
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    4 V' `3 X5 h  u
  76.    
    ' D" ~9 ?' h2 V6 Q9 ^) N7 T
  77.        /*计算图片灰阶值*/   
    $ [  f4 c) Y0 K7 D: |  |4 ~
  78.        $grayArray = array();   
    ) J5 q+ s" b# P0 m+ r; A
  79.        for ($y=0; $y<$delta; $y++){    3 L9 e1 U3 q' h8 c9 h
  80.            for ($x=0; $x<$delta; $x++){    0 F0 k# [9 J/ D% p8 o1 L' d
  81.                $rgb = imagecolorat($img,$x,$y);   
    " O1 E( u( D  E, ]0 w
  82.                $col = imagecolorsforindex($img, $rgb);    8 y* b5 }+ U+ k( @' M3 M; n5 z
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    1 g* _! u# v0 E+ x) T
  84.     3 u- t* y1 j* }0 l% G7 V+ o
  85.                $grayArray[] = $gray;    5 N2 L- c, K2 E1 {2 C
  86.            }    : v  W1 B5 W% I. ]4 w
  87.        }    ( I3 c- n9 T4 X2 h( @- N! z! B& w& c" E
  88.        imagedestroy($img);    + {1 y* b- m: [, |
  89.     9 d/ l2 j5 b4 `1 C
  90.        /*计算所有像素的灰阶平均值*/   
    * U0 p1 F# t) W/ Q: e
  91.        $average = array_sum($grayArray)/count($grayArray);   
    8 o7 N) I( j0 `8 O
  92.    
    & {( C" t6 J3 r/ u; p
  93.        /*计算 hash 值*/   
    4 L$ T) P9 K& p
  94.        $hashStr = '';    4 R% s% l5 G7 I: Z; ~
  95.        foreach ($grayArray as $gray){    2 a7 \8 d, I! T1 v  C: B
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    ! i9 t% e. q% X! b# R5 Z, f) J
  97.        }    - v/ j+ o, n& R' b
  98.    
    8 ?+ ^# e& f/ V" c1 R9 k7 \# G
  99.        return $hashStr;   
    4 h" \7 z* S5 x
  100.    }   
    0 n0 A, _) O7 ?( x7 {( T7 L; r
  101.     7 L: i4 u( B; L
  102.    
    2 u+ y2 P# t3 T( `
  103.    /**hash 图片文件   
    ' }" ?" {2 `1 N4 c" \
  104.     * @param string $filePath 文件地址路径   2 Y8 Q7 \; w5 D  C' i
  105.     * @return string 图片 hash 值,失败则是 false   % G4 V, ^  r( y8 c7 W
  106.     * */   
    5 [9 S7 T8 N/ k; |
  107.    public static function hashImageFile($filePath){    7 P: Y  z# ]) R+ A1 q- F0 y
  108.        $src = self::createImage($filePath);    . M! y- Y' U2 }. g7 ]6 p- l
  109.        $hashStr = self::hashImage($src);   
    ( w9 G5 o$ `, s1 d
  110.        imagedestroy($src);    * ]- U) t3 O% K
  111.    
    ' _1 }. ~' l" @' a
  112.        return $hashStr;    ' u& R- M; L/ m, `' w" `% L: _! ]
  113.    }   
    ( w" ~% Q& [: U  p
  114.     3 K) x1 m3 u5 S( P) N) G- |' e
  115.    
    , {9 t. |( y  o5 i9 `
  116.    /**比较两个 hash 值,是不是相似   
    . i* g$ [! b- u
  117.     * @param string $aHash A图片的 hash 值   
    / t. Q2 d5 H- G9 D/ S* ?: n
  118.     * @param string $bHash B图片的 hash 值   % u/ t3 X( F% u2 R9 m2 j' U
  119.     * @return bool 当图片相似则传递 true,否则是 false   ' x  Q$ p. y4 W
  120.     * */    7 L; y* u* n8 r' ~
  121.    public static function isHashSimilar($aHash, $bHash){    / D) E1 P# \6 n3 M' \" }% o
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    $ l% c) x& y: S$ K4 r
  123.        if ($aL !== $bL){ return false; }   
    . w. O0 E3 A1 U5 S* a
  124.    
    / A+ M  L7 l: K( }9 B' Z/ y. W6 \
  125.        /*计算容许落差的数量*/    + ^. n' l  ]- g3 y/ T
  126.        $allowGap = $aL*(100-self::$similarity)/100;    3 Q3 Y! L9 i8 P+ h9 a. d( D; }2 x
  127.     2 I9 }: u! w0 [/ g
  128.        /*计算两个 hash 值的汉明距离*/   
    1 N( m1 N0 s4 e; y- H
  129.        $distance = 0;   
    0 m7 K) m; J' u" t, n( V
  130.        for($i=0; $i<$aL; $i++){   
    " E* s! ?7 C' D4 _& V! F
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    & [+ A7 z% s3 D$ D  P8 d$ D% q
  132.        }   
    0 c7 D* f/ P6 `: _, K  `- e
  133.     + n4 G* U- S2 x5 e) M
  134.        return ($distance<=$allowGap) ? true : false;   
    - u6 i( |, `4 r* I
  135.    }   
    * [+ o/ N, x( q+ W8 t! F' M' {( J
  136.     5 C( C! |* g" ?3 ]) p
  137.    
    5 [* {( t- C: S6 g& j
  138.    /**比较两个图片文件,是不是相似   * R; T2 v+ _$ m- ^1 Y
  139.     * @param string $aHash A图片的路径   
    . `7 z. S5 }: \9 A  W! w" l
  140.     * @param string $bHash B图片的路径   - D0 T5 h$ y- y
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    1 d/ f$ b) b3 G/ l, P  h; s6 J
  142.     * */   
    * q, v' l/ O% b2 d' C! g2 m% n
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    . z/ ]' W3 g" A1 E2 d9 o
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    1 u5 d3 n" F: F( E3 |2 }) n) Y
  145.        $bHash = ImageHash::hashImageFile($bPath);    9 \7 @3 P; u8 p$ \+ S0 G
  146.        return ImageHash::isHashSimilar($aHash, $bHash);      i) I- _1 C& Q" L
  147.    }   
    ' O% o7 @0 Y/ \; H  s% c+ w7 e. D7 C
  148.    
    7 E) X! c% s3 @
  149. }1 r* P$ }( G, e/ p# h
复制代码

/ [6 L: D6 X( T) f+ v( a: d
' w# y( z2 }3 @4 X
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 11:45 , Processed in 0.075704 second(s), 21 queries .

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