cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
3 P8 x' ~9 _3 j; u
( `4 w3 x8 F8 W# S
1 Q0 T' E5 `4 E) L1 x
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
( E" z/ q' g" e7 ^6 s* E
<?php
! V0 T& ]0 y2 t+ i2 G
/**
: N$ R) ^% f' t& L. g9 ~, E; T
* 图片相似度比较
$ w( i. }* Q; ?2 ?# r+ M5 f
*
2 ?0 E7 g& m* R
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
' a1 X+ Q8 o+ F. K# p
* @author jax.hu
6 I2 ^' F# e x9 ]1 F1 i
*
1 M% i9 J" n3 _) M: J$ U
* <code>
* c( h, V9 R: f* M/ B
* //Sample_1
, ? c7 g# T, H+ z
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
' u) c& z, f5 e8 o. R, r1 O0 k" l
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
' y3 D" M' A7 L
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
0 I7 s4 e/ f6 G7 Z, l% T: v. v, P2 i
*
, |8 q) P/ ]! K$ F" c( B& c
* //Sample_2
! n" U8 D( Q# T, Q) Y$ F: b2 o
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
& ^5 R: W/ K; A* A) M
* </code>
- j$ }1 }( j: W9 Q* D6 V0 A
*/
8 r$ \) } W) G) ]# g
+ D- x0 y! }0 d* ?$ o" }& `
class ImageHash {
; {& ?/ _+ b' D5 g+ S1 o+ x
) g$ p. L4 n8 r( n, X( @
/**取样倍率 1~10
, U1 e6 j% y# R" ~( s
* @access public
/ \4 m% ^9 `" b$ U" V" J
* @staticvar int
7 i8 Y n' m N5 q7 `0 d- m& b9 ~
* */
3 K: G* {9 }& [
public static $rate = 2;
7 o' g% E r8 v7 [( ^& c
# R4 T/ I( m: D- A3 w
/**相似度允许值 0~64
# S" X( p% g+ O( U( j
* @access public
) y2 ?2 S' I1 e5 M0 @
* @staticvar int
8 \9 M5 I5 r; Q% y; W# K
* */
J; s! h) ?1 {& i3 K4 A8 @1 v
public static $similarity = 80;
& g& v! L9 @2 [% _
& E- m, c- E& V- X$ ?7 m. E
/**图片类型对应的开启函数
8 p. w2 v/ H# y0 c! R1 N
* @access private
' u/ k. Q6 b! G- p R
* @staticvar string
1 s& z }9 D/ n3 K% Q9 X
* */
' e: h4 U0 Q- @, t1 w! o* R
private static $_createFunc = array(
% [6 B4 s" z+ J" d+ h4 i
IMAGETYPE_GIF =>'imageCreateFromGIF',
' I( a: C( q1 U4 N- ^
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
' K8 ` J- {2 a* B8 E* L
IMAGETYPE_PNG =>'imageCreateFromPNG',
1 a& b1 c' k) o! d( n8 w$ i& `
IMAGETYPE_BMP =>'imageCreateFromBMP',
9 T# t% t; g M1 N% u
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
; {3 w6 V. z2 |' z7 t! a
IMAGETYPE_XBM =>'imageCreateFromXBM',
8 U- f5 Z( [" X! f) k L0 y% \$ ]4 v
);
1 y# j2 z6 H. G+ u7 b
& u1 n, q) C. D5 N9 @
1 y* U r- I- m
/**从文件建立图片
9 B& [- P" n4 Y' N6 o
* @param string $filePath 文件地址路径
, y/ l( H M, y7 F: ~. m" G& b. R% o
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
* l g0 y) a" M3 N8 X* o
* */
+ {/ ^& Z$ e; l" o' q
public static function createImage($filePath){
0 a+ W! u$ B+ x0 n
if(!file_exists($filePath)){ return false; }
" _$ ?* x P0 N: q. p6 k! R' {# k
* r+ P' u5 }( S
/*判断文件类型是否可以开启*/
& @$ x: y( g1 N& A
$type = exif_imagetype($filePath);
. D3 T$ S* C" Y# [1 U& P
if(!array_key_exists($type,self::$_createFunc)){ return false; }
2 }+ L4 W3 X; e S+ o
) N# a1 `: W+ e+ \8 B% G3 Q2 R5 g: `# R
$func = self::$_createFunc[$type];
, ?. E. L: F2 r! W+ w: \
if(!function_exists($func)){ return false; }
6 j* v7 a& T! C+ D$ R7 _5 M
0 M/ u7 E6 R* h
return $func($filePath);
/ u, _7 g5 |6 M. V7 |* \
}
7 u2 ^0 E1 }! B ?3 {7 Y
- T" P# `5 T. z* R, \. |
) B" w8 ]8 c# J% g" U
/**hash 图片
! B' J: p |( g- ], D
* @param resource $src 图片 resource ID
# I6 ^5 }' h6 S+ ^$ u9 v
* @return string 图片 hash 值,失败则是 false
6 l- O7 w5 d& H1 e& M' q Y
* */
) A# g& H0 N; c, O$ a1 e7 E
public static function hashImage($src){
: i: T' T6 _4 f+ p& D
if(!$src){ return false; }
% Z! x& m: _+ }0 E8 b) a
7 X @$ g& E8 \. ]
/*缩小图片尺寸*/
" L4 q5 _7 J6 A% A
$delta = 8 * self::$rate;
7 u C1 A+ z. T9 n
$img = imageCreateTrueColor($delta,$delta);
0 ]& K1 S1 G3 a7 E2 G7 h5 N, {
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
) ` P' J) U+ f G: A, B
. d' l$ {* {/ K2 Z7 s
/*计算图片灰阶值*/
8 D6 O% W# Y- E0 _; v# c; E+ V3 Y
$grayArray = array();
6 p3 Y% i1 C( P. W. T; D" j- Q
for ($y=0; $y<$delta; $y++){
0 |% l0 {0 S( Q5 f6 S9 a
for ($x=0; $x<$delta; $x++){
5 ?/ E. a* k4 v2 m1 e
$rgb = imagecolorat($img,$x,$y);
6 a: C# v) k# h9 X
$col = imagecolorsforindex($img, $rgb);
! b/ A6 J. W# z
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
! H' i2 }9 }2 Q# p+ Q/ O
" C$ ?' w. n" q ~
$grayArray[] = $gray;
: L1 X: Z0 c6 z) O! u/ D3 ^3 r
}
& @* J# s. |3 |& L7 q% _) U6 V
}
' e: s8 G6 W3 }
imagedestroy($img);
9 r/ U, k2 A+ l4 Y1 |8 u
; n* A" c; V/ R
/*计算所有像素的灰阶平均值*/
: ^ B. A2 n% |6 a s3 c
$average = array_sum($grayArray)/count($grayArray);
f+ o+ `: m9 H. J8 @9 F+ r
m' c9 R$ U2 D! l
/*计算 hash 值*/
9 X& ]2 U" r9 E9 P; y1 [0 t
$hashStr = '';
: m2 W% t; Z' p0 c
foreach ($grayArray as $gray){
) s* Y5 K& C) n3 l3 t/ s! v
$hashStr .= ($gray>=$average) ? '1' : '0';
3 o9 E5 J+ ?! o
}
, ?8 w8 U) w' C8 t
0 @7 m2 g% `6 I
return $hashStr;
9 l0 D3 _3 T& g& T
}
' c- w" p) g! Y6 n# _
& o0 ]: m6 L* Z x2 ]
@! C* n/ h! r3 H
/**hash 图片文件
! Z7 I& @: [3 s9 u3 J) o
* @param string $filePath 文件地址路径
+ U- S6 y- a" N* p5 [( R$ n' w5 X
* @return string 图片 hash 值,失败则是 false
& w) ]% d" B& k; e, f. Y2 w
* */
# b9 Z- G( J9 p) m
public static function hashImageFile($filePath){
! b4 X0 b u' O1 I4 A! q' Z
$src = self::createImage($filePath);
+ p K' o7 I; K4 k
$hashStr = self::hashImage($src);
3 F1 L7 |9 I6 L3 p
imagedestroy($src);
0 G9 z1 S9 i- E/ j/ \& _4 A
* A/ X9 a9 O( {( C& W1 G- ^7 O n
return $hashStr;
7 _6 W+ ~0 l" k% s7 W
}
4 g9 D4 m- b4 Z5 e
% D- f4 Y! n' R; W
5 Z/ z r3 P8 ?% W+ {
/**比较两个 hash 值,是不是相似
; w$ q9 y8 r5 p9 T# Y
* @param string $aHash A图片的 hash 值
. u# z' I B/ ~) c- \
* @param string $bHash B图片的 hash 值
) u+ V5 |! V! h# J
* @return bool 当图片相似则传递 true,否则是 false
5 L/ m" k3 `9 b: j
* */
4 \7 f6 v3 a( R( l0 O# Z# x1 T' @
public static function isHashSimilar($aHash, $bHash){
% c2 { B) ]6 g9 j: V4 T/ K
$aL = strlen($aHash); $bL = strlen($bHash);
. ?) ^' { O, d
if ($aL !== $bL){ return false; }
) I5 L( U. b: g: A) J! J
/ q% Z1 I$ t3 Q+ {
/*计算容许落差的数量*/
5 u7 O& {# D# O, D5 t
$allowGap = $aL*(100-self::$similarity)/100;
! F, o H! o. L% d3 O' Z8 q4 p
! y: U9 R( ^% P$ o3 A: X
/*计算两个 hash 值的汉明距离*/
7 O' t" B9 I5 U" V
$distance = 0;
5 J0 a3 ^- @: m- P4 ^6 C* S$ L
for($i=0; $i<$aL; $i++){
, w6 `6 {: _' |# S2 \) p
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
$ K& d x7 V) x, a0 h
}
3 W z# F, l5 {# h% @
8 y$ ?: Q; E4 F4 V0 [9 D8 a
return ($distance<=$allowGap) ? true : false;
9 k8 U3 u+ ?7 Z: f/ j
}
7 ]7 Z& t3 ~ }4 m) l# y8 A: U1 n9 }
/ h" m4 |+ T' d2 [5 j5 O8 i: t
8 @! U; @/ i. v. r$ p$ W
/**比较两个图片文件,是不是相似
' l$ F: Y% Z' F$ \' a2 a) j+ R
* @param string $aHash A图片的路径
0 ]! J3 m/ q4 b; s0 n
* @param string $bHash B图片的路径
- N/ W& p/ L& }& s
* @return bool 当图片相似则传递 true,否则是 false
; A. i7 Y6 P) X9 {* W
* */
( i; ? k! Z5 [0 J$ X
public static function isImageFileSimilar($aPath, $bPath){
$ T: j+ ?1 N$ L! F3 S% z- S8 w. n* g
$aHash = ImageHash::hashImageFile($aPath);
& x/ P) l6 N9 J# L7 C F7 x3 O4 m
$bHash = ImageHash::hashImageFile($bPath);
! p+ ^3 i; k, }2 s
return ImageHash::isHashSimilar($aHash, $bHash);
1 F- O- g+ ]6 m
}
* ~$ D2 Q! l( Y
5 K! r+ A, P* t0 a5 @5 R
}
" }. R$ U2 ~# A2 E, E
复制代码
+ \/ L$ I9 O# m: A. B+ b
# n3 h: J) Y1 h3 C2 {
欢迎光临 cncml手绘网 (http://www.cncml.com/)
Powered by Discuz! X3.2