cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
/ \! X( `% J0 K
9 j/ }0 E: G3 c1 m( c n
4 K; |: X; f" {. k. u' _
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
+ v+ z2 l% ~9 H0 }( j
<?php
, U+ ^- O Y: L3 @" T2 ~# G( Y+ w
/**
2 M; u: _* o1 M3 ~6 J% m
* 图片相似度比较
0 o: y# G: `* A2 u# x
*
8 _3 m; ?" d/ r+ u
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
* d; j% y G* }: O
* @author jax.hu
( Y4 g, B1 s! B7 F# L
*
# E& p) `) A: c* V
* <code>
! B4 X& x$ X: t% {2 b
* //Sample_1
: W2 ~. R# [6 J: T% G* I
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
8 }* \; |1 C" }
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
9 ~( T3 J' G7 t
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
; P% P M5 w+ L8 k% v- b
*
$ m6 t4 r4 h+ \9 m' X
* //Sample_2
. J" j% B6 }$ g; S; T0 j9 {, g! w
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
' p0 B% F. g+ U! [9 ^, M4 O1 Y& X2 R
* </code>
5 i# _* I# F$ ?# e. R
*/
" T( P; S% K& v3 r3 K% Z
! a& g; ~9 F7 w8 M" F/ m
class ImageHash {
3 E( S$ |* u+ I* \- T v
, e/ D7 o/ _. ~5 G$ ?6 S3 D
/**取样倍率 1~10
1 m) N( i" s6 ?3 f! F
* @access public
& O: J- S) C$ u
* @staticvar int
9 }+ D; b6 @6 Q* k1 J. e
* */
$ b' w# Z7 f/ X' u
public static $rate = 2;
) c: P* V* R* o6 N
- }2 P' b5 W4 X2 n2 K7 @
/**相似度允许值 0~64
% R1 @& l0 h4 \
* @access public
6 w8 Y! `' {& l+ j5 ~, g6 P
* @staticvar int
' s- J' r# [* ~$ B
* */
+ W8 J) _( o1 g+ f6 f+ V/ Z" u
public static $similarity = 80;
& ]4 H- e0 D4 y; m- D& L P
' R( N- \2 X# q' a- \& Q! M
/**图片类型对应的开启函数
, h S! P3 j& R% |5 r t0 u+ k
* @access private
: p) j0 c: `# d/ I/ v E
* @staticvar string
6 u& Z3 e. u- ^7 k
* */
: l2 T. ?9 ^! d
private static $_createFunc = array(
, `' f7 x9 e, H3 j! _; r
IMAGETYPE_GIF =>'imageCreateFromGIF',
& ?+ ~- _% ?# D& c0 |& n) k
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
" E6 e4 K# \% N; E/ R
IMAGETYPE_PNG =>'imageCreateFromPNG',
" u0 ~" [! V6 e$ G/ E
IMAGETYPE_BMP =>'imageCreateFromBMP',
7 M, P- C1 S2 O4 L5 ?- S) o
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
' w) z, [) [ e# Y# A+ G
IMAGETYPE_XBM =>'imageCreateFromXBM',
$ z: @6 P% Z7 L& T4 i9 J) q
);
7 ~% T' [+ Q$ d9 t) X* f
; u/ {8 \$ I& ` b+ |% Z, f8 F
, G! M: M# b0 A6 ^
/**从文件建立图片
2 |$ P2 v) e/ v
* @param string $filePath 文件地址路径
' a/ B$ O* U4 j
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
( Q4 m3 F6 {" O( O9 Q; Q9 f
* */
0 q+ V \& y! ~- ]
public static function createImage($filePath){
# |. P5 }% h( e9 m
if(!file_exists($filePath)){ return false; }
2 n3 D, g1 h4 V9 E: u, \( N
* V k" C, F! }9 @
/*判断文件类型是否可以开启*/
# f# a" L8 F/ t2 H8 T
$type = exif_imagetype($filePath);
C2 G) Y3 r3 y. {' w
if(!array_key_exists($type,self::$_createFunc)){ return false; }
8 T3 V, K, }# j) i g- i2 E6 {
9 t' w, U: q8 |2 L/ @: I. d7 S
$func = self::$_createFunc[$type];
$ B9 C( p6 Q! X, m; s0 \. l
if(!function_exists($func)){ return false; }
4 X9 p2 J( D' L: c" U% i
0 R8 n; `5 F% M j1 B9 P' w
return $func($filePath);
, v* ~3 K1 ~0 q: z# L
}
% n2 k7 a" k! C* w, ^
3 `$ D, [0 F1 }( c, t* O( g
. Q4 [, X5 I, R/ [5 l
/**hash 图片
9 k) I7 z, F( N+ \8 R. W* y0 W- _) u2 t, u
* @param resource $src 图片 resource ID
* K! u ~' G8 T+ Y. q( ~6 R
* @return string 图片 hash 值,失败则是 false
& E6 L, C6 j9 A( T( D. N
* */
6 V- ~7 n' @& o: m( l9 ^
public static function hashImage($src){
# ~7 ^8 Y2 B4 H1 `5 J! B/ e ?
if(!$src){ return false; }
2 U0 o6 f# I- w
4 E+ T+ e0 e) I3 }2 C, X1 q
/*缩小图片尺寸*/
* _/ I# X1 P9 N2 k( Q; ^7 [1 g
$delta = 8 * self::$rate;
+ c# \; C" O* F0 X; E* w5 A
$img = imageCreateTrueColor($delta,$delta);
7 o( t1 }& D; j
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
: f* X9 S, w0 Z% q+ p
7 j+ O2 e* Y* |6 W% S
/*计算图片灰阶值*/
) Y0 P( Q' J2 ?+ b# f P
$grayArray = array();
% g8 ]& U0 k0 ^! m& E" C
for ($y=0; $y<$delta; $y++){
) ^3 d% D7 p: {2 F- a7 E$ T
for ($x=0; $x<$delta; $x++){
- C8 P2 Z) G- n \4 h
$rgb = imagecolorat($img,$x,$y);
- h4 S# i* Y3 G9 K
$col = imagecolorsforindex($img, $rgb);
, c6 U. x9 `8 @4 N' {1 R
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
6 |% B* V$ T. Q1 R! e! b2 F
; N1 O0 S e5 |6 y" f1 u' Y; A
$grayArray[] = $gray;
1 ^* Z& a% N8 P1 W0 Q: K% N& p
}
" S! N+ s$ b9 g* s
}
+ W6 R$ v3 ^; s/ q3 V% Q0 J' C
imagedestroy($img);
) ~1 a: C, d+ z+ o- S, ~3 s2 W
$ f1 s7 i3 H) J7 x0 I2 _
/*计算所有像素的灰阶平均值*/
' @/ p" K8 U) a* [: C" Z o
$average = array_sum($grayArray)/count($grayArray);
+ x% @, D3 [0 |7 b7 z5 p) A
. S7 ]# j v! s. S* Q4 O
/*计算 hash 值*/
+ g/ a2 v* P9 N
$hashStr = '';
* B. h& e1 K5 C- V$ u7 N
foreach ($grayArray as $gray){
, D% C2 }: S# t- F/ Q* g7 I; u% E
$hashStr .= ($gray>=$average) ? '1' : '0';
j2 ~8 R: x1 d7 k# E' i/ b7 j
}
3 g" r7 [7 l6 g
. h1 e% L4 M7 v0 L6 ?- J( M# Q/ N
return $hashStr;
; o' i( i& ` l6 ^
}
, z6 }7 P2 @9 _# y( B
& F1 H1 N; Y- q N1 s8 u- M% P |
/ b- Z8 ^. U+ E2 Y2 z& L; ~
/**hash 图片文件
: `$ f$ K3 v e6 W: k
* @param string $filePath 文件地址路径
4 k4 k* F2 X9 \, i, E) K
* @return string 图片 hash 值,失败则是 false
8 b# s" n8 Y% S" m+ \
* */
/ ?2 d. L) s; y( V X' A
public static function hashImageFile($filePath){
& I7 f: I' |! Q7 O* J
$src = self::createImage($filePath);
2 v7 y6 @! K. l" H
$hashStr = self::hashImage($src);
8 ?' c% B b3 }. s# S f) p) C7 ^
imagedestroy($src);
2 T& v* C; Q% F/ o) v1 G
8 N; o8 {8 X* V' K
return $hashStr;
& \/ Z8 l3 a1 `( X e" t
}
& O5 q8 [* a& D: ?
' e* F7 }) ` C/ ]( ^8 ?7 S! R8 w6 ]
3 {% h1 J+ \8 J! m( {' G
/**比较两个 hash 值,是不是相似
! A- T$ F f' p: S) _4 q9 P
* @param string $aHash A图片的 hash 值
/ }9 V) z, |) H {, S7 H
* @param string $bHash B图片的 hash 值
) m3 z3 p0 ?6 T0 p! c
* @return bool 当图片相似则传递 true,否则是 false
, Y- j( b( M, K4 o! L8 F$ a; m
* */
4 ]" g) J! b; p4 v
public static function isHashSimilar($aHash, $bHash){
4 \8 I: \4 R* V4 x- k
$aL = strlen($aHash); $bL = strlen($bHash);
( O) K! \! S' \
if ($aL !== $bL){ return false; }
5 _& ]9 K5 M' r, F d* K
/ O3 v: A' [4 J9 ?, w0 l( @8 C
/*计算容许落差的数量*/
. }$ U( c. p. I! C- H$ \5 {
$allowGap = $aL*(100-self::$similarity)/100;
8 i$ \; N' w+ m. \) j. y& s2 e
3 o' Z$ ?9 C* T1 N6 r) {. ^
/*计算两个 hash 值的汉明距离*/
! ?- t% Q$ N% N! k
$distance = 0;
! X5 r m$ B" o" H- q: Z. P- N
for($i=0; $i<$aL; $i++){
# x: b8 G, y9 Q- }
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
, ]3 D3 K$ v8 H
}
0 V7 a$ i; b9 l
( v5 x; E) Y; V, I- I; r, R& v
return ($distance<=$allowGap) ? true : false;
: F- \# w+ f7 H# K' O M
}
# G6 |0 W6 |# }2 Q1 R
! Y& p8 s9 E$ w0 h
% q+ Q# P( b8 {4 [9 W
/**比较两个图片文件,是不是相似
6 i: M1 O' f- r( \+ Q
* @param string $aHash A图片的路径
6 J% l5 S( Y x# x8 f+ ]" t
* @param string $bHash B图片的路径
8 I0 n9 [4 m/ Y% i( n
* @return bool 当图片相似则传递 true,否则是 false
( g/ e( v) K8 T6 \5 u; P4 @8 N
* */
' h& \ }6 F/ A' f1 d# B0 e4 ^2 S
public static function isImageFileSimilar($aPath, $bPath){
0 a) y: O+ l% _- [. ~% {
$aHash = ImageHash::hashImageFile($aPath);
3 i- A$ C" w- o% X2 K& o4 \* d9 @
$bHash = ImageHash::hashImageFile($bPath);
6 T* j) b! E7 u% M' @# M% M
return ImageHash::isHashSimilar($aHash, $bHash);
& d0 w* ?) }9 `' u% U8 K
}
' M' ]" h% Z6 N! u
! k! n; v- i) E7 {
}
$ ]& ^ A4 a. G0 k3 j
复制代码
y9 |+ a. N( t$ t- H8 b' c. h- k
# Z; u% M% B; p0 d; y9 n: U' b
欢迎光临 cncml手绘网 (http://www.cncml.com/)
Powered by Discuz! X3.2