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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
- h' L+ C2 A, U! ?1 K. y" z# ^0 N" `

  v% F% e0 o& }4 q由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
+ c$ }6 t/ c) n1 g
  1. <?php   
    % f5 J2 K, {& G8 J, w" H' g5 D
  2. /**   
    & v/ n: u  U9 m9 s
  3. * 图片相似度比较   0 \: U2 D9 e1 L/ s9 S, y
  4. *   & g5 X$ I, U0 C) O
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  % }2 Y# ]2 B& x7 h4 B: W
  6. * @author      jax.hu   2 L$ r  w: `  Y6 d5 s1 k$ p* X& R
  7. *   # j; A' P8 C% T) ?5 ^
  8. * <code>   
    % i& i$ J) g3 k5 Q0 D; w- _+ ?
  9. *  //Sample_1   . {+ {5 P$ m# W2 ^* P( ^
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   
    + H0 C2 i  M$ e/ r9 s
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    & w5 Z& }3 _; j+ G8 \" u" f- G3 ]
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    ! H1 G: x$ l& \6 |) @5 M
  13. *   1 S/ R" a! C8 p9 E$ z- h: L3 t" n
  14. *  //Sample_2   
    / ~; f$ R7 c2 J# A. L) v! y
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    8 q; m& S" f! O! w4 D# p
  16. * </code>   
    3 ~. M5 L6 S* V
  17. */   
    ! \9 Q, G! k5 z
  18.     . t" h6 P: j  b) v- M, D4 \$ m9 g
  19. class ImageHash {    ' c( K2 U$ w2 r6 d* j
  20.    
    / ~9 F. G& R: V- y
  21.    /**取样倍率 1~10   
      q% b/ W: \2 C9 r: h
  22.     * @access public   
    " A" P( U" V- O$ G6 m8 l
  23.     * @staticvar int   
    1 N4 i' B( e5 K; W! x' Q( y4 k
  24.     * */   
    0 T% ~/ ^: E! F0 T1 P& G; h( }
  25.    public static $rate = 2;    6 R: @9 }, e  U, k7 _  N% t
  26.     & l! e& r; E; ]" B2 @0 u
  27.    /**相似度允许值 0~64   
    0 d6 e+ V! E6 f& e+ p
  28.     * @access public   ' Q* Y7 D, D+ s0 X9 a; M) n3 g
  29.     * @staticvar int   
    ) \" x- e% A  g+ k# J7 p9 v9 ~2 l) z
  30.     * */   
    / I* w' @8 `0 ]. O- y. C2 f0 c
  31.    public static $similarity = 80;    - n7 S& A7 A- o' N$ U, [
  32.     # R3 \8 L% _3 n) j
  33.    /**图片类型对应的开启函数   
    1 {# O" b3 W7 l" Z" @# J
  34.     * @access private   , [% b# w$ r1 c; ^& ]
  35.     * @staticvar string   
    " V  X  f+ M! s6 B; r5 H* ^
  36.     * */    5 L' l3 J" U& C* q1 |) o( T+ z% D
  37.    private static $_createFunc = array(   
    4 [9 J; X1 r# B  P: p7 k& h/ z
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ! m$ e! b7 y: q0 M4 T7 d
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    % P. |  Y7 {. `$ z2 F6 T, f1 l
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    ! J5 t1 V/ r, @" i; @  R/ A
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    % U  }7 n/ F7 M/ x1 I
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    / r& v: C+ ^+ ~* a" V& n: d+ d3 Y% ?
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    " v, Y+ k# V% U& K1 |0 d
  44.    );    $ P9 T0 \( J, K6 m9 j- C1 e6 B% d
  45.    
    : c" q1 O7 T; T+ @* L5 H
  46.    
    7 M( `# P# ~- M# W, ]4 x
  47.    /**从文件建立图片   
    6 [' i! T$ ]) a  s- C
  48.     * @param string $filePath 文件地址路径   2 C) k) ^$ s2 R# C1 {
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   # f1 u5 ?5 I; {
  50.     * */    . u7 I1 s: {# V
  51.    public static function createImage($filePath){    9 Q, F$ }9 w* W% {+ c. \
  52.        if(!file_exists($filePath)){ return false; }   
    * y4 d1 L" H# }/ m
  53.     9 m' W2 E+ I1 R7 N( w
  54.        /*判断文件类型是否可以开启*/    . _3 ?7 J+ t/ w5 e; {" `
  55.        $type = exif_imagetype($filePath);   
    9 n4 h$ ?% J5 g9 q; J
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    ) u$ o/ v0 e. ^4 S0 ~
  57.    
    1 s9 w6 s% s7 T8 N. v
  58.        $func = self::$_createFunc[$type];    - S: h# a* v% [' z; H
  59.        if(!function_exists($func)){ return false; }      B' B" Z$ e$ Y4 b" r7 B' D
  60.     $ m  K" l1 O9 D0 I+ ]# |# x0 y
  61.        return $func($filePath);    * Q8 E- w+ a3 d$ }
  62.    }    4 H! V9 l" {6 K" @: s! l
  63.    
    . A) d: @# a8 y2 t- C( g3 B
  64.     ; m( ?8 z9 Z+ @- w4 o* ~
  65.    /**hash 图片   
    $ J* p7 ^1 f0 ]" o
  66.     * @param resource $src 图片 resource ID   
    - U  Q) |' F4 j: c
  67.     * @return string 图片 hash 值,失败则是 false   
    4 I/ A( s# {& J( @& c
  68.     * */    8 I% w6 [1 h9 Y* }3 G
  69.    public static function hashImage($src){   
    ( e- X& b) a7 W& j9 N) A- P
  70.        if(!$src){ return false; }   
    2 q1 h7 C! A; q; j, [+ N% ~
  71.    
    ' n0 R& B$ X, ~$ p$ K
  72.        /*缩小图片尺寸*/    , d7 X, i) F: X! C- o% u9 y+ w
  73.        $delta = 8 * self::$rate;    , v( h  p6 ^: ^& `% B, P1 ]
  74.        $img = imageCreateTrueColor($delta,$delta);   
    7 w9 \) p& u/ J( }- b6 x
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
    % t- m- k& {& d( w/ x+ p
  76.    
    ( r( O% C+ s, z; Y3 x; S) J0 g
  77.        /*计算图片灰阶值*/    8 ~) h# T) u) }5 r7 k6 G, f
  78.        $grayArray = array();    - q! ?& P- Y/ C( s% e6 _
  79.        for ($y=0; $y<$delta; $y++){   
    ( U8 `& C2 H' ]. Y9 M3 ?5 Y1 d9 H
  80.            for ($x=0; $x<$delta; $x++){   
    ; t. y) z' `" E# T( V' z9 t. S
  81.                $rgb = imagecolorat($img,$x,$y);   
    - l4 G6 D0 R2 f$ z
  82.                $col = imagecolorsforindex($img, $rgb);   
    , p1 T4 S  v+ i2 j# e
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    : ]' g+ Y0 z5 L) U  f  S
  84.    
    , L' b6 x! K6 H8 a$ j4 I  e& n
  85.                $grayArray[] = $gray;    ; H+ G) A2 ]4 h/ k- T
  86.            }   
    / D% O) G6 j* C: M
  87.        }    * W2 R# [2 |5 B' k+ g" m" m$ x
  88.        imagedestroy($img);    ' o, D& c* A! f9 [
  89.    
    / K5 j. R  T3 L8 m
  90.        /*计算所有像素的灰阶平均值*/   
    4 n# M& I6 O+ k0 ]+ g+ U, B
  91.        $average = array_sum($grayArray)/count($grayArray);   
    1 v( }; s: T5 G
  92.    
    - t* P. w/ K5 ?0 [2 o! ~* K
  93.        /*计算 hash 值*/    ) G2 k% L4 d; y- Q/ @
  94.        $hashStr = '';   
    & {9 y/ b% S) m- L9 `: s8 t
  95.        foreach ($grayArray as $gray){    9 O4 b! Z5 F4 q
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';   
    7 p6 B# v  D% s" z# v
  97.        }   
    7 L& v" J7 Z8 }
  98.     ) J& s  E/ D4 ?8 v8 N
  99.        return $hashStr;    . C1 z: k. `' s2 ?
  100.    }    ) ~# q4 Q3 z* y) E; L9 ?
  101.     % G; Q# H. \) B! Z* T
  102.     / B: A$ g8 y% O2 D; v2 e
  103.    /**hash 图片文件   
    : n/ Y+ Q# Y; Z7 u/ b% E4 d4 g9 b
  104.     * @param string $filePath 文件地址路径   / H* j' N# E$ F: ?6 h0 ^
  105.     * @return string 图片 hash 值,失败则是 false   ! x  F/ J3 I- u  s# b3 j9 p' T6 I1 W
  106.     * */      `/ X, Z, g6 F( p/ J8 X0 T; d
  107.    public static function hashImageFile($filePath){   
    % w2 x8 f! z3 v( ?  s: Z
  108.        $src = self::createImage($filePath);    / u4 @7 k$ N" v" _+ w
  109.        $hashStr = self::hashImage($src);    3 D* N  z% \9 ?; j
  110.        imagedestroy($src);    ) e* T9 G# m2 @+ [8 p# k
  111.    
    ( i2 p5 O* F+ `; y( b$ m4 x
  112.        return $hashStr;    5 c$ T7 {' q( u( B# t. w) q# G- Z
  113.    }   
    ! Y6 X- b$ U+ I7 L- r) b1 o
  114.     % a* h4 O7 g" u/ x5 w9 S! t
  115.    
    3 l- X) I4 H& f
  116.    /**比较两个 hash 值,是不是相似   : `" o% z5 b& a- X
  117.     * @param string $aHash A图片的 hash 值   
    5 O: `6 n( j6 N( P0 M
  118.     * @param string $bHash B图片的 hash 值   
    - U/ V  u7 |8 Q2 f
  119.     * @return bool 当图片相似则传递 true,否则是 false   7 G- A7 n" s1 R9 ^' l5 p; D
  120.     * */    ' Q/ G; I, m% k2 N8 I+ g
  121.    public static function isHashSimilar($aHash, $bHash){    / H! D/ F; v6 o' a+ \
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    # h+ i  n7 |$ h. Q0 R2 [* M! \
  123.        if ($aL !== $bL){ return false; }    ) }) L7 _! A/ s
  124.    
    5 T* ?9 c: q2 B
  125.        /*计算容许落差的数量*/   
    ) r8 N. k5 ]) T& _. J; @- ?1 [
  126.        $allowGap = $aL*(100-self::$similarity)/100;    : r) O& M7 `  M, I, n
  127.     3 }1 p6 I6 u2 F5 W# [
  128.        /*计算两个 hash 值的汉明距离*/    & T/ \( Y, r8 d1 y! A7 B8 s, B
  129.        $distance = 0;    + d; K, m! w6 i# ]
  130.        for($i=0; $i<$aL; $i++){    . a: R+ Y) o6 G- B6 b) E  j
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    % R8 [- z+ h0 x+ K2 n1 h, V
  132.        }   
    0 ?5 b* |. k* W! C  X1 e9 t9 W
  133.    
    " A: r4 A7 a, m( n
  134.        return ($distance<=$allowGap) ? true : false;   
    $ k! s8 X7 V/ K0 _4 X
  135.    }    ; m, P6 j$ _0 k! r
  136.     7 @. s% z: E% F3 h6 W- ^
  137.    
    5 K# S" X7 W) @9 F
  138.    /**比较两个图片文件,是不是相似   / R: k; Y2 a% |8 b+ n+ C
  139.     * @param string $aHash A图片的路径   ' C  Y% u. ?, q2 K2 k: Z; Z
  140.     * @param string $bHash B图片的路径   ' s/ i% g1 {; |  K6 X" t. O
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    . W" C: A0 W7 W" C, T0 R1 E4 _
  142.     * */   
    9 j4 M* J: b/ v+ b4 f
  143.    public static function isImageFileSimilar($aPath, $bPath){    5 E) ^& |; j: B  ]/ Y/ u
  144.        $aHash = ImageHash::hashImageFile($aPath);    # {* y  [' z/ j# T3 c7 k
  145.        $bHash = ImageHash::hashImageFile($bPath);    + C- G  x1 p0 n8 L& I
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    ' |% A% T# z) c9 w+ N  U
  147.    }    7 @: F' ~3 E' b: ?  n- z
  148.    
    1 R* @% W$ o* u. j+ D
  149. }
    # ?8 u4 `9 v0 ]4 B' d) Z& U- t
复制代码

! s8 `/ q% h- x- N; x/ S
3 B, {0 u# O3 d/ |
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-19 15:49 , Processed in 0.076063 second(s), 19 queries .

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