cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
( M8 @2 t+ }5 F4 N A/ {
5 m% W) A* c) j# k7 s* Y
' f: E% I. V' x: Z. t
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
" o- [$ k7 B' `$ Y) b
<?php
: A t4 W/ { @' W
/**
: z9 @2 Y. P( V" b
* 图片相似度比较
" c% C0 L' w0 i0 U
*
& P+ p; C, H Y" O" o& U5 G* [3 m4 w
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
+ b d1 A9 O3 J2 \9 Q P3 i* }# N; J
* @author jax.hu
+ W. j; K: K. x% m2 l, j# ~: q; T
*
2 Q+ m3 r! ]- c" ?3 Q
* <code>
( c2 [8 R% {" L
* //Sample_1
5 b$ N- V! D. j; K+ F+ H
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
% K5 ?6 n0 c. Y1 Y q1 t
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
5 ?% ~4 T6 w: r
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
; ?8 l: l# \, d. t4 s
*
8 i" ?7 e L0 |. q# |, w
* //Sample_2
/ Z. L; p1 Z' t
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
. X9 F% I( X1 L `: }) M, X" m
* </code>
' a% Q7 E I& }( W3 Z9 }; d
*/
U6 N/ z* u. t$ d$ ~
, u. B8 v0 q/ Q6 X1 n
class ImageHash {
1 z" h3 K3 A E! P" X
1 F. z2 t9 K* H# f) F
/**取样倍率 1~10
! O! K3 }6 t& M# X
* @access public
: Z7 m, U2 }) O. ]9 V" w/ u; X
* @staticvar int
' g/ J6 J7 f8 U" A' y2 W
* */
# p5 f. b8 ~$ I9 s# t N7 H; X. R7 X& Z# j
public static $rate = 2;
, z2 X( o. A4 ~, y
4 @8 ?" K7 v# o( `; `( s. v$ L) w1 k
/**相似度允许值 0~64
" g; L l1 B8 k, `5 g
* @access public
5 t' c$ v4 x6 V- I) A
* @staticvar int
8 v/ C) f( v. b' {- s
* */
5 {1 y. \* w) z* K
public static $similarity = 80;
" Y) q; Z6 ^2 a& i8 P6 w
) x" ^2 b6 M1 Z* g$ w z& ]$ g+ R
/**图片类型对应的开启函数
, z1 K& |, j9 r H; U! h, p, _
* @access private
. O' ^7 p; ^% R9 ~: W8 v
* @staticvar string
' |- o! a0 s% @0 d
* */
, h) {- T, L, v; Y8 N- ~/ \
private static $_createFunc = array(
" Q0 R* o0 J; t8 j
IMAGETYPE_GIF =>'imageCreateFromGIF',
% s* X/ |* N2 Z2 d
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
* p) z7 i' o5 N! B$ `) x9 t& Y% I
IMAGETYPE_PNG =>'imageCreateFromPNG',
# F% b0 d' G- t1 |0 S
IMAGETYPE_BMP =>'imageCreateFromBMP',
( j" l {7 I. K$ s9 q/ E0 N$ i
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
$ w1 l' P8 o9 _0 z
IMAGETYPE_XBM =>'imageCreateFromXBM',
* n0 U! o% b+ ]& G0 o+ e) u; v0 A
);
: N% ?: o M6 y& ?3 s) |
& E* N7 P% Y1 `# e( U2 N
3 {* W6 V0 n9 `# T( C- J- g
/**从文件建立图片
# S1 y6 l% H+ R
* @param string $filePath 文件地址路径
( H. i: E- Q7 s5 |; I
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
' W- g2 b4 D; G; B: H- I! ]& t
* */
- n& @7 O* L) L. Y" Q
public static function createImage($filePath){
, W2 J3 a$ Y" S! ?7 C* A4 P8 a
if(!file_exists($filePath)){ return false; }
9 E5 A6 H) C9 P$ J: o! B) ^
2 Q; B# k! C, T& m
/*判断文件类型是否可以开启*/
: B0 Y) \: l9 t9 F, j& Y
$type = exif_imagetype($filePath);
% v- S0 a9 @/ k1 l$ @0 b
if(!array_key_exists($type,self::$_createFunc)){ return false; }
: O8 o: g! l) o7 L! b4 s7 v
2 @" d- z3 J" ^1 {0 J0 E
$func = self::$_createFunc[$type];
. d' |' y1 O% g1 l& {/ B: ?5 {4 a
if(!function_exists($func)){ return false; }
6 d) S( C: \2 b+ N1 O" \6 j
, Z3 `3 f8 h) v0 _/ P. x
return $func($filePath);
8 c1 c5 y7 n# p" j
}
5 [( x2 P& y ]( h5 g
* C- t0 t* C9 Z2 u
! f; ?8 l/ Z' g3 Z0 x
/**hash 图片
4 u1 T0 C9 v# G8 W& n6 x$ T( n* T/ `
* @param resource $src 图片 resource ID
7 H5 V& ?0 B2 w8 A1 J
* @return string 图片 hash 值,失败则是 false
! v0 M0 ^$ v" g* k7 Z: k( C4 S1 q) w7 k
* */
# w8 p2 |- g0 N1 p$ D3 @8 S
public static function hashImage($src){
" }6 U; o5 B( g( w+ d* y
if(!$src){ return false; }
7 N4 J& Q7 f b, E
1 ^, j, d* ~" F) x1 j* s
/*缩小图片尺寸*/
! H8 V5 d& A _4 N" _ c
$delta = 8 * self::$rate;
5 {$ J# I+ M3 `+ b f
$img = imageCreateTrueColor($delta,$delta);
$ ~1 z% x: j' u+ _+ i
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
/ |3 f; k9 X2 [0 `0 `$ S3 Z H/ F& Q
0 j7 X% c7 k$ Z! \
/*计算图片灰阶值*/
7 W. t6 n6 K8 J2 o
$grayArray = array();
6 ~4 x. }1 l V) i3 ]
for ($y=0; $y<$delta; $y++){
" i6 M9 p5 a1 B5 u
for ($x=0; $x<$delta; $x++){
" e+ t6 }* ~9 \
$rgb = imagecolorat($img,$x,$y);
% x% V( q' {+ u7 }/ C2 q! y
$col = imagecolorsforindex($img, $rgb);
0 {2 O# O- ~- P" @' D
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
+ `3 c8 t, `7 F$ n8 w4 }3 G6 |
6 l: c) ]: z! S) X: g
$grayArray[] = $gray;
2 k& c; K$ z2 h0 a5 k- f2 `5 }
}
9 ^* i* b# C: z% p1 @; A, f$ H$ X
}
9 u1 f- F y. n; Y
imagedestroy($img);
/ X" @* g4 x, ]7 q) I5 q
! [" z& Z2 ^5 h9 K" f2 J- h% v
/*计算所有像素的灰阶平均值*/
: l, m4 ?9 h3 y7 V9 f+ Y) Y7 C
$average = array_sum($grayArray)/count($grayArray);
. l! Q! C+ T2 M* x$ V9 i
& w* `9 R! U- @# Y3 Z# \" R k6 v
/*计算 hash 值*/
) C6 `! V- x+ D! P% N* B
$hashStr = '';
. [: p1 s8 j" E
foreach ($grayArray as $gray){
* A5 ]5 {$ q% ]9 }- Y4 x) d. G
$hashStr .= ($gray>=$average) ? '1' : '0';
0 S+ f* w8 Y9 U% V! S
}
) V" D, M0 T9 m# S, P" r3 \
. y- O- |& j$ u" l! z
return $hashStr;
% F3 v$ P Z8 A1 J) y
}
% @2 j. u5 o# I, C
) @4 G; s/ O( ?2 A6 l/ r1 b/ t
2 K m0 p( F& d: t9 P6 \
/**hash 图片文件
6 _( c" {# R/ L
* @param string $filePath 文件地址路径
* J% w4 X5 g( l* h! G, |) x
* @return string 图片 hash 值,失败则是 false
, j4 D& B7 z; i- A( A( o
* */
; y* G- h Y5 C4 I1 p8 c: G9 q8 k
public static function hashImageFile($filePath){
* O) W/ ?7 x' y# ? p- C$ E8 X
$src = self::createImage($filePath);
( J7 v3 k( g# O% I& `, N* |, A+ J
$hashStr = self::hashImage($src);
! l7 j% j5 j3 ]5 R- t# s' Q1 b
imagedestroy($src);
* _0 T4 D3 x) x1 i
) i; L+ V) T6 Q9 {: i6 M
return $hashStr;
) k5 K: K+ ]$ Q4 C) s$ r
}
6 {, c# O3 l; g1 l8 e% u
- m: a) q1 D: X8 A9 x/ M! V
% \3 p$ p E- l5 ^) B( x
/**比较两个 hash 值,是不是相似
+ [; e3 l3 [" c, I8 }7 g$ v
* @param string $aHash A图片的 hash 值
; q0 C* y y% f2 ]3 m
* @param string $bHash B图片的 hash 值
$ `- P8 b+ P& s7 K2 H' B7 ^
* @return bool 当图片相似则传递 true,否则是 false
6 F/ o- G, Y' Q1 ]
* */
. C3 K7 G, W" A5 S3 G9 O- S# Q1 h
public static function isHashSimilar($aHash, $bHash){
$ ?; i1 K- [" H8 G" H# b2 o6 g, h
$aL = strlen($aHash); $bL = strlen($bHash);
, U% c4 v, N9 ^7 q) C& L" f# F
if ($aL !== $bL){ return false; }
+ }8 E `# `4 d; Z2 P g
; ~# g: q. q4 Y/ a, [4 a( f
/*计算容许落差的数量*/
4 p. q' P' ~. E+ G u+ P
$allowGap = $aL*(100-self::$similarity)/100;
$ R& P9 y- k; T, \) n
- H0 A$ x+ t' A# e' x8 S1 W$ C
/*计算两个 hash 值的汉明距离*/
9 ^, [% x/ s$ X+ f7 c
$distance = 0;
# e1 Z. W" ^4 Z$ f
for($i=0; $i<$aL; $i++){
) c; m5 ~5 U& H0 D3 h
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
7 `$ e) W: r( B+ ^# I0 B
}
9 I" ?! H. y e- j+ `3 u/ ]1 Y( M4 t/ r
4 N# P. `! c3 g9 D5 H
return ($distance<=$allowGap) ? true : false;
7 e% ?9 Y+ E" r$ o
}
( D. }# Q. ?3 [4 B0 E4 P& m' _
! k6 Z/ w1 U4 f8 @+ o2 O
3 x! M) R" e/ w, }& o. a' v$ M7 T
/**比较两个图片文件,是不是相似
$ c( L+ O/ Y, T6 q6 H- ~
* @param string $aHash A图片的路径
. ~2 A: v" A8 a6 K+ u, X% s1 ^
* @param string $bHash B图片的路径
: v# L/ _1 `# M8 ]
* @return bool 当图片相似则传递 true,否则是 false
! {8 B2 K; T& s3 u; R j, f3 S ]
* */
! y- v+ `" a3 \2 U) [& D& u7 Y
public static function isImageFileSimilar($aPath, $bPath){
# o" D; q6 x( r3 ^) k# M
$aHash = ImageHash::hashImageFile($aPath);
: F( v. v4 u% y
$bHash = ImageHash::hashImageFile($bPath);
; J' I0 u* T, H- Y2 W: \, @6 u6 ~( d
return ImageHash::isHashSimilar($aHash, $bHash);
# o+ G: v) Y/ O! F" H
}
: ?7 Z% P+ ~7 ^; \
& `/ Q1 B) S; L4 o& @( e
}
2 P& c3 ?7 q2 k! |! @
复制代码
" x5 H5 z: I8 a! u6 y/ n1 `
$ a- e9 w# Q8 n }( W m; M
欢迎光临 cncml手绘网 (http://bbs.cncml.com/)
Powered by Discuz! X3.2