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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图, C, h7 P# m. R2 c$ _) o
+ U& h& |8 i# Y# d! N
: }4 _! j3 C* m% L$ g
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
  X" A0 m. I4 U
  1. <?php   
    # J8 ~9 @. g2 E
  2. /**   
    " V7 [  x- W7 E# j
  3. * 图片相似度比较   7 N; G: B) |8 s
  4. *   % `% g+ c/ q1 D
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  . h/ i6 N1 `1 h6 u/ a  ~/ i1 }
  6. * @author      jax.hu   ) V# N- H9 j7 m3 S: G$ h9 f
  7. *   9 S$ h4 E6 L. G7 s7 _
  8. * <code>   . |% r& V% Q' F3 O' k8 D# C. n: ?
  9. *  //Sample_1   
    ! Y0 Q: `* t% a1 K: M3 n0 [& V, U
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   ! V: u% b/ S5 Q* `
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   * Q( `- S5 W5 q
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    5 x. A: @- r/ q+ b# l: u7 _1 h' t
  13. *   
    ) H; A! `  x- [0 n$ K
  14. *  //Sample_2   6 L) S# H3 F' q4 P8 w$ `4 R
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    , X6 ^3 P, ?, G
  16. * </code>   : z  k# ^3 [1 s+ [0 }
  17. */    ! g/ z1 S6 d( @8 U5 |
  18.    
    1 t7 c7 U8 o7 x+ S6 D# S' N
  19. class ImageHash {   
    ' g# W; N% T/ H7 \
  20.     : }' {5 W7 `  G. Z" U9 w
  21.    /**取样倍率 1~10   3 u0 h6 Y- _  [, ?( [
  22.     * @access public   
    6 k* x  s4 Z, ]1 {7 d* J% @
  23.     * @staticvar int   
    1 `- _! }% U0 d
  24.     * */   
    ; E8 D0 w  ?4 h2 s8 s
  25.    public static $rate = 2;    - e2 Y% M. b+ I/ k/ F
  26.    
    ; o* k% I6 X6 C% O6 n
  27.    /**相似度允许值 0~64   # ]: V5 d$ O5 Z5 |
  28.     * @access public   
    - V9 m  k: z4 E! Y
  29.     * @staticvar int   
      {! u. _3 c( I6 Y! _$ F* A
  30.     * */   
    3 R9 O* U* o/ @+ Z1 p
  31.    public static $similarity = 80;    ! w3 H" N" {# ?; N; b
  32.    
    " }4 T2 |, L, f5 [: L9 A2 O" r
  33.    /**图片类型对应的开启函数   
    * O8 O5 g) K( @& a& p% ^, `# c
  34.     * @access private   - J) K5 K/ v3 G$ p$ f
  35.     * @staticvar string   , n3 e7 c4 G, }# x) S3 ]% ?/ @) t
  36.     * */   
      ~  J7 K9 A* m
  37.    private static $_createFunc = array(   
    9 w8 q  u( Q- c- \+ M( Q" X4 y
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    + r& u4 y. P; @. j
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    3 c  w& l! L/ a. ~
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    * U  J; N- ]1 u2 \+ Q% v, {
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',   
    ) u9 `2 W9 u9 Y
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',    & x0 a( R4 U) X4 z& z: \2 C* X9 d- W
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    4 E( Q/ }0 z9 j1 h! B( M% L+ e; B* A
  44.    );   
    / E: d' B$ S& k& p& B" c
  45.    
    2 |- L2 t" ?& w
  46.    
    # v1 b6 X3 p# E: b1 i; }
  47.    /**从文件建立图片   
    - y% I7 E6 C+ I& V8 \
  48.     * @param string $filePath 文件地址路径   / H2 z4 k8 t% S3 T
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   
    ) j  P: n; }# J( ]5 y7 c
  50.     * */    - N, Y+ b; W+ Y% l' |: _, [
  51.    public static function createImage($filePath){    9 B" n4 f% b/ V, T2 O; O
  52.        if(!file_exists($filePath)){ return false; }   
    7 l% h9 s8 c/ l& y$ T* m
  53.     6 D4 Z( D% ^, K4 P0 T
  54.        /*判断文件类型是否可以开启*/   
    ) V9 h: M# `& g' i/ H% j! u
  55.        $type = exif_imagetype($filePath);   
    . |3 i, P, c8 d0 t7 d
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    + {" C" P4 j9 [* U6 \5 U
  57.     ! F, r. I: k  U4 b8 D$ Q) x: m3 `1 U
  58.        $func = self::$_createFunc[$type];    + Q+ U, H* L- @- v) Y$ ?0 n
  59.        if(!function_exists($func)){ return false; }    6 ?0 j& {6 M( B+ R) O7 z
  60.     4 t, Y: Z9 R7 k/ k& j9 ^! R
  61.        return $func($filePath);   
    9 D1 I5 a: E, i$ B1 X  k
  62.    }    ( N1 g' o0 j; U% C
  63.    
    4 P( ^# b' r$ {) P8 b
  64.     1 B  E6 U/ `/ W, U- K, r
  65.    /**hash 图片   - ^# i; V2 t5 W  i
  66.     * @param resource $src 图片 resource ID   
    7 N1 p, r" {- X( k, `2 n. e
  67.     * @return string 图片 hash 值,失败则是 false   ( k/ V" Z/ i8 p
  68.     * */    . Y3 s9 p9 g1 g1 h& b0 B
  69.    public static function hashImage($src){    / w' w8 w8 c: F: D9 L2 I9 C
  70.        if(!$src){ return false; }   
    : b) w1 X( B) X! U) v$ G% Q
  71.    
    2 j3 F  C. V6 z+ @) ~% G1 P9 ^8 P
  72.        /*缩小图片尺寸*/   
      X0 P7 z3 Y2 b4 k: V4 l
  73.        $delta = 8 * self::$rate;    # |5 _) Y. H1 y4 {
  74.        $img = imageCreateTrueColor($delta,$delta);    9 {4 G4 v- G, c3 R8 `+ Y  C$ L
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    . K8 V& Q- u5 w( n' e: O
  76.     . o* p) {% P, y
  77.        /*计算图片灰阶值*/    0 @6 w% M; u  ^  u
  78.        $grayArray = array();   
    - C0 m* V3 U, h4 S8 q
  79.        for ($y=0; $y<$delta; $y++){    ; d7 w7 C8 I% s/ k
  80.            for ($x=0; $x<$delta; $x++){   
    ! }; q# d1 O( p
  81.                $rgb = imagecolorat($img,$x,$y);   
      r1 y6 r+ w$ o( J+ }. b
  82.                $col = imagecolorsforindex($img, $rgb);   
    . F% j( @: c( w6 t
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    0 f5 ?& B6 S: p
  84.    
    7 o5 P* k5 H. R& s3 G- e
  85.                $grayArray[] = $gray;    9 A2 B, M& N/ ?# j
  86.            }   
    4 q( o/ f* P  ^; X
  87.        }    ) a& w+ ?- K* z2 z
  88.        imagedestroy($img);    " R) `4 _  o$ \# G6 m' [2 i
  89.     ; M( V+ x& m4 I+ J) Q
  90.        /*计算所有像素的灰阶平均值*/    6 B9 G3 b! h( U' w
  91.        $average = array_sum($grayArray)/count($grayArray);   
    6 O2 E2 L8 S$ ^
  92.     $ a8 N7 M/ q! T( g+ K; w
  93.        /*计算 hash 值*/   
    + Y9 M6 [5 l( G, E1 a
  94.        $hashStr = '';    ' w1 d4 j5 E0 s. ^
  95.        foreach ($grayArray as $gray){    : @- S6 r; ]% E. u
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    , v1 P& S% \9 V0 c! f5 ^
  97.        }    # P1 T1 P$ q6 j& L8 h6 J8 F
  98.     ! ~7 h* f; k' P! }8 M( _# `) B' h9 G( P
  99.        return $hashStr;    2 \: E5 b+ N8 A' D- z8 P
  100.    }      h% e8 o* N7 z. J$ I1 P8 M
  101.     ( b2 v; E2 n  G$ k
  102.     : y: [: C8 ^' j* H# p
  103.    /**hash 图片文件   
    , }! r0 L- x2 n" Q  s9 B; C  p
  104.     * @param string $filePath 文件地址路径   
    6 G) G# \% w/ X' c" x4 a. j; v. s
  105.     * @return string 图片 hash 值,失败则是 false   
    + V' u" ^$ H; B
  106.     * */   
    # A& q2 A# d  G# w/ L  o5 D5 A
  107.    public static function hashImageFile($filePath){   
    5 C1 M1 K! d! v
  108.        $src = self::createImage($filePath);    " x5 `8 P* p) v- ?- Q4 X. ^9 J
  109.        $hashStr = self::hashImage($src);    ! x3 A' M( n$ q, A5 X
  110.        imagedestroy($src);   
    ( [$ N$ L6 w' _% H
  111.     + L5 F# U9 P. [# d) L
  112.        return $hashStr;    3 S4 |' H5 R/ K" N0 X2 x+ I
  113.    }   
    4 Z& E! d3 {: o% i6 p4 \: x) x
  114.     % v) s3 n6 E3 i% }" p6 S3 H
  115.     2 f6 E4 p; ]3 K% r
  116.    /**比较两个 hash 值,是不是相似   / o8 L4 R9 `: O
  117.     * @param string $aHash A图片的 hash 值   
    ) y" K% I9 b  D6 G
  118.     * @param string $bHash B图片的 hash 值   
    ; j7 y' A$ |! f. R# x/ t  _
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    * F; q4 s+ O# T8 p6 U! ~
  120.     * */    : L0 J9 m% T3 P$ C$ k6 ?5 Z5 a
  121.    public static function isHashSimilar($aHash, $bHash){   
    ' L% B7 E- p. g/ \
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ' O5 Q5 T4 E+ _, W# a0 J
  123.        if ($aL !== $bL){ return false; }   
    4 ^; Y3 j+ I$ ^( Z8 L4 O9 `; u
  124.     7 J% p( ^) B# s( `
  125.        /*计算容许落差的数量*/    2 _5 x3 ~) L7 I- j; B4 {
  126.        $allowGap = $aL*(100-self::$similarity)/100;      K3 p8 b$ I" M) z
  127.    
    5 w( T% H6 `$ b+ b3 r$ g3 r) s
  128.        /*计算两个 hash 值的汉明距离*/    2 l* c# P8 J. I9 h" x2 u4 Z
  129.        $distance = 0;   
    ; `" Z7 d( ~9 C8 y) R& _; _
  130.        for($i=0; $i<$aL; $i++){   
    : c, ]) Q1 @6 |' ?- W
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    : q& Z, n/ M, T. P  `
  132.        }   
    # ^. H/ b+ q* }1 s: i
  133.     0 I; S5 d! z. G( ?/ H) u/ e4 x  j
  134.        return ($distance<=$allowGap) ? true : false;    % \1 I) ~* X1 k* K* j
  135.    }   
    8 F: S" a; M3 A8 l0 R
  136.    
    8 X* _% ~# c* M
  137.    
    ; n8 N. W; O! U) Z& x0 C
  138.    /**比较两个图片文件,是不是相似   
    - f. Y5 c  P! s& J1 ]
  139.     * @param string $aHash A图片的路径   4 Q$ T* I' y  ]3 N* h
  140.     * @param string $bHash B图片的路径   ) T: e( F$ n3 e$ C, X$ E
  141.     * @return bool 当图片相似则传递 true,否则是 false   0 G+ \; F7 E2 C! Q7 \2 O; U4 M
  142.     * */   
    9 E6 `7 Z2 g* c2 F6 ^1 Z: C: n
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    2 {% F. w: c* o4 n; t& J; x7 S
  144.        $aHash = ImageHash::hashImageFile($aPath);    0 Y0 |' m: l( Q3 [2 J
  145.        $bHash = ImageHash::hashImageFile($bPath);    4 ~( @' K1 p* w
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    5 Y7 g* H9 k1 b5 S, V$ ?
  147.    }   
    . Y3 Y. o! g- R/ p
  148.    
    5 }" I( b& S" a
  149. }$ i6 m+ s& k% O$ M
复制代码

: b+ x5 i" y4 l8 W! q3 D% m4 z) y- |' J% ^6 \4 K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 14:07 , Processed in 0.112522 second(s), 19 queries .

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