管理员
   
论坛积分
分
威望 点
贡献值 个
金币 枚
|
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
. e2 |& m6 P, f# h& Z1 i% F+ }! Q2 D/ U9 X: s! P4 W' c: V
% ]1 C5 }' i+ {
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
$ D" D, U6 I6 p' v5 I- <?php 2 b, X9 B( p! V3 V' m, j
- /**
, a- w! n. ^ Y7 G - * 图片相似度比较
! [. S, @0 J8 i - * 7 R; Q4 P! S! @5 e3 Y
- * @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp; ) L( d' Q8 C$ G' J [
- * @author jax.hu
8 Z4 U3 c$ ` z/ j! Y/ W% h, ] - * 6 g+ P; C2 d: T% }5 E! Z" u
- * <code>
; X4 m3 T: M3 [7 ]; a& b - * //Sample_1
6 L' N: b: l3 x* u/ @( s4 D - * $aHash = ImageHash::hashImageFile('wsz.11.jpg');
3 t3 P. D: g& T7 ]) c- J0 I! m - * $bHash = ImageHash::hashImageFile('wsz.12.jpg');
. ^7 N4 z7 w' L% W4 C - * var_dump(ImageHash::isHashSimilar($aHash, $bHash));
! K1 p: F" Y6 g8 s d' ` - * # c- s9 M! k% z, i; ]" Q
- * //Sample_2
1 u- C5 z; r9 M3 @7 q' a7 [ - * var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
0 I' A( \) e7 ~# l1 @# R - * </code>
! g5 |) |& V! d5 n, j+ b4 q - */ $ l1 a" O7 q, w
-
" m" ^7 W7 W& Z% V" U) y6 k% Y1 F - class ImageHash { / x3 a t7 _& p' u) y
-
9 ~# q- `6 A/ c5 W$ ?1 K4 O' j - /**取样倍率 1~10
9 _$ o9 `1 y9 z - * @access public
% C6 X2 }# y I' Q' O - * @staticvar int
j* U2 i4 f5 z: J! i - * */
% g$ U. X- p' l& S$ x& P4 O - public static $rate = 2; " n$ R" n; l5 m+ d }9 h$ j
- ) f6 s7 S; ], U o
- /**相似度允许值 0~64 " m" U9 ~+ c% V7 N$ h, b
- * @access public
4 N, D& R/ [$ V8 w6 K9 m$ r - * @staticvar int
& M; a0 @$ `( u7 v% Y k1 M/ Z - * */ . X& M: T1 e+ {$ a4 [% Y7 G8 a
- public static $similarity = 80; , M8 B j3 h) q
-
1 V0 T9 e. K) z& ?) r- ~ - /**图片类型对应的开启函数 1 y2 f# j w2 H. w
- * @access private
& _; c6 \4 |) {1 i- B - * @staticvar string ! G' [1 E4 m4 y. E2 M
- * */
8 _$ y: ?/ F) m - private static $_createFunc = array( * ^0 Z1 a& I% e8 y# |4 f
- IMAGETYPE_GIF =>'imageCreateFromGIF', ; _9 F6 T r: l6 r! v6 ^$ o
- IMAGETYPE_JPEG =>'imageCreateFromJPEG',
/ G1 o% t4 x$ x, m% Z( [ - IMAGETYPE_PNG =>'imageCreateFromPNG', 9 l3 u; T8 x. E. d8 u* D- E
- IMAGETYPE_BMP =>'imageCreateFromBMP', ( l3 j! [: ?( ^% e, X% T
- IMAGETYPE_WBMP =>'imageCreateFromWBMP',
/ Z( v, | a" K3 _ - IMAGETYPE_XBM =>'imageCreateFromXBM',
; [: Q' V2 q! m2 B - );
3 q, e6 f8 q: L$ X* L) | -
9 S8 J% ^( w' Q2 H j' Z( w -
5 a$ b9 z1 N7 w R0 H( S7 J# H& k: ? - /**从文件建立图片 . V1 ~4 c' {% }0 b* x1 \' O0 u
- * @param string $filePath 文件地址路径
! G6 Y2 m. o7 l U% ? - * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false ) u5 Y( B+ ^9 ^4 P
- * */ ! Y5 |( `2 n+ Z9 b5 k" s! W/ v
- public static function createImage($filePath){ " o+ w5 l7 |( F5 o2 \
- if(!file_exists($filePath)){ return false; } 0 E" j" {5 T" B! M
- ) z/ D- l1 S7 b4 k9 A
- /*判断文件类型是否可以开启*/ . T. I4 e" h" D! R: W% z W
- $type = exif_imagetype($filePath); 1 F# r/ D- t, s5 X
- if(!array_key_exists($type,self::$_createFunc)){ return false; } 7 k/ q* e9 m" H1 r( N9 C+ o
- 6 V2 T3 G' K% r7 ?
- $func = self::$_createFunc[$type];
3 v2 z& t. F- ^5 Q4 w - if(!function_exists($func)){ return false; }
" Q! I" m1 U0 I2 D7 N - $ O% @! y1 _+ L: N
- return $func($filePath); 8 y0 V8 u0 a* {/ |
- } * b- F6 N/ w, h
- 4 Y0 Z1 h. u3 N y& G
-
8 M7 a/ F1 q. h) C* p- | - /**hash 图片
^& T4 n( R# s$ m5 J. W% g - * @param resource $src 图片 resource ID " u/ Q3 t# L9 F2 }% \0 g
- * @return string 图片 hash 值,失败则是 false 7 O) y9 Y- g1 s( E
- * */
+ c9 _. H3 e" N% ~0 z - public static function hashImage($src){
* @5 Y% E$ J% m+ ]+ ]* H - if(!$src){ return false; }
! W( a( I" ^) W: F - % s6 ?) r% h7 ?8 l9 ~
- /*缩小图片尺寸*/
, R9 J; E% r T* w5 F. o: n - $delta = 8 * self::$rate;
1 e2 @, W5 [: c: _* n/ i4 A% q - $img = imageCreateTrueColor($delta,$delta);
- s/ p( g4 X5 s - imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src)); 2 W1 S1 y5 c% t
-
~4 {* M& |" |# T9 d - /*计算图片灰阶值*/
, g2 n& [& F2 x8 K# X - $grayArray = array(); ( U" q. C7 b3 ]) u# t4 t
- for ($y=0; $y<$delta; $y++){
# w1 x6 W% s2 o4 f. \6 f& n - for ($x=0; $x<$delta; $x++){ - `/ h+ J! |* d% `
- $rgb = imagecolorat($img,$x,$y);
% ]! o& W$ K% d, ?+ t- \7 w - $col = imagecolorsforindex($img, $rgb);
: n( F7 U. n; S5 I, {8 C: J - $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
! p$ T# o% P4 ~ -
9 _- z+ X( j: z6 `& T' _" J$ t8 i - $grayArray[] = $gray; % @, F# R: S4 H1 V- I9 t
- } 4 H. A& b% E. l: Z2 K+ Z" z) @
- }
1 P0 I# x) W x9 K. n1 D$ g - imagedestroy($img);
d" y3 f6 _" s, \9 d, O u -
2 S/ U- N) @, L) M2 G6 a; }4 n8 k - /*计算所有像素的灰阶平均值*/
' L+ k" l! ~* n' ?* }; a8 [% { - $average = array_sum($grayArray)/count($grayArray); $ a8 R/ E1 R3 T, @+ N
-
# `- O6 Q0 P+ `' Z - /*计算 hash 值*/ 4 g9 f/ i! K/ o* L& a" S$ w
- $hashStr = '';
8 X, v+ `2 m3 V3 z3 t# E$ O! O) t( k - foreach ($grayArray as $gray){ 1 W- t) U+ p* E7 C" o% ?
- $hashStr .= ($gray>=$average) ? '1' : '0';
" `! [& h6 ]% n6 F - } & T4 M# [. U: b2 {
-
7 e5 |1 n* E1 j2 }+ X - return $hashStr;
, M5 ]* w" @; K, n8 S6 ] - }
9 ]/ T. F( q9 G -
/ g3 C1 V& o* _ -
% n0 S9 u6 I) d$ t" k - /**hash 图片文件 : n. v/ m) W: @& r5 L
- * @param string $filePath 文件地址路径 $ s' m0 D2 x9 E1 Z+ g* w, j
- * @return string 图片 hash 值,失败则是 false ( Q- n0 I: I4 q" Q' a* ]
- * */
: n* { O3 H$ f- U& {! t - public static function hashImageFile($filePath){ $ R/ ]' C, x7 E5 J
- $src = self::createImage($filePath);
* f' e& S+ p. t$ ` - $hashStr = self::hashImage($src); ) o" Y1 S% t& R$ A! G( e
- imagedestroy($src); ! p! Y8 D- C/ e) H+ o% Z/ e
-
( K, E- r4 h# S Y - return $hashStr; ' J l& h4 G; g" B
- } 4 C, K, ^# Z: r# C# m* u4 @$ E
- + G5 x" D) c6 ~. W4 b
- 0 J6 W& J- y f( B) N6 z
- /**比较两个 hash 值,是不是相似 + r2 A8 W% U& c+ F6 H
- * @param string $aHash A图片的 hash 值
; i B% h) p2 U q4 m8 D' e T0 s - * @param string $bHash B图片的 hash 值 8 u) K ~$ \5 D8 F( ~% N
- * @return bool 当图片相似则传递 true,否则是 false . F1 I0 U' ~; M
- * */ ( h3 ?6 K6 m% ]
- public static function isHashSimilar($aHash, $bHash){
w! m. N2 n7 T/ U! \5 G - $aL = strlen($aHash); $bL = strlen($bHash);
" Q8 d+ ~7 D; u7 R - if ($aL !== $bL){ return false; } 3 \' B9 u; s# d( T3 @- N
- 0 G m! {4 k" v( b9 J% r
- /*计算容许落差的数量*/
% p" `0 Z! Q( F0 C7 o - $allowGap = $aL*(100-self::$similarity)/100;
, }( n4 d6 W8 {0 E- e0 v* R - 1 j- D7 M0 v% U9 W. Z* u/ @3 t
- /*计算两个 hash 值的汉明距离*/
* {( G# r) \+ y4 k. y( Z - $distance = 0;
; [/ Q( k6 v2 B5 i) { - for($i=0; $i<$aL; $i++){
- D3 I* P* N' |, `+ V, V! [& ?1 I - if ($aHash{$i} !== $bHash{$i}){ $distance++; } % N5 ]4 M8 W1 S; C- u
- }
- L# U5 x& S* C) v. x y* b2 C - 3 [) }6 V, `$ c. l5 V- I
- return ($distance<=$allowGap) ? true : false;
# b7 }9 Y( W5 p - }
' s/ |, z% e% L; O$ f% L! x - " A5 m' V6 y2 ]: V
-
; ^" d' |( x: z$ x. E, L1 i - /**比较两个图片文件,是不是相似 + p& F T2 X- U6 E. ^9 e8 V
- * @param string $aHash A图片的路径
. B9 D2 K/ v# v4 B% n0 z - * @param string $bHash B图片的路径 ' |% l- e0 J& ]% i/ m, o A3 d2 d- W
- * @return bool 当图片相似则传递 true,否则是 false ) M* p# y4 ]1 y3 x0 \, x
- * */ 5 j; B3 O+ w$ E, L& e/ u4 s
- public static function isImageFileSimilar($aPath, $bPath){
+ N! s% J! U: T: F2 J - $aHash = ImageHash::hashImageFile($aPath);
) A. L3 k! W, i w: p - $bHash = ImageHash::hashImageFile($bPath); 7 M: A6 z0 p/ q% I6 H
- return ImageHash::isHashSimilar($aHash, $bHash); ; W. ?% [# ]4 }
- } ! _: C, L0 b: `/ E
-
% g3 G9 [9 M2 k: H2 O) q - }9 q4 Z) ]4 O7 E
复制代码
3 ]6 k" J/ |0 p) A* U. w* b. W0 K! D& a; ?
|
|