cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
+ `* ] V/ C0 n @1 }3 j% V# y
0 l( Q: b' p9 N; z
- @& i4 i/ C! r z& o5 V, h
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
9 r3 \& i5 _) ^3 H
<?php
: k! \: g. G7 K1 o4 T3 U8 w
/**
3 p7 O1 F7 E {
* 图片相似度比较
, d! k, D5 V$ h2 H9 N1 R8 K
*
' |4 I5 b. s7 G
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
?2 Y# U i& C( J
* @author jax.hu
: O/ m* v; a& M, ^
*
7 J2 B h1 p$ ]7 N* Q8 w$ w5 F
* <code>
7 S; G; r( t( s: Q. ^
* //Sample_1
: o5 T; ]4 w! B3 V K8 ]# ?; [
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
" j' b3 r( u8 \/ O
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
1 C6 o4 n8 W- X( k% @& L
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
; R! f/ N7 K7 R0 W" I ^) @& \
*
# z0 d4 a( h, ^" m n; f- v
* //Sample_2
% h3 p1 P9 V0 a& N
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
- d. F" ]% z4 P: [8 Y* @
* </code>
% I. x9 V4 O# E+ ?- _
*/
! y! D6 g6 l% i
. E7 T3 n m% c8 `: f& E
class ImageHash {
5 G) a3 u) H+ q$ h& B
, S% a3 r1 {6 a J1 k+ a ~
/**取样倍率 1~10
' e0 C* b6 ~! ~0 y
* @access public
8 z: r3 A8 ]0 ^) {) J
* @staticvar int
1 j) z, U- Y# ^" u
* */
$ L$ o Z! ?& m7 z0 m9 z
public static $rate = 2;
8 B4 g3 [/ N- \3 y: v: S6 s
) y! h: [( K9 N, d( ?& K* ` H
/**相似度允许值 0~64
) m2 X7 @; M8 H* s) p) {
* @access public
5 m J9 W$ d6 f0 j& B
* @staticvar int
9 z- Z# O) a# ?0 _# P" d% x
* */
5 z& B6 o& G+ ]+ d# x1 E
public static $similarity = 80;
5 r. q0 i" D( b4 n8 j& t
( z) Z" J6 B- F( s
/**图片类型对应的开启函数
& G; q, y$ V( e% V9 X. p
* @access private
: ^( ? |1 W6 c3 q
* @staticvar string
" @9 V2 }) U9 W9 q8 y5 z" N
* */
. M8 a) N2 \1 ~# M
private static $_createFunc = array(
0 | g2 m! {8 f C3 [
IMAGETYPE_GIF =>'imageCreateFromGIF',
' U. V7 g7 _& U% G, c$ ?
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
& \1 [% f8 k# `! ~2 n+ `
IMAGETYPE_PNG =>'imageCreateFromPNG',
l* W i- R4 @: E$ j
IMAGETYPE_BMP =>'imageCreateFromBMP',
" p: m1 Z$ i" ]( l
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
1 Y7 u/ V9 U6 }1 c/ D
IMAGETYPE_XBM =>'imageCreateFromXBM',
1 e6 `, }0 s1 E y4 `5 G) ]
);
. b% M F0 P# m# g
2 v$ |, g# [& Q6 n. r
0 W! z# I" Q& Z G+ w+ C5 y3 i
/**从文件建立图片
( Z9 W& m' O' {- N2 ~! G
* @param string $filePath 文件地址路径
* ~% B% B3 T U6 U
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
8 ]6 n* H% O0 t. e, ^) [ r
* */
3 P9 \3 A1 o q; K! L- }5 B% t
public static function createImage($filePath){
4 I4 w+ U1 s p3 r2 i
if(!file_exists($filePath)){ return false; }
# z5 X' W" k" p
) q8 `4 P" H, X# {" q+ T
/*判断文件类型是否可以开启*/
/ h/ _# N; y$ i& p) l
$type = exif_imagetype($filePath);
- P# u+ N' _/ L; ]
if(!array_key_exists($type,self::$_createFunc)){ return false; }
6 |7 g8 k- n, i/ }, \, i
7 ^ R" J# H0 ~( c
$func = self::$_createFunc[$type];
0 f: R; m0 X5 [, Y, i
if(!function_exists($func)){ return false; }
4 @4 s; d. |8 H' i) u: J
. e# O- n( [, d
return $func($filePath);
; A, U1 _; |" B9 h0 b. l1 g
}
5 g& F r: q. _4 L. | \4 v7 }9 u( V4 I
# Y& R! r. T1 i: e: _, ~6 B* f8 q5 F
5 F! g; q( J: [& D
/**hash 图片
- H% l' N0 d( V5 D9 A6 ^8 J1 b) m
* @param resource $src 图片 resource ID
( u: Z7 q4 p6 s9 [
* @return string 图片 hash 值,失败则是 false
3 g; d* a# \3 G3 g; \7 l/ P
* */
4 F# ?+ d8 S/ N! G
public static function hashImage($src){
1 F' M; k3 b4 r8 i: V
if(!$src){ return false; }
( L0 {, @% C4 m" ]7 B( E% g! Q
+ T8 |- V h G
/*缩小图片尺寸*/
6 |4 i/ d* h4 q
$delta = 8 * self::$rate;
9 B; B. M: F* X: R' g3 l
$img = imageCreateTrueColor($delta,$delta);
6 W5 s5 A3 S/ }7 A- |* [
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
6 q% x6 v) [7 ^* O
" g4 W; a9 Q- U8 Z' X8 [# z
/*计算图片灰阶值*/
$ ~6 E6 `( _, I0 U0 W1 S
$grayArray = array();
3 g, T9 g, i2 s5 p8 J' ~- v
for ($y=0; $y<$delta; $y++){
& a3 _0 b2 x9 R2 h L
for ($x=0; $x<$delta; $x++){
2 ^+ a9 Y4 q" K6 v% ^+ y
$rgb = imagecolorat($img,$x,$y);
5 j. r4 A0 K t0 ^5 [9 t3 f
$col = imagecolorsforindex($img, $rgb);
, Y7 l* q* Z$ c. f0 e
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
1 n/ e. |, u X$ {. A+ ]
( g9 i& V" |) g2 Z4 `/ H# |
$grayArray[] = $gray;
. l2 k, M" Z/ x
}
9 l2 @! u" }) c1 o& V5 g
}
6 g. x9 \3 x( i5 ]
imagedestroy($img);
0 O( c8 }2 Z0 F' f9 u! ^- x; I$ d
' B# o* V# f* t& r2 f2 S
/*计算所有像素的灰阶平均值*/
+ _2 [3 R1 |! p: a$ X4 P6 J) \
$average = array_sum($grayArray)/count($grayArray);
' G1 s: a7 V/ O. t+ N7 ~4 a) [1 }2 I+ i
8 e3 u/ a9 ?& ?
/*计算 hash 值*/
: ?+ t2 q- R8 t) c9 ?! j x
$hashStr = '';
( u3 N' G! X& g: p0 f$ [
foreach ($grayArray as $gray){
& A* _/ R8 H9 l, m$ d) _
$hashStr .= ($gray>=$average) ? '1' : '0';
/ i( d7 y: G s+ t& Y
}
8 ~3 [) W# |! J
- H9 N) ^' P" e: m z9 k8 Z
return $hashStr;
$ {9 j; n/ t3 K6 F$ ^1 i% k
}
: T9 A* a8 @& d2 C! G
/ [: _+ j* O5 x# X- l' J4 x2 {* V
% K8 n0 j1 L( ^. v4 b% |
/**hash 图片文件
6 `: t# [1 u8 W. B* j& R
* @param string $filePath 文件地址路径
# u( d7 z T: G% z. U F
* @return string 图片 hash 值,失败则是 false
/ y: O0 @/ N6 u
* */
* w2 D; u/ w8 Z8 ], @/ v
public static function hashImageFile($filePath){
1 D: P$ j* J, `9 B6 ~) z. x
$src = self::createImage($filePath);
8 |4 S% {+ W2 Q9 j/ h0 @
$hashStr = self::hashImage($src);
- |- @ L. i# |* M, b
imagedestroy($src);
- [; R5 ]+ x& G; z3 N
; ]) r) \0 g7 `9 R
return $hashStr;
& H! Y- {8 B9 z2 s7 G% l# c
}
$ L! F6 _: L. i: B$ N" @$ b! t
8 Z: Z1 P- i8 R9 n! }! u
- T! J- |. F ]/ L
/**比较两个 hash 值,是不是相似
7 r5 d+ R: q% q7 `" {! p/ r1 q- \
* @param string $aHash A图片的 hash 值
+ c# [7 E" t P1 c: f5 W& x" H
* @param string $bHash B图片的 hash 值
: i+ T/ c6 `# ^) c9 j3 g
* @return bool 当图片相似则传递 true,否则是 false
2 Y9 B( Z' ~# Z/ y$ [2 ?
* */
) @" U5 p( e) P- P! M F2 J
public static function isHashSimilar($aHash, $bHash){
0 q9 _/ g4 f* [/ S. ?" c
$aL = strlen($aHash); $bL = strlen($bHash);
" O$ l: Z/ [. A8 h3 f/ W8 Y
if ($aL !== $bL){ return false; }
" Z1 I5 N. H R
& ~- }/ V: W0 X
/*计算容许落差的数量*/
0 a" E2 y- \/ U% g, A1 Y
$allowGap = $aL*(100-self::$similarity)/100;
: c$ ^, G# I+ r1 d
) n) y# h1 k3 z/ c
/*计算两个 hash 值的汉明距离*/
- F3 G6 i i' q( G
$distance = 0;
5 `: h4 [* g/ q" F5 G+ ?4 c/ `
for($i=0; $i<$aL; $i++){
9 x3 S1 t. a! q r9 W6 G
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
8 P% n2 ]7 H8 u
}
P: ]$ ~( |/ |/ L D+ k
, E: i! U% j. k# t$ E/ ?
return ($distance<=$allowGap) ? true : false;
& x; i& f, ~9 M6 E
}
( X6 g8 {& p5 [0 P
( v. S2 d2 Z/ ?# X' {. V8 ?% I* T
/ o1 t# @" z* f: ~/ T) m
/**比较两个图片文件,是不是相似
0 F6 ?( m- u6 ~: `' j% y. S' H0 E
* @param string $aHash A图片的路径
& P1 Y! c5 r! z+ H: @- {
* @param string $bHash B图片的路径
6 X/ _: k' q. w" h
* @return bool 当图片相似则传递 true,否则是 false
! D+ n, ~! u/ C, M, z+ _ I) v
* */
& F. T8 `$ e- V* v, o5 N! { q
public static function isImageFileSimilar($aPath, $bPath){
8 J; _# ]' c7 A$ V& X6 p2 Z, \4 b6 L
$aHash = ImageHash::hashImageFile($aPath);
5 p/ b5 J- o; G7 ?% f) x9 E% S
$bHash = ImageHash::hashImageFile($bPath);
' a6 Q e) s9 |
return ImageHash::isHashSimilar($aHash, $bHash);
7 a9 n+ l1 }" {& {4 K
}
1 s, w4 S: y% s, r' t: M
& K. k8 w" D9 @9 \) r; l
}
, J1 A0 y/ J! }# F ?/ b4 z5 E
复制代码
: w+ S+ D8 g% Y4 M# S, a, ~9 T
+ y3 z+ c, F( o. K) {$ _- O: r( H$ w
欢迎光临 cncml手绘网 (http://bbs.cncml.com/)
Powered by Discuz! X3.2