cncml手绘网
标题:
分享一个PHP简易的图片相似度比较类
[打印本页]
作者:
admin
时间:
2018-7-7 23:06
标题:
分享一个PHP简易的图片相似度比较类
摘要:
本文讲的是分享一个PHP简易的图片相似度比较类, 由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。 代码如下 复制代码 <?php /** * 图
) r& ?( ]) y' ^ I6 L$ p1 o- E
. u) ^$ O1 C( _. s8 w
& [0 }' l. i2 ] z! M/ ^
由于相似图片搜索的php实现的 API 不怎么符合我的用途,所以我重新定义 API 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
& |. s% \8 e, z; h
<?php
5 C( e8 ~, L% b
/**
1 T. }0 p4 v5 k0 h, X
* 图片相似度比较
0 A6 `1 L4 l# [0 n. X: j
*
: I: W/ h% l: e" g, \2 D
* @version $Id: ImageHash.php 4429 2012-04-17 13:20:31Z jax [ DISCUZ_CODE_1 ]nbsp;
1 q) [" o3 s, \, ~& B$ p8 T; S! y
* @author jax.hu
0 k: u' F- O, u: n& q6 D0 \, u7 I
*
* O2 o U) c6 |0 l |2 R( z
* <code>
* j$ o4 J/ X$ w: }
* //Sample_1
T F3 F& i2 @+ M# Q
* $aHash = ImageHash::hashImageFile('wsz.11.jpg');
& p/ |! a |) v" |( e6 h0 P, a
* $bHash = ImageHash::hashImageFile('wsz.12.jpg');
# g0 F% j. k& d9 e7 `
* var_dump(ImageHash::isHashSimilar($aHash, $bHash));
! o+ M. L: j& r$ v1 M4 d4 o ]
*
! h- O; H# C4 Y6 m9 J9 ^
* //Sample_2
+ ?. y, A+ u" \4 h8 Y2 u
* var_dump(ImageHash::isImageFileSimilar('wsz.11.jpg', 'wsz.12.jpg'));
+ `. v5 P2 E |' K" \0 u p( I0 p$ L
* </code>
; o: u+ h" S! J
*/
2 _0 a, [4 v* {, m8 u
5 S0 Q8 B$ k1 }. H* G% ~2 P
class ImageHash {
$ V; D- j& [. H& h& H4 f# H
- A' J: b: ^5 Y6 s5 U$ b
/**取样倍率 1~10
6 a+ w5 P! ?, z4 p. B. w& |# ^
* @access public
5 V9 ]/ {& }, r& x" f) V6 W& X y
* @staticvar int
2 C% f0 Y0 k) V* p9 T# \" L& d: n
* */
! x6 t7 k! m7 G b( n
public static $rate = 2;
/ r7 K+ B9 R4 P4 I: f n& c
. S c5 K3 ^9 a, ^( ~; Z! D" t/ p
/**相似度允许值 0~64
0 q, |% ?3 J+ D8 w
* @access public
% s( F: l4 t5 `2 {0 k/ N# t
* @staticvar int
3 H' p" v7 {. o* X5 M
* */
: J$ ]$ a0 _* h) ?
public static $similarity = 80;
/ u2 {& E. s% k+ t+ ^' b" R
$ B/ d9 b$ V- o' `2 r) p! @+ S
/**图片类型对应的开启函数
* ^$ I7 |; d) y/ a
* @access private
0 J7 z4 [3 \ p3 f
* @staticvar string
9 b$ \! F4 n7 B( S
* */
8 _% [; N( n- R; F8 \
private static $_createFunc = array(
5 c3 }9 T. p( i
IMAGETYPE_GIF =>'imageCreateFromGIF',
8 }3 |+ l# ]) i. z
IMAGETYPE_JPEG =>'imageCreateFromJPEG',
+ l; G) z: N2 q+ W4 ^+ h! k G
IMAGETYPE_PNG =>'imageCreateFromPNG',
& N) N$ |+ y: M" N, C/ Z
IMAGETYPE_BMP =>'imageCreateFromBMP',
! V/ [" {7 k- z" v6 H( S. Z$ }' t
IMAGETYPE_WBMP =>'imageCreateFromWBMP',
# O8 S# M/ N+ w2 e4 r
IMAGETYPE_XBM =>'imageCreateFromXBM',
, v0 T3 l" O# ^9 z2 [
);
8 m& Z4 o- u1 V* P8 u
8 I6 L0 f# Y% q% `% I
2 d1 P9 k' C) r' `$ f7 M- `$ O8 c! x
/**从文件建立图片
. z" |9 }! y2 u D( Y' |& _
* @param string $filePath 文件地址路径
, o& T W* @# E4 i2 W
* @return resource 当成功开启图片则传递图片 resource ID,失败则是 false
' j& r0 Y/ i7 G' X2 r
* */
8 \8 Y: J2 O& a* g
public static function createImage($filePath){
5 m9 p, c) v4 X) b
if(!file_exists($filePath)){ return false; }
& h4 _% Y- \! `" B6 Y( s* I
! v$ e& u; B* n+ [1 l: b1 E; y
/*判断文件类型是否可以开启*/
1 g9 J, o- ]0 k% P3 U0 d5 B
$type = exif_imagetype($filePath);
; Y* M3 |' v b2 h9 u2 d
if(!array_key_exists($type,self::$_createFunc)){ return false; }
* J0 y9 {- D4 x
' T \3 J/ B/ Q/ ^9 {
$func = self::$_createFunc[$type];
+ k7 ^* E! i/ |6 L
if(!function_exists($func)){ return false; }
$ N9 b9 M' Y v0 @* Z3 @+ p
X8 S& H$ c& [2 T
return $func($filePath);
. \$ Q9 g- x$ C) H$ d) }# @
}
$ w3 G6 I2 Y( }
! \+ d0 L6 @5 G7 f( n- ~
2 B) x# l; h- B3 R" ~1 e, N
/**hash 图片
* K9 h- a. [5 C! ]& y. C' r' h/ k5 j
* @param resource $src 图片 resource ID
{* a' j' x+ Y" n6 E3 B
* @return string 图片 hash 值,失败则是 false
7 w% s2 P4 w6 g+ i, U
* */
: Q% t, D# C. Y# H( l$ T
public static function hashImage($src){
7 M6 U% Y/ ^. w9 }4 @1 D. {
if(!$src){ return false; }
$ Q; J3 P$ ~; P
! [8 [$ C" [' @" L1 Q
/*缩小图片尺寸*/
1 J0 ^. U" y" q6 e! a0 T
$delta = 8 * self::$rate;
5 u/ J% J9 X9 H C5 Q9 V$ ~
$img = imageCreateTrueColor($delta,$delta);
" p0 N$ d( R1 U# F1 \: h) k
imageCopyResized($img,$src, 0,0,0,0, $delta,$delta,imagesX($src),imagesY($src));
# k, [6 d( M" ^, }8 G1 ?
' y. X- ]' ?1 K
/*计算图片灰阶值*/
+ a' d$ u8 F. f( [5 {* {
$grayArray = array();
6 Z5 f1 a6 o5 m: H* D
for ($y=0; $y<$delta; $y++){
% }% ~0 X5 M1 y4 e! Q
for ($x=0; $x<$delta; $x++){
& v0 c+ Q2 D* b5 e5 ^
$rgb = imagecolorat($img,$x,$y);
% q" O( ~) o9 Q) f2 ]' w; g' Z4 e
$col = imagecolorsforindex($img, $rgb);
7 ?/ t7 t' d5 n8 b* w: w
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xFF;
; _& r( I7 ^8 M" F
+ Z: s& F* n$ Y
$grayArray[] = $gray;
+ U3 z5 r# T% v7 v; Y
}
; j5 K; B& X! J2 d( o8 L, k1 R
}
$ b2 k: m4 _( `; q: A! k0 M2 R
imagedestroy($img);
) K4 N3 w; H+ v) X- Q1 V* @! s
: d% p O* j, r w6 n: @' q
/*计算所有像素的灰阶平均值*/
3 i+ v" ^" Z6 u, L# C, ^, T
$average = array_sum($grayArray)/count($grayArray);
, V1 |7 I. f& _: G, E' Q
' Z7 ?" h7 g8 m, N# m' C+ k2 S+ L
/*计算 hash 值*/
$ @: v1 J4 M1 t. F I
$hashStr = '';
7 g: k- ~8 v" w' u
foreach ($grayArray as $gray){
7 K! N/ }, E6 y2 V
$hashStr .= ($gray>=$average) ? '1' : '0';
% k+ B0 i8 p- M. D0 Y0 X
}
! N. A/ W! z9 f! C" e1 S' A
5 z% d* O$ m, s
return $hashStr;
) J# c% a3 S! z( m( p) p! {( U
}
2 H. ]1 a/ b( w+ P% X C/ D/ ^
2 ^; T0 U* m" _/ w
* O& g7 n7 m/ W
/**hash 图片文件
! o' r1 U2 p, {- Q5 d9 D
* @param string $filePath 文件地址路径
7 M' Y5 _+ _$ L' b- P9 {
* @return string 图片 hash 值,失败则是 false
& X0 |7 h9 Z$ s: ^
* */
3 S; C% L# K" \+ s# e# ]( J
public static function hashImageFile($filePath){
+ x$ D. q! m! h) _' d# U# N# `2 W3 o
$src = self::createImage($filePath);
( u- a! C" s+ X+ s3 Z. Z( W
$hashStr = self::hashImage($src);
7 F2 ?- ]: U, G& l; j
imagedestroy($src);
4 Y& ]* y/ ?7 D$ T* b
' j$ ^* Y2 }; h/ z3 Q
return $hashStr;
$ a& {. @- S3 X* d8 J4 _, x
}
# ^3 g" m+ I v( {. c0 p
$ {/ [0 G# D7 A8 S* `; t/ d+ R& E9 _
p) B# }* ~5 l7 n. y
/**比较两个 hash 值,是不是相似
' [& u! t3 ?) I% J* A: ^) M
* @param string $aHash A图片的 hash 值
8 G. ]' k% U, L3 q( h6 X
* @param string $bHash B图片的 hash 值
$ t, _, l3 a9 s; X7 f+ c. A2 k: Z
* @return bool 当图片相似则传递 true,否则是 false
: I6 F& ^- W2 l# S2 i+ T
* */
1 U) N* ~. j& w9 S0 p) g2 c
public static function isHashSimilar($aHash, $bHash){
6 [3 D" B d" K+ ^- F2 N4 ?
$aL = strlen($aHash); $bL = strlen($bHash);
! {, V9 X1 E6 ], N& f% o& r/ W% k
if ($aL !== $bL){ return false; }
3 Y! A& A- X& U5 ^/ u- W( a z2 y
3 L2 S! x7 M7 f) [" u* |! }- l
/*计算容许落差的数量*/
7 h6 @5 d/ }1 @9 f7 A) z) i& B
$allowGap = $aL*(100-self::$similarity)/100;
' `$ g; N7 q9 X
7 x+ E& C) y. |0 U n$ o- h6 a
/*计算两个 hash 值的汉明距离*/
) `/ v& E Q+ v- C( a" }+ x& J
$distance = 0;
! R$ J+ E* o9 N
for($i=0; $i<$aL; $i++){
2 e i. K& G% C& t- {! H% ?
if ($aHash{$i} !== $bHash{$i}){ $distance++; }
& T5 G2 {# r, f
}
+ c: T3 Z8 o1 ]* M5 g3 F" y
9 ~ s0 S& ?/ i$ j
return ($distance<=$allowGap) ? true : false;
5 \$ [: s' p5 k* S' G
}
: a' P( g w% s9 w5 D4 B5 x
1 S( d, ^- Q; h% R
9 Y ]% ]1 }) b. \ V# w8 X+ [
/**比较两个图片文件,是不是相似
4 V. P- n) }4 O+ {
* @param string $aHash A图片的路径
+ P3 \' z# Z6 F7 k" l
* @param string $bHash B图片的路径
3 \: o% a1 y3 h
* @return bool 当图片相似则传递 true,否则是 false
1 T; w8 n$ [: j
* */
* g b1 w D+ J, \' b
public static function isImageFileSimilar($aPath, $bPath){
( \3 X0 n) @, Z2 a- [4 h
$aHash = ImageHash::hashImageFile($aPath);
; y" J" k u- U, u" J( C
$bHash = ImageHash::hashImageFile($bPath);
! `) _' v2 G# J( ]! x3 N* ]2 C6 T
return ImageHash::isHashSimilar($aHash, $bHash);
" k t/ t. r9 f2 ?" k
}
3 x) o! F! l+ m) C7 U: p: U
A( z7 m+ ^, ^5 `+ z& b4 P
}
$ v6 a: X; E) w0 k0 x6 u
复制代码
3 y6 V/ A8 O1 G: ^$ R+ ]
+ l- }' L$ J1 Y. W
欢迎光临 cncml手绘网 (http://bbs.cncml.com/)
Powered by Discuz! X3.2