管理员
论坛积分
分
威望 点
贡献值 个
金币 枚
|
摘要: 本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图, C, h7 P# m. R2 c$ _) o
+ U& h& |8 i# Y# d! N
: }4 _! j3 C* m% L$ g
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 X" A0 m. I4 U
- <?php
# J8 ~9 @. g2 E - /**
" V7 [ x- W7 E# j - * 图片相似度比较 7 N; G: B) |8 s
- * % `% g+ c/ q1 D
- * @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp; . h/ i6 N1 `1 h6 u/ a ~/ i1 }
- * @author jax.hu ) V# N- H9 j7 m3 S: G$ h9 f
- * 9 S$ h4 E6 L. G7 s7 _
- * <code> . |% r& V% Q' F3 O' k8 D# C. n: ?
- * //Sample_1
! Y0 Q: `* t% a1 K: M3 n0 [& V, U - * $aHash = ImageHash::hashImageFile('wsz.11.jpg'); ! V: u% b/ S5 Q* `
- * $bHash = ImageHash::hashImageFile('wsz.12.jpg'); * Q( `- S5 W5 q
- * var_dump(ImageHash::isHashSimilar($aHash, $bHash));
5 x. A: @- r/ q+ b# l: u7 _1 h' t - *
) H; A! ` x- [0 n$ K - * //Sample_2 6 L) S# H3 F' q4 P8 w$ `4 R
- * var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
, X6 ^3 P, ?, G - * </code> : z k# ^3 [1 s+ [0 }
- */ ! g/ z1 S6 d( @8 U5 |
-
1 t7 c7 U8 o7 x+ S6 D# S' N - class ImageHash {
' g# W; N% T/ H7 \ - : }' {5 W7 ` G. Z" U9 w
- /**取样倍率 1~10 3 u0 h6 Y- _ [, ?( [
- * @access public
6 k* x s4 Z, ]1 {7 d* J% @ - * @staticvar int
1 `- _! }% U0 d - * */
; E8 D0 w ?4 h2 s8 s - public static $rate = 2; - e2 Y% M. b+ I/ k/ F
-
; o* k% I6 X6 C% O6 n - /**相似度允许值 0~64 # ]: V5 d$ O5 Z5 |
- * @access public
- V9 m k: z4 E! Y - * @staticvar int
{! u. _3 c( I6 Y! _$ F* A - * */
3 R9 O* U* o/ @+ Z1 p - public static $similarity = 80; ! w3 H" N" {# ?; N; b
-
" }4 T2 |, L, f5 [: L9 A2 O" r - /**图片类型对应的开启函数
* O8 O5 g) K( @& a& p% ^, `# c - * @access private - J) K5 K/ v3 G$ p$ f
- * @staticvar string , n3 e7 c4 G, }# x) S3 ]% ?/ @) t
- * */
~ J7 K9 A* m - private static $_createFunc = array(
9 w8 q u( Q- c- \+ M( Q" X4 y - IMAGETYPE_GIF =>'imageCreateFromGIF', + r& u4 y. P; @. j
- IMAGETYPE_JPEG =>'imageCreateFromJPEG', 3 c w& l! L/ a. ~
- IMAGETYPE_PNG =>'imageCreateFromPNG', * U J; N- ]1 u2 \+ Q% v, {
- IMAGETYPE_BMP =>'imageCreateFromBMP',
) u9 `2 W9 u9 Y - IMAGETYPE_WBMP =>'imageCreateFromWBMP', & x0 a( R4 U) X4 z& z: \2 C* X9 d- W
- IMAGETYPE_XBM =>'imageCreateFromXBM',
4 E( Q/ }0 z9 j1 h! B( M% L+ e; B* A - );
/ E: d' B$ S& k& p& B" c -
2 |- L2 t" ?& w -
# v1 b6 X3 p# E: b1 i; } - /**从文件建立图片
- y% I7 E6 C+ I& V8 \ - * @param string $filePath 文件地址路径 / H2 z4 k8 t% S3 T
- * @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
) j P: n; }# J( ]5 y7 c - * */ - N, Y+ b; W+ Y% l' |: _, [
- public static function createImage($filePath){ 9 B" n4 f% b/ V, T2 O; O
- if(!file_exists($filePath)){ return false; }
7 l% h9 s8 c/ l& y$ T* m - 6 D4 Z( D% ^, K4 P0 T
- /*判断文件类型是否可以开启*/
) V9 h: M# `& g' i/ H% j! u - $type = exif_imagetype($filePath);
. |3 i, P, c8 d0 t7 d - if(!array_key_exists($type,self::$_createFunc)){ return false; }
+ {" C" P4 j9 [* U6 \5 U - ! F, r. I: k U4 b8 D$ Q) x: m3 `1 U
- $func = self::$_createFunc[$type]; + Q+ U, H* L- @- v) Y$ ?0 n
- if(!function_exists($func)){ return false; } 6 ?0 j& {6 M( B+ R) O7 z
- 4 t, Y: Z9 R7 k/ k& j9 ^! R
- return $func($filePath);
9 D1 I5 a: E, i$ B1 X k - } ( N1 g' o0 j; U% C
-
4 P( ^# b' r$ {) P8 b - 1 B E6 U/ `/ W, U- K, r
- /**hash 图片 - ^# i; V2 t5 W i
- * @param resource $src 图片 resource ID
7 N1 p, r" {- X( k, `2 n. e - * @return string 图片 hash 值,失败则是 false ( k/ V" Z/ i8 p
- * */ . Y3 s9 p9 g1 g1 h& b0 B
- public static function hashImage($src){ / w' w8 w8 c: F: D9 L2 I9 C
- if(!$src){ return false; }
: b) w1 X( B) X! U) v$ G% Q -
2 j3 F C. V6 z+ @) ~% G1 P9 ^8 P - /*缩小图片尺寸*/
X0 P7 z3 Y2 b4 k: V4 l - $delta = 8 * self::$rate; # |5 _) Y. H1 y4 {
- $img = imageCreateTrueColor($delta,$delta); 9 {4 G4 v- G, c3 R8 `+ Y C$ L
- imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src)); . K8 V& Q- u5 w( n' e: O
- . o* p) {% P, y
- /*计算图片灰阶值*/ 0 @6 w% M; u ^ u
- $grayArray = array();
- C0 m* V3 U, h4 S8 q - for ($y=0; $y<$delta; $y++){ ; d7 w7 C8 I% s/ k
- for ($x=0; $x<$delta; $x++){
! }; q# d1 O( p - $rgb = imagecolorat($img,$x,$y);
r1 y6 r+ w$ o( J+ }. b - $col = imagecolorsforindex($img, $rgb);
. F% j( @: c( w6 t - $gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF; 0 f5 ?& B6 S: p
-
7 o5 P* k5 H. R& s3 G- e - $grayArray[] = $gray; 9 A2 B, M& N/ ?# j
- }
4 q( o/ f* P ^; X - } ) a& w+ ?- K* z2 z
- imagedestroy($img); " R) `4 _ o$ \# G6 m' [2 i
- ; M( V+ x& m4 I+ J) Q
- /*计算所有像素的灰阶平均值*/ 6 B9 G3 b! h( U' w
- $average = array_sum($grayArray)/count($grayArray);
6 O2 E2 L8 S$ ^ - $ a8 N7 M/ q! T( g+ K; w
- /*计算 hash 值*/
+ Y9 M6 [5 l( G, E1 a - $hashStr = ''; ' w1 d4 j5 E0 s. ^
- foreach ($grayArray as $gray){ : @- S6 r; ]% E. u
- $hashStr .= ($gray>=$average) ? '1' : '0'; , v1 P& S% \9 V0 c! f5 ^
- } # P1 T1 P$ q6 j& L8 h6 J8 F
- ! ~7 h* f; k' P! }8 M( _# `) B' h9 G( P
- return $hashStr; 2 \: E5 b+ N8 A' D- z8 P
- } h% e8 o* N7 z. J$ I1 P8 M
- ( b2 v; E2 n G$ k
- : y: [: C8 ^' j* H# p
- /**hash 图片文件
, }! r0 L- x2 n" Q s9 B; C p - * @param string $filePath 文件地址路径
6 G) G# \% w/ X' c" x4 a. j; v. s - * @return string 图片 hash 值,失败则是 false
+ V' u" ^$ H; B - * */
# A& q2 A# d G# w/ L o5 D5 A - public static function hashImageFile($filePath){
5 C1 M1 K! d! v - $src = self::createImage($filePath); " x5 `8 P* p) v- ?- Q4 X. ^9 J
- $hashStr = self::hashImage($src); ! x3 A' M( n$ q, A5 X
- imagedestroy($src);
( [$ N$ L6 w' _% H - + L5 F# U9 P. [# d) L
- return $hashStr; 3 S4 |' H5 R/ K" N0 X2 x+ I
- }
4 Z& E! d3 {: o% i6 p4 \: x) x - % v) s3 n6 E3 i% }" p6 S3 H
- 2 f6 E4 p; ]3 K% r
- /**比较两个 hash 值,是不是相似 / o8 L4 R9 `: O
- * @param string $aHash A图片的 hash 值
) y" K% I9 b D6 G - * @param string $bHash B图片的 hash 值
; j7 y' A$ |! f. R# x/ t _ - * @return bool 当图片相似则传递 true,否则是 false
* F; q4 s+ O# T8 p6 U! ~ - * */ : L0 J9 m% T3 P$ C$ k6 ?5 Z5 a
- public static function isHashSimilar($aHash, $bHash){
' L% B7 E- p. g/ \ - $aL = strlen($aHash); $bL = strlen($bHash);
' O5 Q5 T4 E+ _, W# a0 J - if ($aL !== $bL){ return false; }
4 ^; Y3 j+ I$ ^( Z8 L4 O9 `; u - 7 J% p( ^) B# s( `
- /*计算容许落差的数量*/ 2 _5 x3 ~) L7 I- j; B4 {
- $allowGap = $aL*(100-self::$similarity)/100; K3 p8 b$ I" M) z
-
5 w( T% H6 `$ b+ b3 r$ g3 r) s - /*计算两个 hash 值的汉明距离*/ 2 l* c# P8 J. I9 h" x2 u4 Z
- $distance = 0;
; `" Z7 d( ~9 C8 y) R& _; _ - for($i=0; $i<$aL; $i++){
: c, ]) Q1 @6 |' ?- W - if ($aHash{$i} !== $bHash{$i}){ $distance++; } : q& Z, n/ M, T. P `
- }
# ^. H/ b+ q* }1 s: i - 0 I; S5 d! z. G( ?/ H) u/ e4 x j
- return ($distance<=$allowGap) ? true : false; % \1 I) ~* X1 k* K* j
- }
8 F: S" a; M3 A8 l0 R -
8 X* _% ~# c* M -
; n8 N. W; O! U) Z& x0 C - /**比较两个图片文件,是不是相似
- f. Y5 c P! s& J1 ] - * @param string $aHash A图片的路径 4 Q$ T* I' y ]3 N* h
- * @param string $bHash B图片的路径 ) T: e( F$ n3 e$ C, X$ E
- * @return bool 当图片相似则传递 true,否则是 false 0 G+ \; F7 E2 C! Q7 \2 O; U4 M
- * */
9 E6 `7 Z2 g* c2 F6 ^1 Z: C: n - public static function isImageFileSimilar($aPath, $bPath){
2 {% F. w: c* o4 n; t& J; x7 S - $aHash = ImageHash::hashImageFile($aPath); 0 Y0 |' m: l( Q3 [2 J
- $bHash = ImageHash::hashImageFile($bPath); 4 ~( @' K1 p* w
- return ImageHash::isHashSimilar($aHash, $bHash); 5 Y7 g* H9 k1 b5 S, V$ ?
- }
. Y3 Y. o! g- R/ p -
5 }" I( b& S" a - }$ i6 m+ s& k% O$ M
复制代码
: b+ x5 i" y4 l8 W! q3 D% m4 z) y- |' J% ^6 \4 K
|
|