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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

: R0 m% \7 ?* I由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

( K3 w2 r  O8 d: x
  1. <?php    # I' @9 M# N9 @+ v0 J6 P7 D0 [
  2. /**   7 q0 U; L! F3 r/ W: e3 z
  3. * 图片相似度比较   ! ^; f. o" X) w, D
  4. *     w# q' ^" _3 N7 U" C# x" d" u
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    ( U! l0 H* y4 e" c( ~
  6. * @author      jax.hu   $ s! i2 F- s* {+ Y
  7. *   
    5 N: f: ~/ b6 h
  8. * <code>   1 y5 S, \) Y0 ?8 P: s: j3 Z
  9. *  //Sample_1   
    0 E) j: N# K+ e
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   - Z8 ~* j0 y; [* K/ g* e. S
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    ( A" u1 Y- L: U
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
      n7 {+ R5 k; z. o# P4 _* R5 j
  13. *   2 z8 G9 K0 u6 e% V. ]
  14. *  //Sample_2   / s( o2 x4 I; t( {- _+ h
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    4 q) T0 @. E- Z3 r; d- I
  16. * </code>   : s  N6 Y+ `  k0 _
  17. */    - P% b8 i% y8 a0 X
  18.     # J5 t8 F+ n5 [" Z( Q) k  J4 [
  19. class ImageHash {   
    1 _6 U$ Q' @0 Y% [' ?' z% ]
  20.    
    . H# W3 p9 o) Y9 s
  21.    /**取样倍率 1~10   
    . j9 I) p! j) ]. _, {0 T- b; f( Z; x
  22.     * @access public   6 I) R) K/ ?) U4 f7 R
  23.     * @staticvar int   % Y9 n7 o3 B& J& L
  24.     * */    - o7 W6 C0 f. e- F8 s, K5 A+ ?
  25.    public static $rate = 2;    ! x5 p7 X  c! M3 a5 `; Y
  26.     " ~. ]% f' K! ^
  27.    /**相似度允许值 0~64   ' p0 [5 W* ?9 l9 G8 M" U9 ^
  28.     * @access public   
    / l2 X- D( L7 a: E
  29.     * @staticvar int   ; u7 I- ]. `. X- a* S  n
  30.     * */   
    ! n9 w8 W, K. W: ^1 \& m9 Q
  31.    public static $similarity = 80;   
    + k6 x# p) [2 i- I. Z
  32.     ) E, i6 w  g9 z2 n  N
  33.    /**图片类型对应的开启函数   3 ]# s2 I" M7 @' Z$ D' H$ Y
  34.     * @access private   
    : l8 f6 t7 K0 {
  35.     * @staticvar string   
    ' w& g+ _; f0 f' a
  36.     * */   
    6 D( C9 t$ U; t' Z) I0 s! ~
  37.    private static $_createFunc = array(    - q& V: J! L% M. M
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
      ]8 O# K8 ]0 l* ~; h  M/ I2 S
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    2 @7 T1 h- n0 I! I
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',   
    8 f. j& }& D  a9 l
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    0 u* U5 {4 L2 z1 t7 Y1 B) f# t! {
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    , C$ \- |% s4 p! ^
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ! t  R) q5 E: n
  44.    );   
    4 i2 s* L$ A7 k
  45.     ) _9 @+ P) K$ L; O1 B" O0 Z" z4 z- W
  46.     ; Q& S9 r2 ?  E; h1 ?% `
  47.    /**从文件建立图片   + G' S  ]: [* t' v
  48.     * @param string $filePath 文件地址路径   
    + x2 E( ^' A; a, O/ f4 y- T* A
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   % C- }: H0 _( o' _- V
  50.     * */   
    ! c, G! c2 G( G9 l. [& H' {
  51.    public static function createImage($filePath){    3 {' e( N) S7 S5 Q
  52.        if(!file_exists($filePath)){ return false; }    7 K) d  J. C! c2 s* i+ h
  53.     ! s& M: {5 L* ]; O0 B5 }
  54.        /*判断文件类型是否可以开启*/    3 ?) h: y, E0 y4 B3 L/ R
  55.        $type = exif_imagetype($filePath);    9 S2 y2 Z7 L1 N3 [3 D+ [
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    0 i) z' g6 l4 H, o3 D
  57.     . r' ~3 F/ x) f. M5 f. P& |9 M/ Z
  58.        $func = self::$_createFunc[$type];      s/ N& {5 o9 ^
  59.        if(!function_exists($func)){ return false; }    9 J! k/ ?  x5 W6 G
  60.    
    , h! F' S1 o3 {; h' ]7 }" Q! d. Z- F
  61.        return $func($filePath);    / o3 w0 f" r! x3 ^& M
  62.    }    , M" ?" ~- x0 o5 t3 _- g
  63.     * M6 t& ~1 [5 |% H
  64.    
    3 k6 ~) O) K4 q- L* h; V
  65.    /**hash 图片   + |& F) e) ?1 L, v3 \
  66.     * @param resource $src 图片 resource ID   
    - {: R- s" m7 J
  67.     * @return string 图片 hash 值,失败则是 false   . Q3 ?1 \, c& g8 E8 d
  68.     * */    8 n: D5 F- ?' h, v6 j
  69.    public static function hashImage($src){    $ Z! a: `+ J( |" ]& s
  70.        if(!$src){ return false; }    $ l. S- m8 N9 X' c- @
  71.    
    0 R: C$ i4 j* D/ X
  72.        /*缩小图片尺寸*/   
    ; c; s4 a: i$ Z$ B$ k
  73.        $delta = 8 * self::$rate;    - C, g0 Z& T) ^/ ^! m" X. ^: |
  74.        $img = imageCreateTrueColor($delta,$delta);    , v) W7 Z, u+ d! I: \, ]2 r' E
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    , K4 b: A: d, r7 m& |4 P) x
  76.    
    + h9 p- {! l# \9 q% s6 n8 b2 \
  77.        /*计算图片灰阶值*/   
    $ V2 B: {' Q, @* z6 {" N
  78.        $grayArray = array();   
    + c5 d5 Q- C) z0 b# s
  79.        for ($y=0; $y<$delta; $y++){   
    / {! O% x, h1 F+ V. D8 c9 Y
  80.            for ($x=0; $x<$delta; $x++){   
    2 d# |% E  G; |
  81.                $rgb = imagecolorat($img,$x,$y);   
    " Z8 H+ X  ~* C! e. V/ A" B7 k
  82.                $col = imagecolorsforindex($img, $rgb);    + B" A& o( X. Q* ]' G- h
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    0 g2 T! S8 j' a) u. P
  84.    
    0 ]0 C$ |% z4 a! \/ X
  85.                $grayArray[] = $gray;   
    , q% H) ?2 m% C9 C
  86.            }   
    5 ~% r2 u) p9 P
  87.        }   
    1 |' `  r: e0 k. p- Z0 ^
  88.        imagedestroy($img);   
    ' J4 `/ O, w6 J- x$ b( B+ I
  89.     1 c4 `: q) r" k% H1 [, Y: k
  90.        /*计算所有像素的灰阶平均值*/   
    - E3 t  k% m7 l( d
  91.        $average = array_sum($grayArray)/count($grayArray);   
    . x' x4 \& x- J5 L
  92.     ; Z) k* a8 Q' r6 u
  93.        /*计算 hash 值*/   
    " R9 Y* \) v9 J0 ?  P" d' D
  94.        $hashStr = '';   
    5 ]. u) ~" r1 K
  95.        foreach ($grayArray as $gray){   
    0 V% ?) }% A: }. o- \1 _- C8 m
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    : F% O# r/ w9 n" z( i5 a
  97.        }    2 k% Q4 v3 V$ T! r+ S- M$ e2 E
  98.     7 M+ z. v$ o  a1 S" Z& i
  99.        return $hashStr;   
    * w8 p; Q7 ?0 e( i. M( ]0 f6 q' M
  100.    }   
    - u. z/ T; @- k5 j/ u
  101.     5 r$ m5 P! s8 f& Z
  102.    
    / o) t; N( Y3 e* E; I1 J
  103.    /**hash 图片文件   
    1 H0 b  A- g+ x( W! f% z. ^
  104.     * @param string $filePath 文件地址路径   
    4 ~5 K- _4 j9 ~- b
  105.     * @return string 图片 hash 值,失败则是 false   # C& L& G8 M9 I' i' b
  106.     * */   
      D3 T/ @, z, y0 u9 X
  107.    public static function hashImageFile($filePath){   
    * e* d; z. B2 d7 e4 O3 A7 |, V
  108.        $src = self::createImage($filePath);    4 e- n1 a% M( E9 }3 T6 a. U7 r
  109.        $hashStr = self::hashImage($src);   
    2 i5 E- K3 _7 i! O/ L1 }2 a# L
  110.        imagedestroy($src);   
    / o# C! V4 p" B5 F7 }6 x4 S. O
  111.     + u2 N+ y2 H  v$ c" N9 w0 Y: q2 ~
  112.        return $hashStr;    4 F' K2 a; s/ h7 k5 @6 ^! q5 R
  113.    }   
    ' P7 w6 ^1 H5 h7 r, |
  114.     - U+ G- Z4 @: a2 V0 y
  115.    
    9 x: W  z# D0 O. [* Q) B0 B
  116.    /**比较两个 hash 值,是不是相似   
    # b; y! {& \/ J' t9 I. `) q
  117.     * @param string $aHash A图片的 hash 值   
    ) I5 J6 |6 d7 [7 @8 w  s0 w* V
  118.     * @param string $bHash B图片的 hash 值   
    0 P, L3 m0 ?/ ~& D" G
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ! `: J0 K3 c0 o0 A9 K
  120.     * */   
    0 f7 P6 }! `) ~5 y- X) A2 G
  121.    public static function isHashSimilar($aHash, $bHash){   
    - a' k" q# M8 [2 H% _. M
  122.        $aL = strlen($aHash); $bL = strlen($bHash);    6 \1 L, f# w+ [* u8 N3 D% i, @
  123.        if ($aL !== $bL){ return false; }   
    % K1 y4 k$ u* X' V! ~
  124.    
    , d' U3 B  w" I
  125.        /*计算容许落差的数量*/   
    & V  w) J! v) A" e2 l; o/ s
  126.        $allowGap = $aL*(100-self::$similarity)/100;      p* l& U) ~, X+ D) x: L
  127.     0 d; m4 Z0 v$ U. e, f* t4 q8 c
  128.        /*计算两个 hash 值的汉明距离*/    * \* ^: p4 V9 H7 b9 G
  129.        $distance = 0;    : d/ U5 t  L, B, D% Z
  130.        for($i=0; $i<$aL; $i++){    4 k/ C6 @( \, C+ k: a
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    " [- J9 F: V, n* ~
  132.        }      p8 J1 o& z' a( A2 f, n# ]
  133.    
    - U! J8 E4 U3 [9 y2 Q* [: [: a
  134.        return ($distance<=$allowGap) ? true : false;   
    8 h2 w0 T0 w; F
  135.    }   
    9 Y* o; X% |4 D; H$ ]1 l1 X7 \' o
  136.    
    3 x/ X1 T; z4 l1 w
  137.    
    9 [9 P, V. t8 q5 U
  138.    /**比较两个图片文件,是不是相似   
    9 v7 O9 O4 b% E" W
  139.     * @param string $aHash A图片的路径   : H8 C( B8 T; w- }1 V+ q# s
  140.     * @param string $bHash B图片的路径   
      z9 _+ Q0 c8 w
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    : H) o& Q0 z: X# e# C: s. h' Z# X- S
  142.     * */    ' T( Y# }; L5 Q* k: Z
  143.    public static function isImageFileSimilar($aPath, $bPath){    $ M. i. o& `: a4 i) e! O7 t- s
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    % _' [( J6 Z, o+ l
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    # V' `8 z$ T. E! F
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    9 z  a; O% {! x2 p
  147.    }    . X3 U* A2 c2 q, c5 s& ~! k
  148.    
    1 _7 Z# c# A# `+ C8 z8 }# k4 h
  149. }
    5 t* B# x! R% F6 ~/ R9 y) g; N
复制代码

( U* N" W; A# v/ Y* K3 ^1 T* Q7 {1 N
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 20:06 , Processed in 0.130833 second(s), 19 queries .

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