管理员
   
论坛积分
分
威望 点
贡献值 个
金币 枚
|
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
f! T* C! e8 W8 c. M- h+ ^, ^! Q. o* G! _* k, Y' K
" B' `9 L* M- N5 _, g由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。( T' \+ s* b, E( k7 y" D
- <?php
8 G* k6 r0 A! _ - /**
' ?; u. c3 I4 A; ^3 I; M* F - * 图片相似度比较
/ v9 L W$ x9 q9 c* l - * ) \( d' }, r0 T3 a& O: ?- [
- * @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
5 v0 H O, G' v0 J - * @author jax.hu ) j- d2 J, i* A
- * & W- F+ u8 @( a2 u$ H/ ]4 m' Y$ Q
- * <code> 6 k9 Z( n z: F
- * //Sample_1
5 d* m0 Q. P4 } - * $aHash = ImageHash::hashImageFile('wsz.11.jpg'); - O/ V2 s/ t; C( E9 W0 l% X
- * $bHash = ImageHash::hashImageFile('wsz.12.jpg');
/ ]% H: q; n% g/ E. w. h } - * var_dump(ImageHash::isHashSimilar($aHash, $bHash));
7 s4 r" n& ^- t Y$ {; l1 k - * ) q6 j2 p0 M5 `9 o
- * //Sample_2 6 J$ \# [3 p. T. i
- * var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
9 z! Z" E( T! b! E - * </code> 3 N6 R6 w& W+ z5 C8 F
- */ 9 J5 g5 b& G/ @3 Y
- ( F7 ~% j, w u% E0 R7 m
- class ImageHash {
6 _( u, d9 c4 v3 ~ -
4 D6 g( L% l i# ]' {/ Q - /**取样倍率 1~10 2 _9 ]! o+ C0 {/ z" ?
- * @access public $ R# A P, n' x& i$ M8 I1 f
- * @staticvar int
$ V/ ~1 |/ W! j5 q+ }; v - * */
S3 \0 `, ]; z - public static $rate = 2; 1 h' ^3 `1 _8 \( c& C" p5 O g( V
- - ^+ }5 V8 \" l i! n) H+ ?0 A: j
- /**相似度允许值 0~64
+ g+ ^: L$ e& V0 u# Z - * @access public
6 ]6 I- r; h; _/ X' N - * @staticvar int
4 ?6 `9 G5 |: i/ u1 D. C - * */ 2 a3 }0 k2 r4 O, c8 j
- public static $similarity = 80;
" x m" S9 H j5 M# ]8 e. B - 1 `( q" {5 J. j7 M
- /**图片类型对应的开启函数 ) T0 ~, l! T5 k1 `7 _
- * @access private + u( F" A- X8 _& P l Y
- * @staticvar string : P* e0 h# F4 w% V- |% L, Q
- * */
0 e) s4 a) k2 _' ]: [+ p" | - private static $_createFunc = array( / Q& J( ^7 C* i% g' h$ j% r
- IMAGETYPE_GIF =>'imageCreateFromGIF', G; G' i) o) U7 q$ t
- IMAGETYPE_JPEG =>'imageCreateFromJPEG',
* p2 j6 y! `6 L! x, ? - IMAGETYPE_PNG =>'imageCreateFromPNG', - r1 e X% x: q/ d. r
- IMAGETYPE_BMP =>'imageCreateFromBMP',
$ x* ^2 X% _% H1 _9 S8 R" X1 ? - IMAGETYPE_WBMP =>'imageCreateFromWBMP',
" h( d: C3 \: ]6 j3 \+ w - IMAGETYPE_XBM =>'imageCreateFromXBM', - J/ j' b$ Y: h A0 k
- ); $ c9 f* z$ r2 v p
- - A+ D9 g [7 e) w8 l6 f+ l4 I& i
-
& y2 i0 X/ A$ J8 k# n - /**从文件建立图片 ' z, L* g/ t+ e% M7 q/ }/ d
- * @param string $filePath 文件地址路径 0 o9 K" S" ~9 H; H, Y% Z: A
- * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
0 p3 K9 l' k) {7 g3 C+ E0 F - * */ $ S# g9 y. a5 F; F2 f' t. J1 h
- public static function createImage($filePath){
9 U7 W, V8 t) }; s! z5 c - if(!file_exists($filePath)){ return false; }
- Q1 O! [! S" F -
5 T& n8 K: Q) ?8 ~8 ?" j - /*判断文件类型是否可以开启*/
: D$ K; i l/ y. ` - $type = exif_imagetype($filePath);
3 G* ^' r9 L0 _ - if(!array_key_exists($type,self::$_createFunc)){ return false; } 9 g, A$ M0 ]6 N% Q" X
-
1 n- G) V: Y2 t - $func = self::$_createFunc[$type];
$ S0 o8 ?& ~) x0 m0 ` - if(!function_exists($func)){ return false; } . u5 N' ^8 g) G% n
- - l, f1 R/ m1 T8 p
- return $func($filePath);
* d6 t F" h9 W2 g7 R6 z" |0 a - } : I+ I: W# Y% N
- 8 L' }) i3 I( ~) i, h( N8 p. T
- * f; H. I- b" L# J1 W3 w
- /**hash 图片
) k4 K" j" S. V! E6 o/ r - * @param resource $src 图片 resource ID 2 d& @" w) L- Q& `1 |
- * @return string 图片 hash 值,失败则是 false
8 f; M( t+ T. _ n - * */
6 F1 T- G6 Y: D" d: q - public static function hashImage($src){
; g/ c+ G) X1 d. A4 ~4 k( [# f - if(!$src){ return false; } J) N7 Y& n, A3 K. y/ m9 Z' P! B
-
& P3 J; e X2 p - /*缩小图片尺寸*/ , j! x/ Q6 H0 G& l
- $delta = 8 * self::$rate;
0 w5 {2 Z6 }: O+ e! G0 _: W - $img = imageCreateTrueColor($delta,$delta);
, p" v9 G$ Z5 p! O, j; d& k - imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src)); " V3 J; W% K' w6 m9 d
- 8 a( P6 s( r' a& \9 ~8 f
- /*计算图片灰阶值*/
5 r+ a' \ U, p* _2 v6 `1 Y( P - $grayArray = array();
8 V2 C4 w. r& O: s5 `% h - for ($y=0; $y<$delta; $y++){
0 B8 S- f+ q; n - for ($x=0; $x<$delta; $x++){ % E7 _+ k" V2 H3 z
- $rgb = imagecolorat($img,$x,$y);
) o( z, k1 x5 b* x - $col = imagecolorsforindex($img, $rgb);
9 m8 [ x5 G, w5 h$ @ Q& Y( Y - $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
) i6 a O- A' U! I5 K' X -
/ {' e4 x0 J4 S! A: X1 p4 c - $grayArray[] = $gray; + ^% H! u& `8 e3 i) t
- } . \2 V% J5 z5 j! K+ A1 ^
- }
- o4 N% Q$ N9 T* \ M - imagedestroy($img); . u3 X+ m0 }9 ^6 C5 R
-
# p% c9 c( e! U' m o) N - /*计算所有像素的灰阶平均值*/
8 p3 e4 g: v: m; Z! e9 I9 V7 F - $average = array_sum($grayArray)/count($grayArray);
5 U& i' I* M- z1 D& T# i! [ - 4 b F* P+ Y. p
- /*计算 hash 值*/
( v; _! h' K3 e( Z - $hashStr = ''; 7 Z# E9 H3 \& Z, K
- foreach ($grayArray as $gray){
/ d1 U; H# k8 T9 B$ U - $hashStr .= ($gray>=$average) ? '1' : '0'; 7 ]' r$ J7 j2 G6 \# w# o
- } 1 d9 _$ {# x) h' z9 c6 Y
- & d* o% ?# P8 E2 Z! c
- return $hashStr;
3 F, N0 k( z9 k0 N- ^* K6 [. h - }
4 v2 b. L' J4 J: C3 K/ a+ ~# t - ( U2 s. Q0 y" Y: S4 n
-
' j) a ~$ x2 C% C( ?0 j9 P$ E - /**hash 图片文件
1 C. Y7 c+ @+ ^* C, a# o" P1 \ - * @param string $filePath 文件地址路径
% B0 j# s, V' I z5 b$ j& e1 h3 r - * @return string 图片 hash 值,失败则是 false
3 u* l: k$ n. ]! q+ {. k - * */ U2 ?; r5 m8 ^- w; T* C
- public static function hashImageFile($filePath){ % T! u4 l! \& C8 x, @. p
- $src = self::createImage($filePath);
: f) K; W- {) P& g! ?) \4 |9 z - $hashStr = self::hashImage($src);
, |* j: F0 U" \0 u - imagedestroy($src);
$ d) K6 h: g% W* ~# D - 8 R% h$ c; ^, e; K4 X* p, x& M
- return $hashStr;
$ H S& W: _6 K9 Y& ]! ~ - }
! P$ S1 U# P( c! x% h - & _5 a! O( n/ |( w& u
- f, m2 n* p8 E( t
- /**比较两个 hash 值,是不是相似 * C" h, x+ m7 C1 L& {/ \4 ^! k
- * @param string $aHash A图片的 hash 值 - y( H" o$ f" Y* Z- H( Q
- * @param string $bHash B图片的 hash 值 - o @/ A1 I" v* L5 J" u
- * @return bool 当图片相似则传递 true,否则是 false
2 K b5 }5 m G: y7 O6 |) V - * */ + I! M5 X! q8 v7 Q) | m" `. R
- public static function isHashSimilar($aHash, $bHash){
- k" I8 f4 q+ t# w - $aL = strlen($aHash); $bL = strlen($bHash); $ w, O! @2 b* r. a* v. Z3 n' g
- if ($aL !== $bL){ return false; } 8 F3 B$ } V1 {/ L5 u6 t% z
-
- X4 V7 O9 f# R7 [: f% p - /*计算容许落差的数量*/
, G( f+ T4 R. |/ \/ j - $allowGap = $aL*(100-self::$similarity)/100;
$ N4 K% s' q% s0 y - 8 A+ ~4 \* ~ e2 k
- /*计算两个 hash 值的汉明距离*/
( j/ |! _/ D( S3 d - $distance = 0; ! i3 |+ c" l7 a1 I1 \, l! U' t
- for($i=0; $i<$aL; $i++){ ( G" k: E( @; ^6 [
- if ($aHash{$i} !== $bHash{$i}){ $distance++; } 7 R( v/ Z! X, o3 z
- }
4 l/ p; f7 o+ O! K. \: i; ^ F -
: w9 y, ?* y1 U) U/ L. h5 q: G - return ($distance<=$allowGap) ? true : false;
) j( E% u" ^8 e) Q+ {. K - } - x. }/ Y5 @. \& [2 o; m
-
! q* q+ ]) K2 \6 W5 r5 L( Z6 x1 } -
4 t0 A) G6 I) f) a - /**比较两个图片文件,是不是相似
& h7 C+ t) u1 F: i4 s/ F - * @param string $aHash A图片的路径
% ?1 `' B$ R7 v9 R, _! w - * @param string $bHash B图片的路径 9 C$ t" Z1 F) g- q- o% v/ s
- * @return bool 当图片相似则传递 true,否则是 false $ ~, x/ `5 P( F# _2 A% z
- * */ $ j; `9 T5 c& k3 ~: Y" d
- public static function isImageFileSimilar($aPath, $bPath){ ; \8 Y% `' W/ J [% ~
- $aHash = ImageHash::hashImageFile($aPath);
7 U: d/ `; o: B+ E, i - $bHash = ImageHash::hashImageFile($bPath);
6 B9 y, l- F9 U! ?* R1 L - return ImageHash::isHashSimilar($aHash, $bHash); . G2 p3 ?( Z1 ?7 Y) ?" M
- } ' g, {( ?) I; P3 G
- * S9 b7 Z8 n9 o! ^% ]
- }* B' B) F& l* L9 _7 L0 J( e
复制代码 1 q- c: G) z F8 a) o( J
! T) ]: m' ?7 t2 j
|
|