cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
4 }7 N. m" \! P- J7 ]% H! G" M9 N* C" F1 t
9 I5 {* v( ?5 N- E3 T& \
- N5 d K+ W5 b# p* t, A
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
% E# e2 }2 `) B
<?php
. `; K0 S0 ^! T' m* g
/**
' l+ O( E- _. t4 h$ M$ C
* 图片相似度比较
1 |7 {7 R4 d; X
*
) U5 Y3 O) g$ I ~
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
2 z3 @* t* X) J& T: z( K% H/ c
* @author jax.hu
" _/ \; C+ ^# Q9 O: J
*
4 Y- I9 `7 M: O8 |/ g; k; j
* <code>
' q6 l$ _# x' I2 x
* //Sample_1
7 s5 B# t# R1 Y6 i+ Z4 H- Z6 P
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
9 F r: c# N1 e% b$ y: c: N0 g
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
' o; Q, G" O2 H
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
' V x( t2 L. `7 t
*
0 ^5 U6 ?, j1 }8 Q2 L9 P/ c
* //Sample_2
! t# d+ N4 t! _# t( b+ a
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
# Y1 ]6 ?( p2 x) O
* </code>
/ W3 y- W: |' H- Y* x, P1 n
*/
. n1 A( k7 v1 |; s7 s3 M
/ H3 l" u# Y3 \% N
class ImageHash {
8 j6 g/ b } I' W" w
3 P( G2 H d9 f; ?! v0 a- T
/**取样倍率 1~10
" J0 T: J4 z1 r5 W3 @0 H
* @access public
# \# o9 j) m0 Z: m2 I
* @staticvar int
* `9 \) K' X6 Z7 p8 J& y- R7 f5 T
* */
7 _5 Q' O, e- [- O
public static $rate = 2;
( k) s9 ]1 V' w0 L: Z
' {/ R. l/ d. d8 T/ Q
/**相似度允许值 0~64
$ Z+ Q" n# _0 k! w' @
* @access public
, _, N! V( [% j6 o" _
* @staticvar int
q+ s5 ]* w9 D2 d2 D
* */
' `2 Q* m- ~! V8 `7 b
public static $similarity = 80;
7 M- x/ w8 E% V2 g+ S4 L; L
+ a: F9 C2 f- ^. i* X8 f
/**图片类型对应的开启函数
) R" B! `0 h. D' R) f/ L) N3 A
* @access private
# t$ d9 b! U/ j3 v( Q& l
* @staticvar string
: t" J: L: Q3 o/ h. u, O3 M+ u
* */
% S* T( e' f, u _/ y
private static $_createFunc = array(
! t" v# c9 N2 _9 m/ n8 q
IMAGETYPE_GIF =>'imageCreateFromGIF',
$ W& |, b1 ~& m! d
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
7 d" T# U3 f: M6 j) P# N+ v
IMAGETYPE_PNG =>'imageCreateFromPNG',
* E% w; Y6 P V. t$ t$ H5 ^0 @
IMAGETYPE_BMP =>'imageCreateFromBMP',
- p8 _6 I1 ]% \! [- P- b" C9 U( V( n
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
, A' _1 I. u% n2 h/ Y# X! v
IMAGETYPE_XBM =>'imageCreateFromXBM',
0 x2 m8 k2 h' ^( q# H5 ~5 Q
);
# `: D( T9 q/ ~' N
) q( w9 w) c& i2 c4 z" ?. k) n5 U& ?
! o7 N+ U/ x# \7 i" ]
/**从文件建立图片
- |+ I* r0 M& |% j% w
* @param string $filePath 文件地址路径
4 M( o4 O' S q& G% v
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
: e( F: k( d+ l0 H" C
* */
! @& _5 \. y- a, Z0 f
public static function createImage($filePath){
- ~! { N v# Y% x0 \5 I* ^
if(!file_exists($filePath)){ return false; }
8 I4 z/ p/ D! j' O3 i
4 A' b/ i1 V& Y! x# g6 U
/*判断文件类型是否可以开启*/
6 X( L9 T) i" X( v- [
$type = exif_imagetype($filePath);
+ Y7 j1 Z7 n3 Y
if(!array_key_exists($type,self::$_createFunc)){ return false; }
: C {4 @) m7 m# n) N, ?' U( d
1 J, O8 H: H7 A5 @6 N8 M+ t
$func = self::$_createFunc[$type];
0 h$ U$ {5 Z( l* _3 A9 ^
if(!function_exists($func)){ return false; }
( [1 F7 h, ?! Q: p$ d$ W z, M
* g, B) O0 ~" a7 M4 |8 a
return $func($filePath);
. L: G. K; q$ U9 h1 H @
}
' E3 F" u7 n4 u6 v5 I; B9 H4 m
- f' B: ~* |0 |- T
+ j- r2 U1 D# n) F/ O
/**hash 图片
: C% f& h1 a4 g+ y# v
* @param resource $src 图片 resource ID
# i0 k" I9 S6 N2 s% r/ {5 `6 Y
* @return string 图片 hash 值,失败则是 false
6 L- D4 Q$ c' F c3 d0 W
* */
7 s/ W h& B2 O. Z5 T
public static function hashImage($src){
& p, o' h1 K9 P) z+ I( ^3 |
if(!$src){ return false; }
7 }9 g+ |; f! [; X O, ~# L a
! d! y7 F; c4 ]0 \1 ?" S
/*缩小图片尺寸*/
0 j' P; w. G# Z0 k; U3 V1 W
$delta = 8 * self::$rate;
. ^# q: Y$ ]: d+ r
$img = imageCreateTrueColor($delta,$delta);
; A: S: C9 o% z& v; S# G! @4 ~
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
! t3 q; H5 Q, x6 R2 R# c
' |7 |( g0 b& @* u( y# J, k
/*计算图片灰阶值*/
/ g* a' C3 S/ s/ f
$grayArray = array();
; ` e' V/ X# v, ?& v# p3 ~
for ($y=0; $y<$delta; $y++){
t. b4 N2 |8 v
for ($x=0; $x<$delta; $x++){
; |. n# d+ @" L4 ~2 J, {* A- @
$rgb = imagecolorat($img,$x,$y);
9 F q" |' e, \: M5 T: p
$col = imagecolorsforindex($img, $rgb);
y; H$ y" ?9 {
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
3 U9 g4 T6 f" o, r3 r
& B0 e9 s( G1 Q- _& o8 L/ ^) S
$grayArray[] = $gray;
' u# \+ a1 A) r" y: V
}
% `) D! {5 I/ w6 q/ ]
}
: e: H9 N: V6 y
imagedestroy($img);
3 D# E( G3 X! X# Y$ k* o; ~) M
6 v& f2 f* M6 W. `1 G; m
/*计算所有像素的灰阶平均值*/
% g# o2 o" [; L, w8 Y- R6 Y
$average = array_sum($grayArray)/count($grayArray);
- d# Y# H3 X l l8 E' ^1 z0 N
; k* w- G) R+ \. ^! i1 O. A# c
/*计算 hash 值*/
9 V8 I" k: b8 U R9 X: f# }
$hashStr = '';
0 n# ~- b) J( A. z. H5 p
foreach ($grayArray as $gray){
( z, {0 [9 B% b5 Q
$hashStr .= ($gray>=$average) ? '1' : '0';
7 ^, W# U# ]( N
}
9 a ~$ h# y% d6 Q! C1 }0 A
3 ~9 P. |! R0 p0 y7 P2 X
return $hashStr;
4 t# W. l( ` U( s6 c& N& o$ }
}
4 {, G; ?( {8 J* {
[+ u* W& \% g3 i
8 t6 v2 Z/ ^" S$ q+ l
/**hash 图片文件
9 l1 y" X4 O7 W
* @param string $filePath 文件地址路径
4 c3 D# a+ T% S9 U1 g# { `( Y
* @return string 图片 hash 值,失败则是 false
9 T: D$ `4 i2 k
* */
! D! \6 v* ?# U) G: P! H, M' @$ b
public static function hashImageFile($filePath){
2 Y3 q3 v) g, S
$src = self::createImage($filePath);
% B! B& }' I' t2 z/ E
$hashStr = self::hashImage($src);
H! k4 \/ f+ k
imagedestroy($src);
; p3 W& x4 I7 J9 S2 t3 N
: u% y! x- E/ W/ F$ I8 C3 ^ [
return $hashStr;
+ w# u6 Q6 ]2 G5 ?+ o# ~
}
! s0 \, r/ k1 `8 C
) n' ? S/ G" W1 a! g1 C& c! l
: L: \2 h# L% u) c* u2 m" ~0 f
/**比较两个 hash 值,是不是相似
3 q" ^- {" w/ O2 w5 T# n3 F
* @param string $aHash A图片的 hash 值
- N: ~! i0 m+ l0 E
* @param string $bHash B图片的 hash 值
. b* i0 o5 Q0 W% s2 ^0 t) E$ N
* @return bool 当图片相似则传递 true,否则是 false
1 r8 w9 b& D* V& k
* */
* |$ W( ]* }4 R4 y8 I$ N. }' f; F
public static function isHashSimilar($aHash, $bHash){
% f& p" e$ K) v' U2 n! t* q
$aL = strlen($aHash); $bL = strlen($bHash);
- d+ V. N0 m7 T" w
if ($aL !== $bL){ return false; }
1 J' z8 _3 J4 I B7 g
5 \( c% H( L( |! n( O
/*计算容许落差的数量*/
3 S" t$ E' P1 L3 ~4 ]
$allowGap = $aL*(100-self::$similarity)/100;
/ O6 L5 \6 H: t0 Z" X1 ^
- A+ _6 M W- A6 _
/*计算两个 hash 值的汉明距离*/
* W$ c$ B/ `) A1 [3 r% B
$distance = 0;
( x" ~1 [0 V+ n4 G" U- g
for($i=0; $i<$aL; $i++){
6 P5 o- m! A' J3 I
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
* c; @# t v( |: p: f! R+ i
}
; Y J# v$ ^5 v E, ^7 o0 `
% ] z7 f# u' } E* P- Y
return ($distance<=$allowGap) ? true : false;
. p# R0 W) r0 J3 C+ U8 X6 l, _! w! Z& j7 N
}
# i8 B5 u1 q# C; x' b
' A; W8 }" s. c0 E
0 Z/ _* z1 T( M) v& h! t- ]- s
/**比较两个图片文件,是不是相似
3 S- N& ^' A* f( z; b8 l
* @param string $aHash A图片的路径
( ] h2 K5 Z6 U$ [+ ?
* @param string $bHash B图片的路径
4 j) p& b. i" T3 `
* @return bool 当图片相似则传递 true,否则是 false
- W, l0 S0 [: i) o/ ?/ ~
* */
8 y: m& I% C! K* `
public static function isImageFileSimilar($aPath, $bPath){
6 _9 B8 Q) o2 P, m2 I$ X
$aHash = ImageHash::hashImageFile($aPath);
. @! t' r+ {8 Q- L E+ |
$bHash = ImageHash::hashImageFile($bPath);
7 `5 t4 u$ G! b! N+ H
return ImageHash::isHashSimilar($aHash, $bHash);
( ?: |9 ]: h4 }- v. M8 B6 t
}
; W8 J7 |+ _+ z; T
$ G2 P5 Q$ o: y9 i5 [; }
}
" i2 i3 m9 l" F' }# C% K
复制代码
/ S5 v( c+ D6 [
2 A9 {6 ~! k$ p6 p, u5 t- X
欢迎光临 cncml手绘网 (http://cncml.com/)
Powered by Discuz! X3.2