cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
0 L. v c: E0 U" q {+ M
, W* o7 ^: B: e$ K- M. o
1 u' l! p) J Y, I! w
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
+ m4 l7 a2 w2 q2 Y0 \
<?php
) ~. r! ~7 g$ }. ] l' t
/**
7 A3 B% z9 B( A
* 图片相似度比较
- Q$ E6 C6 ?+ P. y
*
4 a! T* L1 N2 Z r
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
. a3 f# ]0 V) Q" m! y: K
* @author jax.hu
; _: q0 w" ^0 g) b8 g. r
*
8 l, D1 X- W+ ~' o% N' [5 x' ^/ h
* <code>
' P" Z, B; D: }
* //Sample_1
! u4 I* L" v0 {$ T3 t
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
+ h* J3 S* {9 H1 e
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
" g. k$ Y- y2 W) N, z4 k
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
6 o8 |; m* F" k* T% ^$ g& Q( [
*
8 u ~3 f2 E3 k4 s0 C3 E
* //Sample_2
6 O: I( i( I( E% a! C* n& O U6 W
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
9 f$ |& C j4 g. B" e! e! I, |
* </code>
4 f3 O! \9 S' |, i K
*/
" N. d0 E2 l% g5 Q' [
) J7 x8 J0 m( o9 l0 N0 G% ]; K: v, L
class ImageHash {
' a5 X4 b7 G. ^! }3 p4 A
- `1 a+ `% @4 u
/**取样倍率 1~10
3 \4 Y# Q! d3 Y2 Y5 f$ d& V
* @access public
1 E; q6 t6 I$ H6 D! v7 x9 m6 y1 U
* @staticvar int
6 o1 ~7 u; E: P d; |7 {
* */
1 I+ \' \+ d r) }5 M( y) D* k' }
public static $rate = 2;
0 x- ^- u$ r7 t/ @
$ p7 Y0 y: A9 v) } M! q8 }
/**相似度允许值 0~64
" P; ~5 L9 L; C& I! D6 G
* @access public
* c1 m! r# ?+ ?6 o4 B
* @staticvar int
: ]* a" u# H: s( [
* */
7 t, S! [2 J% ]) b, L
public static $similarity = 80;
' u* y3 M" ?/ I3 X* f
7 o0 A" E1 o( C
/**图片类型对应的开启函数
`* ?! L! |. Q; q2 P( e
* @access private
2 X# u! Y2 o) U
* @staticvar string
3 S9 \, H# I {
* */
' b3 P$ F/ m/ ^) S: y( Q
private static $_createFunc = array(
& {' I# X1 n! a9 |6 p
IMAGETYPE_GIF =>'imageCreateFromGIF',
7 ^+ j. g. t- u' P! Y
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
% C$ x, ?2 d% o! ^# f
IMAGETYPE_PNG =>'imageCreateFromPNG',
5 l) r( V1 a, ~5 l
IMAGETYPE_BMP =>'imageCreateFromBMP',
4 k+ c u( @: t, l( P4 q: F& k! ]
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
# C# z' D+ x7 p5 E: a# S# c
IMAGETYPE_XBM =>'imageCreateFromXBM',
+ C* Y. Z) q1 F/ r0 r0 i; i3 t/ Z6 A) N
);
: u; z1 i- e5 F: n4 C9 k
V3 o% n% |8 u& k! u
# `8 g4 K, E$ I6 g: k+ \3 S
/**从文件建立图片
- c2 A% E5 b/ N8 _+ ?4 Z
* @param string $filePath 文件地址路径
: { K5 s: Y- q/ f5 [
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
1 L# W4 `" J/ j! M, K) e
* */
0 k' s4 [1 T" {3 L; i; T
public static function createImage($filePath){
2 @. U1 h7 b4 p( B
if(!file_exists($filePath)){ return false; }
1 P) k6 F' ]* h, |
: s0 m6 _& I; M) G, t4 i8 J9 d, @0 ?
/*判断文件类型是否可以开启*/
% X' [8 m! ]5 L4 L0 m7 s( j
$type = exif_imagetype($filePath);
5 y( S/ q+ F3 E8 h# g6 t
if(!array_key_exists($type,self::$_createFunc)){ return false; }
/ E1 C, z6 j2 }1 u
. Y) K' s9 m3 U; A7 W
$func = self::$_createFunc[$type];
' v& m8 C1 p n# ?
if(!function_exists($func)){ return false; }
: ^; [0 ?% u: j* M5 A
|+ k: U" G) P5 d
return $func($filePath);
3 s1 q. O' c3 o
}
' F* W" n9 `8 ?5 K9 f$ Y, R& D
- g' K& K4 Y: ]% t. n6 r
7 R$ @2 H# v8 u; q
/**hash 图片
( C3 P% j- h: u6 m
* @param resource $src 图片 resource ID
! M0 F' D; c; W f2 d% _
* @return string 图片 hash 值,失败则是 false
, d" w4 Z; j" k% S4 w$ X2 d
* */
- u" U+ J- F1 Y& z
public static function hashImage($src){
+ [. [% |8 `6 K3 i1 i( k
if(!$src){ return false; }
# k, j' b9 X# f2 D4 e! ]$ l
0 y! @3 ^5 H0 W1 q. W6 m/ _8 [
/*缩小图片尺寸*/
0 ]9 ^3 f+ ?5 [9 H" @4 G# D
$delta = 8 * self::$rate;
' ]; o6 {5 _+ H4 R. z7 `
$img = imageCreateTrueColor($delta,$delta);
3 q; i& b: x, ?2 `+ G0 x
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
! i5 i6 G) B: }" k1 ^- s
6 r. w( Z( d: i( q, L
/*计算图片灰阶值*/
; I" m8 @$ ` t* I; i8 F. m
$grayArray = array();
4 b$ k: W/ B( N( a
for ($y=0; $y<$delta; $y++){
! k2 H, W/ F d7 O
for ($x=0; $x<$delta; $x++){
7 I# b0 l. W# R) j: t
$rgb = imagecolorat($img,$x,$y);
, _4 ^( g6 {! g9 l) h
$col = imagecolorsforindex($img, $rgb);
. N* D. o2 ~' t2 X
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
0 F! Q3 p8 a+ _: c' Z
' d- h/ |3 F5 p
$grayArray[] = $gray;
9 K8 x7 t* h6 g" ^1 j" T# v
}
* W9 g: i" @# U$ Q' O$ h
}
k7 W: W$ x, u
imagedestroy($img);
6 V$ Z2 R8 l$ o% }( [/ w: _
$ Y( M a5 E3 S) K* ~6 {
/*计算所有像素的灰阶平均值*/
3 {2 K P8 X7 [. f( J
$average = array_sum($grayArray)/count($grayArray);
, {% L$ c) }% y- g e5 m. ?4 ^% x
9 A0 r7 h, v1 }' d9 {0 z& H
/*计算 hash 值*/
/ ^( s2 m' T+ \- X
$hashStr = '';
/ l9 ~7 r8 x* J: n
foreach ($grayArray as $gray){
. k8 _) L9 d2 w1 v" c& u% V- m
$hashStr .= ($gray>=$average) ? '1' : '0';
1 @$ L C% |- t2 ~* v
}
6 E+ X( |/ l) @( t) u
% Q; o( Y- L: r7 g8 q8 |. K
return $hashStr;
/ `9 W, x9 Z% J; M! c
}
6 F4 E6 c% f! ^9 P9 V+ o& q
3 y' s7 F2 I: e9 Q8 Z' P
+ a; i0 I9 s7 w C
/**hash 图片文件
" J9 o6 `, @" H: h
* @param string $filePath 文件地址路径
) D2 n/ J6 u- u$ ]! X( Q
* @return string 图片 hash 值,失败则是 false
z. v! _% R7 K; [6 A, F, G$ q
* */
# E9 M n4 q9 j. F! a5 _
public static function hashImageFile($filePath){
8 Z( Y1 {; S8 v d
$src = self::createImage($filePath);
% p; ?4 P( _+ ?6 V1 i
$hashStr = self::hashImage($src);
9 m5 z0 k* i4 x6 q- Y7 C* }: [
imagedestroy($src);
/ z6 k6 d; [* w4 ~9 U. a ]" y
3 @3 i0 C2 I. y6 a6 H; S
return $hashStr;
6 V& l; M2 `# E$ V# l0 q. j: D
}
" n" Y( Y7 U) n, I* Y7 K7 q
) L6 v: Y; {# E/ E: O( \
* n) b' ? P8 X6 N' j
/**比较两个 hash 值,是不是相似
) Y( [& D% V- r0 F! E( L
* @param string $aHash A图片的 hash 值
+ G8 R8 q5 h* B; p3 R
* @param string $bHash B图片的 hash 值
5 ^ B5 m( g7 v+ ?) R& [( d
* @return bool 当图片相似则传递 true,否则是 false
, O$ A& U5 r8 j9 {! z/ s
* */
2 u) Q4 z5 b# w. O3 H2 b5 G" e$ e
public static function isHashSimilar($aHash, $bHash){
% \- O( `- b9 M, Z# D, e
$aL = strlen($aHash); $bL = strlen($bHash);
' {0 z" x9 P. X0 }7 a) H
if ($aL !== $bL){ return false; }
% V. c3 r! ~/ ~- C. z
; H( u; n7 s' e
/*计算容许落差的数量*/
8 }8 W* [" p* C* e
$allowGap = $aL*(100-self::$similarity)/100;
1 Z& Z; ]' q4 k
9 v1 U. W. u5 ?5 C. c' K0 r
/*计算两个 hash 值的汉明距离*/
! S; y+ R9 ]" F5 \5 r
$distance = 0;
5 a( I6 e. h& f$ E
for($i=0; $i<$aL; $i++){
2 e9 T2 _: e2 f l& k8 C* n
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
: @, g6 M" N: b) Z- R
}
& m! V4 n- w* p3 l9 Z
, X7 S6 \/ X0 x. l7 {5 S; s1 @! c
return ($distance<=$allowGap) ? true : false;
( V( L& P$ j N/ | B
}
) k" m7 X3 D! z ^9 s6 z3 F
! X( R! U& a, h) e4 ~' Y* V; K
# k W' y4 b, o: q! Y0 \
/**比较两个图片文件,是不是相似
; H' o( f* @0 M7 r6 x+ ^
* @param string $aHash A图片的路径
7 f) C, }( {/ O1 m
* @param string $bHash B图片的路径
0 |: Q( R8 v: K
* @return bool 当图片相似则传递 true,否则是 false
; e8 ]2 N* X' v( a! }2 t
* */
# Y6 O' D2 B0 k+ M" R# q. U5 \
public static function isImageFileSimilar($aPath, $bPath){
! o! `3 }" ~5 p& }8 {& R* |9 E! D
$aHash = ImageHash::hashImageFile($aPath);
' K K& |. {6 u& A& O8 \, F
$bHash = ImageHash::hashImageFile($bPath);
; _4 g& R0 Z$ t9 W: e! E2 F2 E
return ImageHash::isHashSimilar($aHash, $bHash);
( o% o( D6 \' X/ ^3 p6 P
}
+ o6 H) z. M) L
7 w+ J0 m- \- H* a& S% J
}
: e: k g$ _% \( U. t
复制代码
9 ~9 _' x+ V+ m- E! T! x+ K# S, k
% m5 k$ a& o* ]! {( r* d0 |
欢迎光临 cncml手绘网 (http://www.cncml.com/)
Powered by Discuz! X3.2