cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
r+ B& E$ O: W% F! P6 [7 n. I
/ e, Z) H" l; |3 k. q* u7 i$ p
- \6 {* d) P3 p5 }4 g( I# n) P9 D/ e8 U# Y
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
7 ^ B9 h. X) r
<?php
: Q, C/ V$ O$ _ H
/**
' E) F6 d5 ]1 D# P$ o! S; A6 M
* 图片相似度比较
9 J q' a S; e
*
5 o: k7 R( Z4 q% B; X$ {3 f6 Y
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
5 X- U, U( R" ^4 }% M- r4 L
* @author jax.hu
: U$ t3 f* T7 X6 i! g0 z1 E Z
*
n" x/ A- N/ v) N# N c' K
* <code>
7 S. _1 O6 B f: C% j
* //Sample_1
1 v, V1 K2 O3 ~9 s/ W+ h0 d
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
e7 C% T% t7 x4 g0 X
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
) ^$ L+ q& Q. d/ _6 M2 m
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
1 o h0 `5 ~) b, B/ H
*
# f5 ?' L. Z8 T8 Z2 T
* //Sample_2
- J( p' c& x6 j2 x$ n
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
' }4 U9 j: k6 @9 K. h
* </code>
; ^0 ]. P( u+ ~- x4 x: O/ y* L
*/
4 ?+ H; j6 _! ^
6 g$ g: P( S7 A* D5 K% c' n
class ImageHash {
+ J# k" {( k6 e
+ k( _/ ~1 L& ]2 G
/**取样倍率 1~10
! I: \8 u9 C ^1 v
* @access public
5 h$ @2 P: Y4 o0 \1 e4 I
* @staticvar int
u" w& F$ P" f
* */
0 Z6 M# h' E6 t4 U
public static $rate = 2;
D0 G: j/ [# M4 L
( V/ s# m) Z# J/ o% z
/**相似度允许值 0~64
0 p4 j# U X2 r, R9 V
* @access public
+ p1 E9 Y6 h$ d( P
* @staticvar int
3 m+ r. P) s0 U' ~2 E
* */
: G2 s9 y* y" z% \1 {; n, z6 I3 l6 Z
public static $similarity = 80;
# i& S) l9 S( ~7 P6 T& V0 w' ?
! ~+ u8 D. ?" V2 m! c
/**图片类型对应的开启函数
' j9 p4 {4 l3 R4 r- R
* @access private
$ H/ {7 H; I9 _5 h1 j9 \+ h
* @staticvar string
9 X8 L( }5 ^/ _) i6 G
* */
/ ?7 R7 p3 r& M6 b2 l
private static $_createFunc = array(
9 p' ]: z; D0 F7 F, K9 v
IMAGETYPE_GIF =>'imageCreateFromGIF',
; h! u6 d' [3 ]% c. w2 i5 q
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
" m, l7 U- B3 i, Z5 K
IMAGETYPE_PNG =>'imageCreateFromPNG',
. v2 V! ]/ v1 k& d: _' i
IMAGETYPE_BMP =>'imageCreateFromBMP',
& H3 Y" m- g, B3 v" y
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
7 e2 p/ {0 q: ~
IMAGETYPE_XBM =>'imageCreateFromXBM',
' ?% I7 R( n% U9 _
);
( Q+ f$ u0 c, Y) \
( J& q4 k1 |, f% S6 ?; J
! h5 U0 |- a. u* A, f+ z. ~
/**从文件建立图片
* x9 f; [# w; o1 o( D; Q, r. _
* @param string $filePath 文件地址路径
; q3 |( R' w' J2 u
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
" c/ q4 E9 R# {5 \& P/ R9 F
* */
# y4 m' j2 ^0 x/ j+ e: F& g
public static function createImage($filePath){
0 G7 C. F( D. M5 e
if(!file_exists($filePath)){ return false; }
8 D0 n7 u! w, s5 K$ W: r2 l
/ h1 A2 N' [4 T- a" }! H9 |( g! Y1 ]1 v6 m
/*判断文件类型是否可以开启*/
' q$ _% Y4 K6 d0 W5 j5 L9 h
$type = exif_imagetype($filePath);
) s% }, a% X: ?# M8 `
if(!array_key_exists($type,self::$_createFunc)){ return false; }
3 H" C* g- M+ X+ G( D* ?6 I
4 Z' [2 k8 x* {: A0 m
$func = self::$_createFunc[$type];
$ @8 i5 ^6 S9 y" p1 ?6 @% I8 v% \
if(!function_exists($func)){ return false; }
! N0 j2 x8 ^2 {2 m. }$ C
2 m% D( c! g/ |
return $func($filePath);
7 z7 a' ~! Y* v
}
4 S/ z& I) L" }
4 k" Y. P( K- ~. H
; [+ t+ G5 T# j) X2 k
/**hash 图片
) R f/ {2 a7 m7 k
* @param resource $src 图片 resource ID
! j/ V# }% n& }: _. ] e2 ]
* @return string 图片 hash 值,失败则是 false
( M, b9 ?' i! x G$ A, T& z
* */
* u; i7 j; t1 S+ ~
public static function hashImage($src){
5 ]6 j, E+ j ?2 [" M, X$ p& a; |
if(!$src){ return false; }
# Y: ?, Q' D6 f4 j4 c N# Y+ D
o, U9 f: \/ z& B1 J' g- g
/*缩小图片尺寸*/
" b7 R7 e: Z3 \3 e) a) e$ i
$delta = 8 * self::$rate;
( S: }' {4 v+ c: k3 h
$img = imageCreateTrueColor($delta,$delta);
2 Z. s3 i" W% ?6 S
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
7 A% O# s- t9 q4 p' K* A" K
) M+ s% A3 }) y% u
/*计算图片灰阶值*/
3 ~' X; m: ~5 h* ~
$grayArray = array();
. p0 Z; P6 y0 f o0 l
for ($y=0; $y<$delta; $y++){
6 f1 l$ c# {" j, j) q- ]8 S1 T
for ($x=0; $x<$delta; $x++){
( p3 P1 N8 U3 T6 V/ ~9 O- b
$rgb = imagecolorat($img,$x,$y);
- e/ z$ l1 W, P7 i
$col = imagecolorsforindex($img, $rgb);
) |* _1 d( Q& N
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
& W' @) ^ c) |9 C
5 o" R. J9 @$ y0 G' x: p1 f
$grayArray[] = $gray;
$ j4 p% q- h/ R0 p1 ^
}
* m1 \5 A4 V, } A: [
}
( I* G1 l! {' Z" @6 y/ h
imagedestroy($img);
! ^& R, G& Y5 |' K
. n* x0 ?% b, A& ]" @( u
/*计算所有像素的灰阶平均值*/
. E0 u8 b4 |7 G3 H7 E+ M! B
$average = array_sum($grayArray)/count($grayArray);
! N1 ^ s7 P* B4 n3 X! O
; H5 L3 e$ Z' E( a, b
/*计算 hash 值*/
% h a+ I" b6 }- i# X: r$ k k5 p
$hashStr = '';
4 k8 o/ N N' k/ v7 F
foreach ($grayArray as $gray){
' U# R' s2 Z, ~- h5 R
$hashStr .= ($gray>=$average) ? '1' : '0';
& o+ W1 C/ t* i8 a% ]; Z. e( n
}
- o) ?9 Q1 x& r# \( q/ e% ^. n
) T. Z! ` t Q' r8 L
return $hashStr;
/ d. J, v" \4 O5 u& R% y* s
}
m: X4 |" k; ]" [& N
9 F. Z) }+ n, ~1 o
9 U# L2 P$ w( R3 i. U
/**hash 图片文件
0 a9 t' H( e$ e
* @param string $filePath 文件地址路径
6 ~) c" c0 V3 b+ S
* @return string 图片 hash 值,失败则是 false
& s2 ]7 S7 w; E
* */
+ U/ e- h; Q! x/ Q& q6 n* p- f* r+ r I
public static function hashImageFile($filePath){
& b5 { N7 J- i6 [$ R' K
$src = self::createImage($filePath);
" L7 i7 U0 T N6 F& A7 }
$hashStr = self::hashImage($src);
. F% D \0 D$ G7 H# R
imagedestroy($src);
& |$ l, o5 X) \! y% x. Y
9 [# W o6 z' \0 q. m Q9 Q0 A
return $hashStr;
' z4 [, T( o1 ]. j! \& N
}
+ N) @) C4 t5 j# Y
" Z# e, M* g. s! ^6 b
+ K! q% o r9 l
/**比较两个 hash 值,是不是相似
7 O( |3 A# F4 W$ n
* @param string $aHash A图片的 hash 值
Y, _1 J9 j# j3 M, J! r1 k' C
* @param string $bHash B图片的 hash 值
7 \" c6 f* ]7 E3 ]
* @return bool 当图片相似则传递 true,否则是 false
+ k. Z3 u4 w0 T6 I3 a, Q
* */
- O+ b9 F. M0 c: Y: Q/ j w
public static function isHashSimilar($aHash, $bHash){
1 c! K7 T, N8 U
$aL = strlen($aHash); $bL = strlen($bHash);
* Q. r/ U, a9 z2 l ^4 S1 T
if ($aL !== $bL){ return false; }
5 R& |8 s: n! e& O" `* } H
$ G1 k0 ]) o" Q2 N% m+ i7 t
/*计算容许落差的数量*/
6 _; r/ s! L0 k* C; k2 w0 |
$allowGap = $aL*(100-self::$similarity)/100;
! G6 O) J) O: a( r/ s m
; U6 W" q' h% A% U8 x
/*计算两个 hash 值的汉明距离*/
4 @/ u/ i( W1 \: j
$distance = 0;
- s! m& @2 U( {% h V/ z9 Y2 [% ^
for($i=0; $i<$aL; $i++){
6 ]# O/ p4 B' c/ F# |
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
& L3 N, ?7 B6 `: {! @+ z' J
}
[ U" k: c$ O4 a9 j
1 \! U/ E$ n/ W2 O
return ($distance<=$allowGap) ? true : false;
% v$ `( e% t, P2 c( A% J" q3 J
}
, F- e. n6 C, p! l0 {* G
, b% S- k5 E6 a2 ? A$ Y
! e1 H# i V$ i- l0 u
/**比较两个图片文件,是不是相似
3 x" E$ I9 A* y; {* n; M" n. [8 L
* @param string $aHash A图片的路径
* }8 J% s8 D, f7 V
* @param string $bHash B图片的路径
- u; I3 X2 f$ a( \0 f2 C' S' v8 E
* @return bool 当图片相似则传递 true,否则是 false
( ]! k& N3 l9 ?
* */
# u: ?" R: u5 }5 S; m
public static function isImageFileSimilar($aPath, $bPath){
; h: i) \' V6 I3 V! c! _
$aHash = ImageHash::hashImageFile($aPath);
( r; N2 Z) \9 s1 s7 P' ?. g
$bHash = ImageHash::hashImageFile($bPath);
- a9 V) e% B- ^* J
return ImageHash::isHashSimilar($aHash, $bHash);
# S) _9 d4 x1 ^+ a% e1 u
}
; @# D9 d8 `% R, K. F* G) C* k: Y! l+ l& D
! d# A, L' O( {! Y o4 s3 R! [
}
# [) \3 C& C+ L! L. t0 ^) c1 \
复制代码
( d. p8 D: {5 V" Z8 ]/ I0 }; K% Y/ Z8 [
& A7 h; i3 Z' R6 h; n
欢迎光临 cncml手绘网 (http://bbs.cncml.com/)
Powered by Discuz! X3.2