cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
, c7 ~, M, o3 [
( i0 V* p( a% z; v5 [+ `
& K5 C* M( g5 @3 k$ b8 V
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
6 f- M$ Q: |: a. Y h- C. z
<?php
' i' q1 g& ]- w: Q6 M( O0 W3 d
/**
4 a$ U I7 y% X% V/ R
* 图片相似度比较
" s: @" c* D( k0 S4 r: ~
*
9 Z# x" g( W- @$ {% c: E4 F
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
5 d* L$ V0 r" D" n% N3 C) s% {+ ?- Q5 o! Q
* @author jax.hu
% u/ ]3 L9 q) m1 N. |! R# q
*
5 A k) z# X6 l. C" i* z4 K, Y
* <code>
3 m- E+ X3 u9 M: V* X' @
* //Sample_1
% s2 n- S' u" M" ~
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
. P4 G% ]% R o- Z/ A0 X
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
a$ v$ g' N3 B! Z) D* o* Z# S
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
5 l& d* j" k# O3 k3 ?7 G8 F. S: K& D
*
; K7 Z# v( l: [+ o2 f# n2 `
* //Sample_2
5 t6 a0 S- ^+ H+ n
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
" g8 V. L3 u0 x9 r, C' [& O
* </code>
' r, ~+ t; A3 \ P. F
*/
& _. L$ C; l. @& h
( R& V" u e K# V% ]# i% f4 s9 c
class ImageHash {
* B0 O: o) O3 F5 W, E. T! N
4 H9 V; E4 e; g
/**取样倍率 1~10
" c: R6 J" R2 S; P% i( R. c
* @access public
1 l. e: y" U( k
* @staticvar int
7 X9 |9 E4 y! }) d8 H
* */
# ?& e- M! v, N8 C% ?
public static $rate = 2;
6 x: V6 u4 m' Q
! ]9 q6 S" ~/ j; K; J
/**相似度允许值 0~64
3 ?( s. n+ k1 }3 r8 F) B
* @access public
* C; s! g- k/ s$ m% o
* @staticvar int
2 V4 o: B Y( a
* */
) f( M( O8 b$ k: U
public static $similarity = 80;
, H' R- S: K1 t/ m& Z
1 a& d' b2 G' } t/ w* o( q0 D
/**图片类型对应的开启函数
5 G( Z8 A+ g5 k' w, S+ c
* @access private
$ {8 s2 d: c; C# V3 [, K6 ]
* @staticvar string
2 c; q- V/ V$ H+ }4 \
* */
3 [, j! n/ m+ r* H' R
private static $_createFunc = array(
; H/ P J; }, e
IMAGETYPE_GIF =>'imageCreateFromGIF',
* K" F1 Y X8 M4 y
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
' t$ t% c$ X6 X5 ]) P3 y* s& r; r6 y. Z
IMAGETYPE_PNG =>'imageCreateFromPNG',
9 T1 L% A8 l7 I# |; t8 F2 G/ @9 |
IMAGETYPE_BMP =>'imageCreateFromBMP',
, w1 Q. U. Y% Q
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
9 g7 V7 A. U" E- w5 X4 }' Q2 w
IMAGETYPE_XBM =>'imageCreateFromXBM',
3 N5 e& x* z6 P- _4 `9 a
);
, X% f- d' s5 I! |# ]# K/ ~
) d2 m, ]. G! C( \& _9 e
, P8 _6 t4 B( }: g m( N
/**从文件建立图片
! e" Y: {7 g. N* N& J0 r
* @param string $filePath 文件地址路径
1 `$ N' H, W' B2 D0 H7 A
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
' j" {2 h+ Z0 `3 }2 x- ]( [
* */
! h h p# F$ e! H$ G
public static function createImage($filePath){
6 f* ?$ e! T( t" {& k
if(!file_exists($filePath)){ return false; }
/ q+ z( `" \* Q( r; ~1 L# v0 y6 j& T
1 a# Z( ^* q) ?
/*判断文件类型是否可以开启*/
+ J; G- C' _; T9 r! s. F! {6 J. u
$type = exif_imagetype($filePath);
% q8 q4 X% {# f/ k9 `* q+ V
if(!array_key_exists($type,self::$_createFunc)){ return false; }
9 k6 ?5 ^6 @% n3 C: c$ e) B
" h! X+ v* {7 h% C: W
$func = self::$_createFunc[$type];
' p0 l! ?5 y7 e9 b! g7 C$ {
if(!function_exists($func)){ return false; }
& \- K" ^9 |. \: v8 o4 \
$ d# K2 R9 _1 M8 p+ u0 R8 g, k, a
return $func($filePath);
9 f' w q4 }$ ?5 b7 a, d9 H
}
8 q; c/ V8 g! h) G4 I& y8 k1 G
8 T' f1 q# b# v& M
7 K, G- g" N t, h! r$ O0 O3 O% y
/**hash 图片
, Q$ F: H, j7 P
* @param resource $src 图片 resource ID
% e7 O5 s6 c2 @! ?+ G4 h& j0 h( h4 Z
* @return string 图片 hash 值,失败则是 false
7 N1 B( u3 l/ l
* */
3 c5 S8 @( ]' w. T6 p/ R
public static function hashImage($src){
" H9 |- ~$ M& J. }) \$ T) f
if(!$src){ return false; }
" _) q0 \* i7 v9 J# }# @ ]
4 f( {8 A! h8 _1 f( _7 E. i* }
/*缩小图片尺寸*/
4 W3 u1 o6 M0 \) [# o
$delta = 8 * self::$rate;
" A3 R/ q2 [! u- ], {& X$ b* u
$img = imageCreateTrueColor($delta,$delta);
, n6 f5 v! C. g p+ j9 C
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
2 b0 V+ e* E l! v
- k9 n& w) w1 I3 |
/*计算图片灰阶值*/
- n' a6 Y- K1 _1 n6 `
$grayArray = array();
& {9 Y) W8 m9 `/ R
for ($y=0; $y<$delta; $y++){
3 A3 n5 E$ q& |1 E$ T: `
for ($x=0; $x<$delta; $x++){
: J' ^- C* U2 m! G+ o. ^' O
$rgb = imagecolorat($img,$x,$y);
* T* x- c' h" ~; i3 C! F
$col = imagecolorsforindex($img, $rgb);
I2 k5 {6 v2 O ]) w
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
2 Z. s# ^" E0 y# R! i7 z
6 |. h4 H" m# H# N
$grayArray[] = $gray;
8 O& A6 }1 Q; s& g9 K# @
}
% Z; l& s1 u8 s- k# @
}
1 x; ~5 M9 C4 ^. q7 {+ s, H
imagedestroy($img);
( K, [; b9 E/ ~. g% W( ~
/ u( S$ Y4 c0 X* C8 x" ^
/*计算所有像素的灰阶平均值*/
8 h! p# T# o$ y# f8 {
$average = array_sum($grayArray)/count($grayArray);
) {, V& A6 s3 @8 y `
% |- T- x. l& A0 M: O; y, q* S
/*计算 hash 值*/
; O# k6 d8 m: J
$hashStr = '';
- h4 A- w; m( `: Z9 F- z
foreach ($grayArray as $gray){
5 v7 r/ }9 e1 N3 j4 N/ A
$hashStr .= ($gray>=$average) ? '1' : '0';
7 o/ A, B$ r# s$ ~8 ^
}
7 ?/ {1 h9 j2 E! _
1 l O* {0 q/ l1 l$ ^
return $hashStr;
8 b% o6 y- n( a8 t1 R: W3 Z
}
: }+ x+ t+ l9 k2 Z
2 d! T4 F N- X+ }0 O, M
7 e# G. H: T. g$ K
/**hash 图片文件
2 Z) u$ b1 R5 E
* @param string $filePath 文件地址路径
- w& w2 }6 |3 ?9 K7 R
* @return string 图片 hash 值,失败则是 false
( q# P1 k( }3 ~% Q" N9 U/ m9 X
* */
" ]8 N& G" ~% U! `. |! W
public static function hashImageFile($filePath){
. p9 S( W7 s/ R/ @! y9 [
$src = self::createImage($filePath);
/ R: }- T% G- ?
$hashStr = self::hashImage($src);
7 z5 G+ z) X4 ^; O6 u6 A% @
imagedestroy($src);
5 ~" r! y0 h+ E/ c% d' y
6 s$ w; o0 ^) ]
return $hashStr;
2 p2 i; _/ ^1 c0 e. M
}
- s+ X, q* f# l
4 o g: S3 ?/ q
+ i3 B4 T0 N- g3 s; h
/**比较两个 hash 值,是不是相似
5 z) T' j; [+ {; w0 M# m# ^
* @param string $aHash A图片的 hash 值
$ ?1 n1 }4 K6 `( B' Q, X X! ^- _
* @param string $bHash B图片的 hash 值
. _$ c- k9 |1 J$ V% `
* @return bool 当图片相似则传递 true,否则是 false
( s: t. C# [ l: x& @
* */
9 u) L6 l- F& |/ g" d
public static function isHashSimilar($aHash, $bHash){
* a5 ~* T+ Q/ Y6 M: }- Z9 ?
$aL = strlen($aHash); $bL = strlen($bHash);
8 r/ J/ r: w- M: O0 v' F# g/ U8 D
if ($aL !== $bL){ return false; }
9 ?' w! T7 y( z, K' v2 ]: }
6 D$ N' U. K$ l$ S& |
/*计算容许落差的数量*/
h# c$ I, F: J; |
$allowGap = $aL*(100-self::$similarity)/100;
, F; g0 \8 d3 m( C# E
9 G' a* q& t2 X5 [& _; q: n* ~+ x/ X
/*计算两个 hash 值的汉明距离*/
- o% M. x, \+ R, H
$distance = 0;
: J* [6 s! E6 z: s) a
for($i=0; $i<$aL; $i++){
! y+ I: Y3 k, f# o
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
0 Q: Q1 Z" M* x! O+ c. ^2 f
}
6 N5 {$ o( F9 y) }
& i: \4 }5 t; T# @7 T
return ($distance<=$allowGap) ? true : false;
6 q+ J3 |( v& Y) ~
}
) I2 ]* d- W( @$ Q- ^2 F0 {* L3 m
- ?7 Q9 M) b' e+ h7 J! J
. `2 O& B2 `- ?1 D2 Y: i5 Q7 q
/**比较两个图片文件,是不是相似
4 ?( S, R# l, C# E7 x5 f
* @param string $aHash A图片的路径
: w* ~$ |. [- ` B" ]' a) x" m8 c. W
* @param string $bHash B图片的路径
- S8 \" ~+ _9 y3 d% O# |8 t/ i
* @return bool 当图片相似则传递 true,否则是 false
5 j" M* z' ~) b. W
* */
4 Y. n+ c4 w7 n* h4 \
public static function isImageFileSimilar($aPath, $bPath){
; H9 f/ j- ^1 _+ R
$aHash = ImageHash::hashImageFile($aPath);
* C) u& R/ u. L' u. `% d
$bHash = ImageHash::hashImageFile($bPath);
& ~) Z, P3 v: T! j
return ImageHash::isHashSimilar($aHash, $bHash);
- F V7 V4 p7 f7 ]8 B
}
3 q+ p+ g+ p1 s9 a* p" t
* s. E0 a* T" Q, ^
}
: B7 }& n0 D Y) x A3 e
复制代码
1 Z+ Y6 o& V+ w, D4 D! B
8 F+ }3 o8 E+ y; U
欢迎光临 cncml手绘网 (http://bbs.cncml.com/)
Powered by Discuz! X3.2