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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-7 23:06:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。  代码如下 复制代码 <?php    /**   * 图
) [+ t" S/ `. n8 ]" V5 E: j* |$ E  k1 {9 U' `& D* V: {3 H( v. L

" O$ o' c) o8 {2 |4 r由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

( d, |8 k2 p5 c9 }3 Q
  1. <?php   
    3 f1 F3 t9 W  ~0 }2 k& t% ]
  2. /**   
    1 S+ a, N1 U( ?% o
  3. * 图片相似度比较   
    8 A0 H' B$ ]& n4 f* B
  4. *   & b% p2 H- S  V6 O" o; m
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  1 E& W( [* f% P5 f9 `. X
  6. * @author      jax.hu   
    4 k2 B  b5 u' \" R; }$ I
  7. *   
    4 G" r8 C2 B1 D+ Y2 D; ?8 J
  8. * <code>   
    6 T5 @, C- M8 @8 ?
  9. *  //Sample_1   ) R' f4 A1 C7 j+ h, X  Y5 O
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   ! F8 t+ n8 E) y4 t$ c8 h
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   5 K! M7 @0 j; R7 V1 Q6 N. x2 H
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   6 [6 D8 y+ g7 u1 ?/ [
  13. *   ) r0 B' @/ t( h$ y+ G+ A, s" p+ X
  14. *  //Sample_2   ; `$ V" [# B$ U2 {
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   
    ! ?9 @# ?1 L6 k+ G
  16. * </code>   
    1 ~' v; n7 {( y" n
  17. */   
    ; v- N3 Y* m% Q+ N, ^% k
  18.     ( F  k# R* y' u5 G, z3 |
  19. class ImageHash {      C4 n4 K! Y( X+ g. y$ u. _; }
  20.     2 k1 S7 o% y5 `5 x- y9 T
  21.    /**取样倍率 1~10   
    * M# A( o9 u) K3 _2 Q* T
  22.     * @access public   
    5 ]* C1 M* u8 W: @3 p) i
  23.     * @staticvar int   " P7 y8 L! g# H
  24.     * */    8 A% m1 \; N, ]+ i. T
  25.    public static $rate = 2;    ' s, f/ s1 R2 s, {
  26.    
    % A0 p. x9 [% F4 z9 O5 W
  27.    /**相似度允许值 0~64   
    ; O: r" d8 h7 ~* i
  28.     * @access public   
    0 S; W. t4 W7 \5 z2 H% _& d9 }: f
  29.     * @staticvar int   
    0 J! Q) Y5 a% ~% n9 p9 \
  30.     * */   
    $ b8 Y) s! I6 B' q( |; X
  31.    public static $similarity = 80;   
    " E- C3 n3 A3 V8 _" p$ S
  32.       }6 q( x5 l8 }* @$ h; O
  33.    /**图片类型对应的开启函数   # {1 H5 i3 @* a: M4 v
  34.     * @access private   
    7 U% W" |2 l- f" B6 W$ U, a
  35.     * @staticvar string   ) J7 u* T. S4 e
  36.     * */    & f* Y8 d7 o1 j# L+ _  q3 u( M6 K$ U
  37.    private static $_createFunc = array(    6 y+ t3 c3 `5 d
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',    ' j" q# `6 K6 u1 J
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',    9 @: k. f* ~. H
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    3 ^2 z$ T3 w% x' [
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    * L2 {% }3 z$ S- w
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    : ^* t. V! f) Y  |1 O4 |
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',   
    ' _" H' i) ~4 G+ _- B1 ?1 z
  44.    );    5 t+ o& f& q! o5 l
  45.    
    4 I; T2 z7 W$ _& K  @7 K
  46.     8 `4 M+ s6 M5 E; Q& D, K6 W" v
  47.    /**从文件建立图片   1 ?  D' j2 q( {' w: W# f1 o3 {
  48.     * @param string $filePath 文件地址路径   . G8 b' v1 `; |7 Z" Z
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   ) a* w/ l. b; c9 ^0 n6 v4 a1 Y2 p2 u
  50.     * */    ( y0 J1 ?! O7 x
  51.    public static function createImage($filePath){    7 S" y! _* ^/ u5 {- B+ F' K
  52.        if(!file_exists($filePath)){ return false; }    2 C9 N. G* P: o/ @
  53.     ! {' D+ }8 }, ]( ~( R# m* v
  54.        /*判断文件类型是否可以开启*/   
    ; R8 ]; g7 r' g/ ~
  55.        $type = exif_imagetype($filePath);    : F# A. ~% }* d
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }   
    % U% B. N. M2 w( l1 X
  57.    
    # r$ t3 j) r0 _/ D* k3 O
  58.        $func = self::$_createFunc[$type];    & q; K6 E8 |; @- C* m
  59.        if(!function_exists($func)){ return false; }   
      J* R4 K9 q, Z% r5 |3 u
  60.    
    9 t; ?  e% s1 i" o% U
  61.        return $func($filePath);   
    3 h2 p0 b% y3 c: ~1 z) D6 h: U
  62.    }   
    + l! \9 ^" s$ m, s2 e
  63.     ( l% ~0 D+ p, X+ ^8 u, D( p
  64.    
    4 X+ |0 h) l2 @5 [4 z; ~" \! d
  65.    /**hash 图片   
    : i& i8 V2 F2 Y* _! c
  66.     * @param resource $src 图片 resource ID   / @1 n: C# {& p( ?3 ]2 T: C
  67.     * @return string 图片 hash 值,失败则是 false   3 w% a3 |& d* n' n/ C
  68.     * */    1 h& \* D: y* }9 {3 N
  69.    public static function hashImage($src){    5 _. c- O0 [# ~$ e
  70.        if(!$src){ return false; }    % K0 H- t5 W9 t6 l2 T
  71.    
    % o1 {  g, K* i( d2 M, n2 o
  72.        /*缩小图片尺寸*/   
    ; j2 a5 `% o6 s; f3 J, F- x  ^- h
  73.        $delta = 8 * self::$rate;    7 H7 @: G0 t. p
  74.        $img = imageCreateTrueColor($delta,$delta);    + S7 @& S7 L2 F+ w) s/ r" U
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));   
      e5 z  N  K' w9 o. ?
  76.    
    & j( k: W' _% |( v1 b
  77.        /*计算图片灰阶值*/    4 U% \/ ]; Q% x" k, m$ `
  78.        $grayArray = array();   
      @9 X4 |4 ^  Y6 p8 Y2 V
  79.        for ($y=0; $y<$delta; $y++){   
      L/ |# y" b8 S. K- |8 e
  80.            for ($x=0; $x<$delta; $x++){   
    2 Q+ g0 E2 {/ T8 e6 u
  81.                $rgb = imagecolorat($img,$x,$y);   
    8 q$ h1 x# Z2 k  ~' K4 _: Q
  82.                $col = imagecolorsforindex($img, $rgb);   
      g  ?" }6 f9 g3 S' T. F; z
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;    ! b3 g* l: M2 p* p; `( G
  84.     . v* {$ ~. g# Y$ _+ k
  85.                $grayArray[] = $gray;   
    5 U% l' ?/ p6 V; z. u+ _5 g
  86.            }    / P5 X5 G, B# ^! o7 P3 A: x
  87.        }   
    1 U$ I6 h) `( U! e, V
  88.        imagedestroy($img);   
    1 N+ M5 ?2 f: Z# n% D1 t
  89.    
    5 |2 W: R1 j/ `3 O
  90.        /*计算所有像素的灰阶平均值*/    0 E5 z1 r9 x8 m! D$ J' Y6 k% @
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ! x; ?) B+ G, }
  92.     , C5 p' r  s* i
  93.        /*计算 hash 值*/    - ?8 _' D  ]9 a" L/ T( g( N: ?6 A
  94.        $hashStr = '';   
    6 J9 g& g, l8 D4 N0 ]( P0 y. ], D9 T
  95.        foreach ($grayArray as $gray){   
    ' ]/ g/ q4 C3 I
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    2 R7 W" ?+ V) c! P5 }  e
  97.        }    $ @. G9 d7 L' `8 e9 z6 q8 A
  98.    
    ! g' ?3 i, E% a/ Z: T
  99.        return $hashStr;   
    9 i, t+ v. j7 a/ v5 p
  100.    }    & m! ^( _+ L3 x( C1 |/ X' c) ?
  101.     0 z5 F+ t, Y+ a2 w5 N  C
  102.     - M: ~, [+ ~4 v! W% y. G
  103.    /**hash 图片文件   
    ; Z8 d% ?" e$ T0 d# |- l
  104.     * @param string $filePath 文件地址路径   
    " h3 T# O7 W* f: {4 g
  105.     * @return string 图片 hash 值,失败则是 false   
    ; B' y+ E6 e: ?3 l+ |/ F
  106.     * */    + o3 G% A) p" z% n% h$ b5 g2 p
  107.    public static function hashImageFile($filePath){    ' ~5 e! q$ j- b( t+ l4 {# ~. q
  108.        $src = self::createImage($filePath);   
    5 {- q5 v1 D5 @
  109.        $hashStr = self::hashImage($src);    : f8 p* J# E) `1 I+ X. x/ o* V
  110.        imagedestroy($src);   
      p$ u6 U0 I8 @
  111.    
    3 c$ G7 q6 X$ P
  112.        return $hashStr;   
    . X8 U/ X7 T+ r$ p0 I" g" P4 u" [+ {
  113.    }      X4 l$ y% r/ G" R/ j3 ?  |8 [, ~. }
  114.     ' d/ z; \" O9 ^! D
  115.     0 z) z" }7 C3 S8 U. q0 @- r
  116.    /**比较两个 hash 值,是不是相似   
    ! [) ~& y, l3 e5 T3 n
  117.     * @param string $aHash A图片的 hash 值   6 j3 n4 @- \; _" A
  118.     * @param string $bHash B图片的 hash 值   - x5 |1 B7 i# p7 a
  119.     * @return bool 当图片相似则传递 true,否则是 false   6 _" s/ g# D, a% q+ ~
  120.     * */    0 _( |7 q* g$ q
  121.    public static function isHashSimilar($aHash, $bHash){   
    4 {2 J% t, w1 S
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ( |3 l. {8 T4 R
  123.        if ($aL !== $bL){ return false; }    - s5 T! Y  B# x/ ?6 h+ v
  124.    
    3 V/ u( z. c7 o8 D
  125.        /*计算容许落差的数量*/   
    9 w) X# k9 n4 L0 N7 B5 Z( s8 {
  126.        $allowGap = $aL*(100-self::$similarity)/100;    ) E, o2 A6 O1 y6 h* i# s
  127.     3 ]) {. I, c9 x  |
  128.        /*计算两个 hash 值的汉明距离*/    + E# ?- ~9 I( x1 P3 p3 N
  129.        $distance = 0;   
    % N: N, L" g; T1 }
  130.        for($i=0; $i<$aL; $i++){   
    , q3 |  C) Z! X2 l6 K1 h. b! J
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }   
    $ Y& u3 |5 O' y+ Z8 O
  132.        }   
    % A; }% b- o. H9 b
  133.    
    $ ?' v) f8 \' ]$ u8 W+ I! M* X
  134.        return ($distance<=$allowGap) ? true : false;   
    ) p& }- N2 l4 A# t
  135.    }    7 D# S; S4 o; T' e4 s
  136.     ' C% \; a- c8 o! \- A8 |$ Y8 O" P
  137.     , T0 [7 v+ \, Q
  138.    /**比较两个图片文件,是不是相似   
    6 r* I/ ?# R8 _! z
  139.     * @param string $aHash A图片的路径   
    8 r# f; |/ L: b/ e3 F9 Z
  140.     * @param string $bHash B图片的路径   3 z0 i" M5 g5 W$ t+ l4 W
  141.     * @return bool 当图片相似则传递 true,否则是 false   
    ' L* t: W- p. u' h; Q' k9 f
  142.     * */   
    # B8 `( b( i. p6 c
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    & e) O- t5 f8 k: |. c3 A
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    5 o' M1 I: i* W- [3 Z7 z& o# ]$ F
  145.        $bHash = ImageHash::hashImageFile($bPath);    * K5 x! |: ?2 \+ Y3 p
  146.        return ImageHash::isHashSimilar($aHash, $bHash);    ' A! K* z7 }2 n" v- F4 O
  147.    }   
    % V2 _1 _9 x9 U! ~' Y
  148.    
    9 `( Z: I' ^- a& J% D/ A6 a4 l
  149. }0 o9 ?, \$ q* ]+ L
复制代码
$ K# C$ D) d" t/ {# E& W
) O8 e  Y4 b6 t. [
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 02:07 , Processed in 0.066789 second(s), 21 queries .

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