PHP实现的简易版图片相似度比较
程序员文章站
2023-04-05 17:12:10
由于相似图片搜索的php实现的 api 不怎么符合我的用途,所以我重新定义 api 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
复制代码 代码如下:...
由于相似图片搜索的php实现的 api 不怎么符合我的用途,所以我重新定义 api 的架构,改写成比较简单的函数方式,虽然还是用对象的方式包装。
复制代码 代码如下:
<?php
/**
* 图片相似度比较
*
* @version $id: imagehash.php 4429 2012-04-17 13:20:31z jax $
* @author jax.hu
*
* <code>
* //sample_1
* $ahash = imagehash::hashimagefile('wsz.11.jpg');
* $bhash = imagehash::hashimagefile('wsz.12.jpg');
* var_dump(imagehash::ishashsimilar($ahash, $bhash));
*
* //sample_2
* var_dump(imagehash::isimagefilesimilar('wsz.11.jpg', 'wsz.12.jpg'));
* </code>
*/
class imagehash {
/**取样倍率 1~10
* @access public
* @staticvar int
* */
public static $rate = 2;
/**相似度允许值 0~64
* @access public
* @staticvar int
* */
public static $similarity = 80;
/**图片类型对应的开启函数
* @access private
* @staticvar string
* */
private static $_createfunc = array(
imagetype_gif =>'imagecreatefromgif',
imagetype_jpeg =>'imagecreatefromjpeg',
imagetype_png =>'imagecreatefrompng',
imagetype_bmp =>'imagecreatefrombmp',
imagetype_wbmp =>'imagecreatefromwbmp',
imagetype_xbm =>'imagecreatefromxbm',
);
/**从文件建立图片
* @param string $filepath 文件地址路径
* @return resource 当成功开启图片则传递图片 resource id,失败则是 false
* */
public static function createimage($filepath){
if(!file_exists($filepath)){ return false; }
/*判断文件类型是否可以开启*/
$type = exif_imagetype($filepath);
if(!array_key_exists($type,self::$_createfunc)){ return false; }
$func = self::$_createfunc[$type];
if(!function_exists($func)){ return false; }
return $func($filepath);
}
/**hash 图片
* @param resource $src 图片 resource id
* @return string 图片 hash 值,失败则是 false
* */
public static function hashimage($src){
if(!$src){ return false; }
/*缩小图片尺寸*/
$delta = 8 * self::$rate;
$img = imagecreatetruecolor($delta,$delta);
imagecopyresized($img,$src, 0,0,0,0, $delta,$delta,imagesx($src),imagesy($src));
/*计算图片灰阶值*/
$grayarray = array();
for ($y=0; $y<$delta; $y++){
for ($x=0; $x<$delta; $x++){
$rgb = imagecolorat($img,$x,$y);
$col = imagecolorsforindex($img, $rgb);
$gray = intval(($col['red']+$col['green']+$col['blue'])/3)& 0xff;
$grayarray[] = $gray;
}
}
imagedestroy($img);
/*计算所有像素的灰阶平均值*/
$average = array_sum($grayarray)/count($grayarray);
/*计算 hash 值*/
$hashstr = '';
foreach ($grayarray as $gray){
$hashstr .= ($gray>=$average) ? '1' : '0';
}
return $hashstr;
}
/**hash 图片文件
* @param string $filepath 文件地址路径
* @return string 图片 hash 值,失败则是 false
* */
public static function hashimagefile($filepath){
$src = self::createimage($filepath);
$hashstr = self::hashimage($src);
imagedestroy($src);
return $hashstr;
}
/**比较两个 hash 值,是不是相似
* @param string $ahash a图片的 hash 值
* @param string $bhash b图片的 hash 值
* @return bool 当图片相似则传递 true,否则是 false
* */
public static function ishashsimilar($ahash, $bhash){
$al = strlen($ahash); $bl = strlen($bhash);
if ($al !== $bl){ return false; }
/*计算容许落差的数量*/
$allowgap = $al*(100-self::$similarity)/100;
/*计算两个 hash 值的汉明距离*/
$distance = 0;
for($i=0; $i<$al; $i++){
if ($ahash{$i} !== $bhash{$i}){ $distance++; }
}
return ($distance<=$allowgap) ? true : false;
}
/**比较两个图片文件,是不是相似
* @param string $ahash a图片的路径
* @param string $bhash b图片的路径
* @return bool 当图片相似则传递 true,否则是 false
* */
public static function isimagefilesimilar($apath, $bpath){
$ahash = imagehash::hashimagefile($apath);
$bhash = imagehash::hashimagefile($bpath);
return imagehash::ishashsimilar($ahash, $bhash);
}
}