管理员
论坛积分
分
威望 点
贡献值 个
金币 枚
|
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图: G, ]6 C; B% s( `9 J3 W
" H1 t9 j! i7 f' R
# S9 G. m9 O+ x7 X1 y由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
9 K3 A! K8 o8 n9 N# l9 D- <?php % L& d% d$ C9 M, \
- /**
1 s' R& _2 S9 X5 v9 p2 X6 e - * 图片相似度比较
& n0 z) r$ f: I) g - * - a1 ~' t' w" [. H) Q+ T3 Y
- * @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp; ( u L: k1 N y5 h, q% ]) @( \/ T
- * @author jax.hu , F# _5 W4 p% _
- *
( j5 Y' s2 c3 t0 m1 } - * <code>
7 T, p9 u3 q4 x2 G2 x0 v - * //Sample_1 ' g7 i1 S8 I( [
- * $aHash = ImageHash::hashImageFile('wsz.11.jpg'); 8 H& X' Q. }7 D( P& G
- * $bHash = ImageHash::hashImageFile('wsz.12.jpg'); # P6 d ~" X: p6 G4 P; K
- * var_dump(ImageHash::isHashSimilar($aHash, $bHash));
4 f7 b0 U8 ~: Q8 r+ h. R - * 8 f1 Y* M& W* }+ [ S# `/ h
- * //Sample_2
) L9 s4 Z+ x9 n9 y5 p) y - * var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg')); 8 d+ n9 y2 ^+ R9 [# f" f2 X2 z
- * </code>
/ J5 q: ^! l6 U4 g3 x - */ 6 [! ]( P4 ]9 S9 I' W
-
& q- Y* C8 d9 } - class ImageHash { 8 K+ }1 @ O0 _/ h+ M
-
* x8 a/ W) Q& T- p7 { - /**取样倍率 1~10
) r/ v6 @ W0 R5 n8 } - * @access public 9 B9 i, h, q, e0 Q
- * @staticvar int
6 o0 ?- r$ x% B4 O0 { - * */ # ^$ A/ ~! [( M9 o( [0 g: N
- public static $rate = 2;
3 A2 ?7 o2 A" W - 4 H6 V. |/ y w" }- s; L( q
- /**相似度允许值 0~64 ) F0 z+ Y, ~- m
- * @access public
) J1 d; D: J% I7 r9 @) Q7 S( l - * @staticvar int
) m% y4 e Y$ \! `* s5 o, S - * */
3 U& p$ L$ q( V - public static $similarity = 80; 2 `, F, h/ M6 a
- ; O2 q4 N# u/ ]+ [/ p, @) m
- /**图片类型对应的开启函数 6 ]! [% {2 t1 o
- * @access private ' Y3 B3 Q1 L4 _7 g- W6 }3 _
- * @staticvar string , l/ t3 n# M/ i. B
- * */ ! e+ l2 L) q, ?
- private static $_createFunc = array(
; b) P' l# ^$ N7 C/ m4 l - IMAGETYPE_GIF =>'imageCreateFromGIF', ! B, Q, G N: O2 ~
- IMAGETYPE_JPEG =>'imageCreateFromJPEG', 1 c# Q# v g+ m! f3 m, g
- IMAGETYPE_PNG =>'imageCreateFromPNG', - k4 a: I7 B4 K1 V9 u
- IMAGETYPE_BMP =>'imageCreateFromBMP',
5 H! i$ S& \: N) n8 t2 ]/ U - IMAGETYPE_WBMP =>'imageCreateFromWBMP',
* s* S. U% D3 D2 g- B; c$ E: {( u - IMAGETYPE_XBM =>'imageCreateFromXBM',
7 n$ w. n' V3 ]. @) k - ); : X8 E$ M6 Q5 R4 b$ K
- ! c" m' @1 [: {% A- f
- / r9 t$ M- Y0 S) k' d4 c& I" ~) D
- /**从文件建立图片 : d `. o. g# p3 b& c3 H. f: U
- * @param string $filePath 文件地址路径
" O! @- G/ u) O0 q5 c - * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false R7 |# N% [9 j' E1 z3 f/ d
- * */
Y! `! D2 r" N - public static function createImage($filePath){
( r& Y3 I5 Z! i) Q/ l9 @ - if(!file_exists($filePath)){ return false; }
f+ E) }, T, F) F -
; Q8 c$ W* Q/ L' c) k! I* e - /*判断文件类型是否可以开启*/
9 G. j" q, E8 P' x - $type = exif_imagetype($filePath);
) \# c! v/ U& z" p - if(!array_key_exists($type,self::$_createFunc)){ return false; }
( Y) C8 ?4 Z$ ~4 V2 F# c2 l -
8 u5 |. t' v$ J: u; h7 ] - $func = self::$_createFunc[$type]; + I" N! v; [- \/ R. ? K" ^
- if(!function_exists($func)){ return false; }
4 V2 p3 O2 E- Q) V -
, Q, N+ V# l, q$ {! F2 f r* \ - return $func($filePath);
- P+ k* A' d- _+ |7 |1 G - }
* S- q! N' }8 g -
# M3 e+ v1 H3 a+ u: o5 a - 1 Q8 {) P8 U8 j6 j# o
- /**hash 图片
x4 [ a9 \0 i4 s2 L# i( n - * @param resource $src 图片 resource ID 3 l' B0 [6 Q5 Q- `4 _7 x) C
- * @return string 图片 hash 值,失败则是 false 8 |" t/ I2 f& F, @
- * */
9 Z9 J, r e; \* n% ` - public static function hashImage($src){
5 N) [; H v6 r1 m' I. N - if(!$src){ return false; } $ x% A' P& J2 e" C6 }/ @
-
. Z$ ]0 x) g! B' w1 J- A- Q - /*缩小图片尺寸*/ / W: j- p( O0 W9 Q) r7 G
- $delta = 8 * self::$rate; # F8 ?! Y3 u( z
- $img = imageCreateTrueColor($delta,$delta); : k, R7 F2 r1 F, h
- imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
! \% S- ?4 u' {7 o! \& O# V - " J, r" w7 q; |+ P# ]& p' v
- /*计算图片灰阶值*/
% ^( h( p' F" x/ ~3 l+ ^: u$ w1 n5 S - $grayArray = array(); 8 z2 x7 p4 s- A! L1 {0 V! a+ z
- for ($y=0; $y<$delta; $y++){
0 ~2 m8 ^; f* G* r - for ($x=0; $x<$delta; $x++){ ! K. \. @9 ]) y/ b" v# i
- $rgb = imagecolorat($img,$x,$y);
) v# y2 @ H9 k1 ^; w) W - $col = imagecolorsforindex($img, $rgb);
3 D5 {8 y. h" r, k5 f, E6 E" W - $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF; ! t5 F* l6 Y( ]3 D0 `7 K7 O: f# x5 n
- 4 D9 r# Q: ?3 Q3 b. Y6 t
- $grayArray[] = $gray;
& G) U* F5 E u( D4 z, y - }
1 R5 d: P9 \% V8 y - } 8 p1 _4 ]& R( k6 l |4 d- @1 \
- imagedestroy($img); 0 ^& [* ?, s* V+ h' p: Z6 w7 U" Z
-
3 F5 S1 A( _; ~% [3 v3 Y - /*计算所有像素的灰阶平均值*/ & K% i) A2 j* O. ]) x- J
- $average = array_sum($grayArray)/count($grayArray); 3 K( k' K" @ f
- 4 c3 v% n( N! W# b) ?' @. ]
- /*计算 hash 值*/
, i# J$ `1 S/ L0 I- X - $hashStr = ''; 5 g0 a) r& _9 o; S- c) Z2 N- [
- foreach ($grayArray as $gray){
# M% R7 l) l% M1 q1 z8 w& C% w - $hashStr .= ($gray>=$average) ? '1' : '0'; ' m6 m8 O+ K- Q( z% v! a
- } 5 ? ~/ N' ^# d. }
-
; G$ R! L0 f$ k0 O) Z - return $hashStr;
. ~3 W; D) l* F b3 L: `& b - } ! R% S! b$ d9 v
-
+ K) \! e2 F" Y# N& K( P - 0 K Q: S0 z/ X
- /**hash 图片文件 4 F. u. l0 W: i
- * @param string $filePath 文件地址路径
3 B+ H9 H% P& z( i5 Z - * @return string 图片 hash 值,失败则是 false ! B3 c3 _& S3 L# W+ m/ }# b8 b
- * */
1 W8 U! x+ ], L$ }+ w3 V: Z. Z - public static function hashImageFile($filePath){
$ V" h9 R7 o- _* y$ u7 R' k - $src = self::createImage($filePath); " o$ L. ~6 E3 o( G) f( {) {
- $hashStr = self::hashImage($src); ! ~0 K% p& b! y3 T9 w" y) j7 x
- imagedestroy($src);
5 {) h- J8 ]6 e, r0 g - + Y7 R% G& o6 d
- return $hashStr; n( `) I$ l2 n$ r
- } - d/ k+ l; `0 C% T, \" p* O
-
( w% R1 G5 O: G. h& F2 @ - & q+ |/ m% Z, H: N. Q0 x/ `) X0 e
- /**比较两个 hash 值,是不是相似 ' C, T8 ^2 N$ {* U* u3 m2 l+ U
- * @param string $aHash A图片的 hash 值 ( Q* \" H% D" T( `
- * @param string $bHash B图片的 hash 值 * T! f# I/ n0 o) Z3 C/ y2 ? ^3 r
- * @return bool 当图片相似则传递 true,否则是 false , ^" O+ ~. m3 U+ ]6 d0 C/ P* J( i
- * */ 6 l- F' ]7 F( T% h
- public static function isHashSimilar($aHash, $bHash){ + b/ i3 t: B- l" ^
- $aL = strlen($aHash); $bL = strlen($bHash); - \/ b$ x ^1 X( K0 r/ X
- if ($aL !== $bL){ return false; } " A% h: P, M6 A2 L0 j
- 5 O* e4 P$ d B. S+ Y6 v
- /*计算容许落差的数量*/
# ~& Q) _0 u! {# i4 Q - $allowGap = $aL*(100-self::$similarity)/100; / {! o/ C. N3 U/ E9 n; |
- $ a+ d$ J) w* m
- /*计算两个 hash 值的汉明距离*/ 2 Z# |! ?, a: m0 p5 ]! @
- $distance = 0;
) o% z; Y1 F' C9 f' S) j - for($i=0; $i<$aL; $i++){ ; K2 g) Q" W2 d; Z0 n1 M; }+ u7 T
- if ($aHash{$i} !== $bHash{$i}){ $distance++; }
) w7 a! o- y$ R& t - } / u# |) a$ M& j; F! r2 {$ K
-
4 }4 D) O! Q- V: G" a - return ($distance<=$allowGap) ? true : false; 8 \& V& g, j3 F) [, H" [
- }
7 Y0 l# P0 H$ S9 c! K: O" S* i -
! z8 u5 v9 {4 e9 Y - 2 [7 r8 I, I( h
- /**比较两个图片文件,是不是相似
! X8 J- p7 q f - * @param string $aHash A图片的路径 3 r# Q& H- |1 K1 i1 C3 a2 Z
- * @param string $bHash B图片的路径
. J! C- b; K/ \6 ` - * @return bool 当图片相似则传递 true,否则是 false
7 H5 E9 p6 t# T9 r - * */ 6 s3 u, o. f5 u* G9 C$ i9 T
- public static function isImageFileSimilar($aPath, $bPath){ U7 A# ]- u' x' ?/ z, k
- $aHash = ImageHash::hashImageFile($aPath); - k f; x1 j) h% Y9 E. H
- $bHash = ImageHash::hashImageFile($bPath); U' `' s; I- w0 ?8 d+ N; s
- return ImageHash::isHashSimilar($aHash, $bHash);
" h2 r8 x5 |) N+ c - }
5 x+ m7 O' ], |3 P - 4 y6 P& t& [8 r* q4 A
- }' |5 {" y: B# u2 _) i6 h7 w
复制代码
/ c" F" v- m9 _; j2 B8 T7 V: M! q4 j1 e
|
|