cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
) |) ^! N: T- a# k
+ h( Y) A' l! U5 R
7 I* J# @0 z x: g% h% R! S
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
9 M2 s1 H3 s8 Q& g5 ~; K) {% J* Y
<?php
4 R2 J/ N% C0 f
/**
4 L: S- m1 }1 p) y+ g9 K6 l$ h
* 图片相似度比较
6 Z5 S+ N' @& h# R1 Q
*
3 d' A" B( t9 M
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
* [, o. @6 L- y( K7 F ]. H) T7 L; C
* @author jax.hu
/ A" v5 ?5 Q8 a; `2 {8 ^6 L
*
) X. p& l& W- m+ {; j
* <code>
n( P6 Q& \$ U, Z4 j
* //Sample_1
/ f1 {; `* o; z- i1 ]6 }1 l
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
- u' |5 ~) T( Y4 K: a1 c V
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
; G. J; a7 x& @, `& j R
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
9 `) B" b# S; A2 p8 H( J# |6 n4 G# p
*
. Q$ I$ i n4 h
* //Sample_2
0 U4 y6 l& W9 y! o
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
9 U! y% J* t4 p: k
* </code>
4 j/ b4 c' C. m9 O3 G: k% d& `
*/
* Z: L1 l9 a: ^1 t$ H
' F& ], m4 G( `8 j1 _$ D2 A
class ImageHash {
% H2 H" q6 S" s8 k
; `+ @% a2 ]! P. P0 t' @' b
/**取样倍率 1~10
0 \) D. w- Q/ m& }* Z: A' ]; k
* @access public
" m! }$ d# \* P" P4 d1 x3 l
* @staticvar int
2 G6 ]: k9 P# r) M! Q7 J
* */
8 s* p/ L) j1 h& V
public static $rate = 2;
5 X; S7 e2 z' y# x, P+ L5 d. N6 m
' l: x% ?* w/ y& h6 d' W
/**相似度允许值 0~64
( z/ b* E8 n1 u% ]
* @access public
7 {1 m( z* c" m, U( A7 ?6 ?$ M
* @staticvar int
; S+ E5 m; r' c; T8 l0 d! a
* */
' `( Z- E; g6 C- v& r2 ?5 r7 }$ {
public static $similarity = 80;
+ p R. E( G2 s2 G
Y0 y' s. m/ o V5 k% G' ~
/**图片类型对应的开启函数
- c8 @/ R, N) u4 r4 D4 C' i& Q) _
* @access private
* u7 w5 ?0 J+ B% k5 V
* @staticvar string
0 }5 L- u8 I1 W$ b t/ J
* */
# g0 r+ v9 p4 T
private static $_createFunc = array(
0 |$ r' c1 {% b2 r( L
IMAGETYPE_GIF =>'imageCreateFromGIF',
/ t0 F2 w, o: o$ w- o' }
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
* M% @" [: v' U: L3 v3 I# Y) U
IMAGETYPE_PNG =>'imageCreateFromPNG',
5 m% L* s- o" a8 A" G3 A3 t& z
IMAGETYPE_BMP =>'imageCreateFromBMP',
. L& U+ W6 ] V5 X5 b
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
8 g% D6 ~' D0 t! d" X3 K$ D' @; o
IMAGETYPE_XBM =>'imageCreateFromXBM',
' X! x6 l& h2 @, d
);
3 e' y% [$ I8 Z
; `6 L, P1 k$ g
) D" Z* Y3 f2 ?# ^6 C- w
/**从文件建立图片
$ s9 A0 L! `) D4 H) U( m5 ?
* @param string $filePath 文件地址路径
' ] Y0 J0 W2 M
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
: S: G3 p1 i* i
* */
8 B# O$ X1 g' H9 X- H9 N! P
public static function createImage($filePath){
0 s* ]; f0 ?& ]) Q3 T
if(!file_exists($filePath)){ return false; }
) Q( c# ?+ j* b1 d0 |' i
5 V* @5 ?$ t* w0 z3 h2 \# u
/*判断文件类型是否可以开启*/
6 c3 S0 v7 ]: ]/ Z. J4 @3 F# n; {
$type = exif_imagetype($filePath);
0 w. I& b! B3 b0 A3 ~0 G/ V1 T
if(!array_key_exists($type,self::$_createFunc)){ return false; }
A4 {( e* N4 e) B
6 u* A7 _4 E$ B* T Q
$func = self::$_createFunc[$type];
: F( K! |" N* ^% z" V
if(!function_exists($func)){ return false; }
: S7 G. H4 m. ^% _5 ?. s) [
- O# g' T- n, t! C% g6 `( w
return $func($filePath);
* k; ^4 }. \& o2 _3 S9 b+ p" X
}
/ B: [* ` V! O/ k O
8 \" t$ r2 R8 l# ~: N/ r: G7 m) k
: p7 R3 J/ D+ r& U3 J- n
/**hash 图片
- z0 {7 A: D& l5 P# e
* @param resource $src 图片 resource ID
4 s L. i, D0 G3 z: }% c
* @return string 图片 hash 值,失败则是 false
) g- |# \+ w- \ {- P& g7 H
* */
- h, r! f' H7 v2 m8 n
public static function hashImage($src){
# A d, X+ U, o/ ?/ f
if(!$src){ return false; }
7 r( c5 O7 v5 z1 |0 ?- ~+ d
# k8 Q3 u" x0 M9 P$ f
/*缩小图片尺寸*/
/ i* ^+ @$ G) j6 A% L5 w
$delta = 8 * self::$rate;
" Y/ S# D: E5 n8 p1 T5 P1 h, H
$img = imageCreateTrueColor($delta,$delta);
$ j J. W! U7 L- E
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
; q" G! |0 h$ B( I; o9 @
8 W6 @; ?9 R! c: d. {
/*计算图片灰阶值*/
4 K% g# U+ s! ^- `9 O4 w
$grayArray = array();
! C4 b; J! K* g; |0 T
for ($y=0; $y<$delta; $y++){
8 J' L6 T7 y2 l9 f) [
for ($x=0; $x<$delta; $x++){
9 a! q1 y6 v. d* `* f# M) |. |
$rgb = imagecolorat($img,$x,$y);
: r: d ]6 ^( A, \' [. p) |5 u
$col = imagecolorsforindex($img, $rgb);
/ r- w4 ^4 `/ [& F- u [
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
: n% y! |' c9 r) v; H* m
V8 f. o4 p$ O9 u) ?! ~" S
$grayArray[] = $gray;
! V Q: m) z3 V3 i- D" \* P
}
3 ]6 C, E0 `1 a! t
}
! r/ v( T* _# \& u \
imagedestroy($img);
+ B. s4 V* x0 c* `/ z
9 X: c8 l1 d" t$ b' H9 F7 W, H
/*计算所有像素的灰阶平均值*/
5 E r/ \* }3 o$ j. j8 m2 g2 f
$average = array_sum($grayArray)/count($grayArray);
. G* P& [( W6 {+ d
5 ]( @% U9 q, j8 F- D
/*计算 hash 值*/
6 ?& g/ \( p& J; O0 Q% Q
$hashStr = '';
% \% ]6 W; F+ k3 f
foreach ($grayArray as $gray){
6 N% r9 U* T( S& S2 D3 B0 N" X
$hashStr .= ($gray>=$average) ? '1' : '0';
@9 C" a: m( F" u+ ]% I- C
}
1 t9 J6 ^ Q$ Y: G
$ ^4 \% q( r5 @3 A N; x; W
return $hashStr;
2 G- p: g0 d5 f& `: `7 j, G7 W) o
}
8 ?5 }# s& X' b: Z5 T% O
0 a1 U; ^& i( [: E; K% w$ r
7 b2 q! Y0 Z' W- k6 B
/**hash 图片文件
0 j/ P' Q: R. {' [4 I6 @$ a6 }
* @param string $filePath 文件地址路径
7 q: K4 ] B+ K8 h: L& S" }7 P
* @return string 图片 hash 值,失败则是 false
+ \6 x7 X5 o/ l# E# e! j8 ]
* */
- d' E' b. f& ?( ~ U! Z9 Y4 r
public static function hashImageFile($filePath){
9 W) R: P1 e: E+ X
$src = self::createImage($filePath);
1 J; G! M% g& ^4 c. I5 R9 S! f
$hashStr = self::hashImage($src);
5 l+ {+ h @4 x+ ^" O) v
imagedestroy($src);
3 n" W: A7 i, f b- E8 L
! j% `6 l; j7 q* Z
return $hashStr;
) j/ F5 y p. v l
}
f2 `% J. Q7 i" p5 |5 J6 n
$ v: z+ r! q+ i! |4 u9 _6 W8 X
: l: ?* f; u1 b; Y. W
/**比较两个 hash 值,是不是相似
4 S6 e& S) ^ C3 Q- |6 m1 Z
* @param string $aHash A图片的 hash 值
p& f" M/ C& t3 X ]8 o
* @param string $bHash B图片的 hash 值
* z+ D! v6 {6 A7 S; b: @2 N
* @return bool 当图片相似则传递 true,否则是 false
9 [0 t* V6 S8 ?
* */
' r( i' S' n3 U- Q/ L# _
public static function isHashSimilar($aHash, $bHash){
9 M5 L5 U' i! i3 C( S5 X, e0 r* ~
$aL = strlen($aHash); $bL = strlen($bHash);
9 A# O0 g3 v* }7 u* V7 y
if ($aL !== $bL){ return false; }
# Z m# c* u) V0 I3 \& |7 v+ L/ J9 E
9 T3 i2 {5 _8 V- [1 |' a! }
/*计算容许落差的数量*/
" n$ `8 g7 E" a) c
$allowGap = $aL*(100-self::$similarity)/100;
+ G! S) w d% i/ U
* p) G7 v: H. ]) f
/*计算两个 hash 值的汉明距离*/
$ Q/ t, z& ~+ a2 B* j
$distance = 0;
' E/ `" u, M2 X- }/ ~! O
for($i=0; $i<$aL; $i++){
: T! b ?) Z' G- M$ X; v
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
4 T: h8 r3 x' D' F2 [* |5 X
}
5 r* |3 f: L( i% {/ q- r" a
2 j% X, x& F) a2 J2 q: T, A& a
return ($distance<=$allowGap) ? true : false;
. K4 [! F# l- o. F+ g
}
: @( Z" k0 N" u
+ L y; Y6 }+ S2 e
+ u& g) L o8 w/ ]- M+ @9 w
/**比较两个图片文件,是不是相似
+ P4 l5 g" z8 c
* @param string $aHash A图片的路径
% N3 |$ i. c" M" W% @% g7 H' ]
* @param string $bHash B图片的路径
) w; s8 \# \+ v! j- I$ w
* @return bool 当图片相似则传递 true,否则是 false
( ] `( t- ?9 g* J; L+ E, h( u# w0 M
* */
( n. Q4 _$ h. b, W6 N7 k5 ?
public static function isImageFileSimilar($aPath, $bPath){
: |- q2 J5 j) X+ E1 W
$aHash = ImageHash::hashImageFile($aPath);
6 r3 F( Z5 T K" T
$bHash = ImageHash::hashImageFile($bPath);
3 t N: x$ Z: _$ C
return ImageHash::isHashSimilar($aHash, $bHash);
- R N" v/ I4 H/ k9 _/ L0 v
}
* t1 E& r! p2 D
j8 Z4 Q2 {1 ^% v( E, S
}
3 p( @/ K, N# ?/ K: Q. l- b2 S
复制代码
! O, e" t2 \$ i) f
% ~& W4 j& u+ H
欢迎光临 cncml手绘网 (http://bbs.cncml.com/)
Powered by Discuz! X3.2