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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

$ L# }0 @4 K# C& G9 M( Q# u由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。

3 w/ [9 w5 T! H: O6 N9 W! L, ]0 Y8 V
  1. <?php    & |& b% s7 X! r' x! x9 ^
  2. /**   , @8 |+ n1 y- p+ m0 g8 q2 T, e' O
  3. * 图片相似度比较   
    % U) J. @' w; F3 i+ _
  4. *   ' w" g5 F5 k( @
  5. * @version     $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [        DISCUZ_CODE_1        ]nbsp;  
    2 V; B+ [" n4 Z4 W0 K
  6. * @author      jax.hu   % n- w7 A% }: N* a4 L5 H
  7. *   / ~6 H* V  {! G% a1 Q1 r
  8. * <code>   
    0 o  K+ I( _& z  |; d% X
  9. *  //Sample_1   $ s* m! k7 j0 j8 H- n
  10. *  $aHash = ImageHash::hashImageFile('wsz.11.jpg');   4 M! z& H, R4 D7 _5 ^' w
  11. *  $bHash = ImageHash::hashImageFile('wsz.12.jpg');   
    . d8 L5 e7 K. H7 K. P; z4 P/ J
  12. *  var_dump(ImageHash::isHashSimilar($aHash, $bHash));   
    " b/ O4 g! `+ ^% y
  13. *   
    " }7 a) G/ W6 C! P# c0 l. \% X) l
  14. *  //Sample_2   " y) x$ |1 N  g1 ~( S3 O+ c/ l
  15. *  var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));   0 q. j+ ~$ o8 k* U! `7 _( z- H7 e& r
  16. * </code>   # r7 F. |) x  |' x8 n& ~
  17. */   
    . V* ~+ m3 x3 ^8 Q" g9 a
  18.     : l7 G4 [- \9 g& L
  19. class ImageHash {   
    ! H- j/ i% N. c- Y- y6 ~
  20.    
    0 [  q; n! p( `$ w
  21.    /**取样倍率 1~10   - s  ]& w. y  F5 l
  22.     * @access public   
    ( c( a2 C( {  E$ }7 T5 s! {8 C
  23.     * @staticvar int   * y1 Z' P* Z9 h2 N* H
  24.     * */   
    # Y2 ]" W0 H4 w4 o
  25.    public static $rate = 2;    % s# z8 K3 P/ o$ e7 c4 M
  26.    
    ' Y, ^1 |$ _/ B+ _6 y; D
  27.    /**相似度允许值 0~64   8 A# o6 q' A% C  v0 Y
  28.     * @access public   , @, u5 N$ ~) T: Y
  29.     * @staticvar int   
    3 S2 v" j  h$ J4 j
  30.     * */   
    ! N# g0 E4 l3 H4 D" F- Q* S
  31.    public static $similarity = 80;   
    " H1 s0 q- b" h4 G7 N! |: o' ^
  32.     / m; t+ \2 T. _" k; h( l
  33.    /**图片类型对应的开启函数   
    # y* S' r, j& @! T6 _2 x+ @2 U
  34.     * @access private   2 W5 v" H, c; x2 I$ i  u8 A) Z
  35.     * @staticvar string   
    ) P% w' ]: l6 Y7 ?
  36.     * */   
    " n3 _5 t0 i. a, s3 y
  37.    private static $_createFunc = array(    $ ^" ?! d' m3 e% f
  38.        IMAGETYPE_GIF   =>'imageCreateFromGIF',   
    ' ^9 B9 l& k9 F: m1 Z
  39.        IMAGETYPE_JPEG  =>'imageCreateFromJPEG',   
    % N  o# Q" r$ Q- W* S, Y# ?
  40.        IMAGETYPE_PNG   =>'imageCreateFromPNG',    - N. b" ]; d/ n  I. s3 {" G
  41.        IMAGETYPE_BMP   =>'imageCreateFromBMP',    " E7 A5 ~- R5 o) G( `+ X
  42.        IMAGETYPE_WBMP  =>'imageCreateFromWBMP',   
    7 R0 N0 A% ~3 R! V' r0 Q0 z
  43.        IMAGETYPE_XBM   =>'imageCreateFromXBM',    8 j$ L. S. M- s
  44.    );    ) r9 R8 J$ Q7 L: [
  45.    
    ) r' H* L( z+ i, z9 @% R/ X8 Z
  46.    
    % ^6 [8 p5 g' x3 k5 p. h* o
  47.    /**从文件建立图片   + {/ w( l! Q& M6 I9 ~
  48.     * @param string $filePath 文件地址路径   . L+ C5 j" P  C+ x: u
  49.     * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false   5 `6 f( [, _7 j0 R8 r# A
  50.     * */    & D: l8 C3 E8 }3 q, s2 o
  51.    public static function createImage($filePath){   
    - `2 p! m6 E* n1 k9 k
  52.        if(!file_exists($filePath)){ return false; }   
    + Y3 \2 v# t+ C& e/ d: u( x
  53.    
    / u2 J6 f0 y8 Z  L5 t1 g
  54.        /*判断文件类型是否可以开启*/   
    " \  s# F: S& `9 U- f
  55.        $type = exif_imagetype($filePath);   
    # ^7 S% a& E9 Z0 d% `% X; L0 N
  56.        if(!array_key_exists($type,self::$_createFunc)){ return false; }    + y- R$ @% Y' o2 f, a' S
  57.     ; x+ E1 k: T& }) ~) a! ~
  58.        $func = self::$_createFunc[$type];   
    , Y! f8 g7 e, b/ ]2 j
  59.        if(!function_exists($func)){ return false; }   
    * E# G5 ~8 |; g9 S! k
  60.    
    # V. |( s3 W) {  w0 w+ g- k' q
  61.        return $func($filePath);    - O2 h) X0 z& c+ h9 i
  62.    }   
    2 \" }* k; _# ^( }
  63.     ! ?9 ~: [2 b  Z- ]- e' q; J
  64.     : t8 ?0 Q0 l8 N$ {) M4 y6 W
  65.    /**hash 图片   * w/ @# |4 ?, r! f3 R' ~
  66.     * @param resource $src 图片 resource ID   
    4 G) q0 N$ K) z/ L( g
  67.     * @return string 图片 hash 值,失败则是 false   
    : K6 m7 ]+ G& E8 F
  68.     * */   
    ; B; R# {) @/ R8 g* l$ B' w
  69.    public static function hashImage($src){   
    1 e  b1 e% x2 x+ F
  70.        if(!$src){ return false; }   
    1 z: v4 C) f9 g5 g
  71.     * V1 u& J. L* |& R' l8 `
  72.        /*缩小图片尺寸*/    5 ]" w6 Q$ z' [6 c  B! L1 c2 V/ O7 D
  73.        $delta = 8 * self::$rate;    7 ?9 r. z8 A$ t6 I1 E4 v, U$ X: V
  74.        $img = imageCreateTrueColor($delta,$delta);   
    0 V4 D4 [) [% U2 }6 x  Z! B
  75.        imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));    . y: i% q% G2 X6 N- @7 @% Y
  76.    
    ) q7 }( m! S3 w  S- q+ I" `
  77.        /*计算图片灰阶值*/   
    5 p6 Z+ g$ h2 Z2 E; W3 N0 t
  78.        $grayArray = array();   
    3 w4 w4 s7 G+ H$ C3 p
  79.        for ($y=0; $y<$delta; $y++){   
    . H0 i. ^, I( s: {
  80.            for ($x=0; $x<$delta; $x++){   
    0 [; o. s0 G2 i" y. k- [1 Z# E
  81.                $rgb = imagecolorat($img,$x,$y);    3 h5 A' l1 D; I
  82.                $col = imagecolorsforindex($img, $rgb);   
    0 t! [0 b. Y% F3 ]) T. Y- M% ~
  83.                $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;   
    . Y. S( \! V" J' Y2 O0 ?& y
  84.     , m9 ~$ G! [. A& R
  85.                $grayArray[] = $gray;    / g, _8 L' w& S" {7 h  U$ K
  86.            }   
    $ Z+ ~  A- n3 w/ B" a6 L7 H& F
  87.        }   
    % C; t7 p$ N! }: T: [
  88.        imagedestroy($img);   
    - s5 L5 }& A3 c1 g: `
  89.    
    ( s$ T6 O+ ~( m* F
  90.        /*计算所有像素的灰阶平均值*/    * |" L1 ~. M5 w$ a/ Z1 ]- x! w
  91.        $average = array_sum($grayArray)/count($grayArray);   
    ' z' H/ X7 C. q8 x( A1 f
  92.     9 R6 C1 ~( _2 k1 H* f+ ?6 g. q
  93.        /*计算 hash 值*/    " L! _. D9 W8 x! r1 b2 B
  94.        $hashStr = '';    / c5 D  p3 N5 {7 V8 L6 |
  95.        foreach ($grayArray as $gray){    1 E2 d5 S) Q( }8 v" K
  96.            $hashStr .= ($gray>=$average) ? '1' : '0';    : Y0 ], ?8 ~, {8 j7 J& n" O
  97.        }    % F( v# u% A6 @+ f$ `& R7 r4 {
  98.     # A: K- \. Z( \9 O; A9 B6 d# m
  99.        return $hashStr;    ( j! N  y% Q9 k. Q( P
  100.    }   
    4 v7 a; P5 P+ X$ G# E) G, ?
  101.     % ~6 [% l6 u0 @; P# l' r
  102.     . t0 y% u; n# f9 @4 {. x0 ?  R9 X
  103.    /**hash 图片文件   
    % O  ~" x+ B' F1 b/ [' u- G
  104.     * @param string $filePath 文件地址路径   % w5 z9 X( ?* Q9 [/ X( y2 H
  105.     * @return string 图片 hash 值,失败则是 false   2 f2 ]  I$ [; E! y. b$ ?* z
  106.     * */   
    8 S: H0 B, x( w; `. o
  107.    public static function hashImageFile($filePath){   
    ; h8 F# e: [" I" G/ s9 M1 x
  108.        $src = self::createImage($filePath);    2 B1 ]9 C3 h, }, x% t* X' O
  109.        $hashStr = self::hashImage($src);    / g& t# E' e2 r) ^
  110.        imagedestroy($src);    ) T& |* W: ?7 P4 {2 \
  111.    
    - k; k% j6 j: ?7 A9 V) M& W9 y* e
  112.        return $hashStr;    / ^' K9 k5 c/ Q+ _+ K2 P
  113.    }   
    . f5 s) ~# o" t7 b: z
  114.     + N$ Z# c, i' j3 R5 i9 T
  115.     + K, \7 `  k  n) X  |
  116.    /**比较两个 hash 值,是不是相似   0 z7 A9 f% U- l
  117.     * @param string $aHash A图片的 hash 值   4 o) M/ j3 w4 h- ~6 H! r
  118.     * @param string $bHash B图片的 hash 值   & i$ q8 ?# _/ L! `4 z: F+ k  p
  119.     * @return bool 当图片相似则传递 true,否则是 false   
    ! Q! J- ]/ s- V% C
  120.     * */   
    8 R, p% u4 c4 ]
  121.    public static function isHashSimilar($aHash, $bHash){   
    ! P$ c' E/ h" p* C7 \
  122.        $aL = strlen($aHash); $bL = strlen($bHash);   
    ; Z2 |5 ~" {# P( C1 w: R' P
  123.        if ($aL !== $bL){ return false; }   
    & T, b, K9 i9 ?, i" Q* ~$ U0 ^: Z  h" o
  124.    
    0 Y% a( }# }1 n
  125.        /*计算容许落差的数量*/    # O( e. r8 |+ \0 y3 p
  126.        $allowGap = $aL*(100-self::$similarity)/100;    0 k+ s& G) Y/ @. V9 L0 g5 S7 W
  127.     ! q0 C( v) s5 q3 t8 c/ A+ U% ~4 M  z
  128.        /*计算两个 hash 值的汉明距离*/    ) Z) w- m7 X* ]
  129.        $distance = 0;    " X6 h6 h/ Y3 O# }
  130.        for($i=0; $i<$aL; $i++){   
    4 [; f8 R; B) u0 ~% z
  131.            if ($aHash{$i} !== $bHash{$i}){ $distance++; }    / q) U( z& G5 X  {, K0 o5 z+ u
  132.        }    / R5 z; O+ @0 ]/ M" Y! c4 q
  133.    
    & X! _8 Z; h8 o
  134.        return ($distance<=$allowGap) ? true : false;    $ }4 V* r0 p# ^# l: a
  135.    }   
    0 V: _2 B' x) b$ f- ^
  136.    
    $ X4 N- l; S" Z) E$ j2 V9 l
  137.    
    - w5 ]: ?6 h3 e  P
  138.    /**比较两个图片文件,是不是相似   
    0 j4 W4 l8 E7 b) p0 t
  139.     * @param string $aHash A图片的路径   8 Q1 n' r. r( q  @* @3 C; ]
  140.     * @param string $bHash B图片的路径   
    1 I1 h& {; B( |8 e- x6 W# ~
  141.     * @return bool 当图片相似则传递 true,否则是 false   , p$ `7 z- U, _; C# x5 M1 {
  142.     * */   
    : v, |$ B' L. Z! q
  143.    public static function isImageFileSimilar($aPath, $bPath){   
    % m4 a% b  A* U" e. \' r) [5 h
  144.        $aHash = ImageHash::hashImageFile($aPath);   
    9 m  N( c0 b3 M
  145.        $bHash = ImageHash::hashImageFile($bPath);   
    9 @# N6 h- |1 s3 ]3 `. X
  146.        return ImageHash::isHashSimilar($aHash, $bHash);   
    . |; u9 W8 @. Q1 |4 ~% U$ Q
  147.    }   
    # T  U/ ^8 a4 s5 _- M
  148.    
    : Q- L6 X$ U9 w1 @* a
  149. }
    # ?" a1 i; j0 H! {
复制代码

  l9 t$ t8 {5 Z) B4 p+ i1 d$ Y& [6 G# L) s, l
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-20 00:32 , Processed in 0.057473 second(s), 19 queries .

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