<?php
/**
* 图片比较类
*/
namespace Think;
class ImageSame {
?
// 单例,防止重复初始化
private static $_instance = null;
?
// 误差
public static $rate = 1;
?
public static function init() {
if (self::$_instance === null)self::$_instance = new self();
return self::$_instance;
}
?
// 获取两个图片的hash
public function doCompare($file) {
if(!function_exists('imagecreatetruecolor')) {
throw new Exception('GD Library must be load
if you want to use the class ImgCompare');
}
?
$is_string = false;
?
if(is_string($file)) {
$file = array($file);
$is_string = true;
}
?
$result = array();
foreach ($file as $f) {
$result[] = $this->getHashValue($f);
}
return $is_string ? $result[0] : $result;
}
?
// 计算汉明距离
public function checkIsSimilar($img_hash_1,$img_hash_2) {
if (file_exists($img_hash_1) && file_exists($img_hash_2)) {
$img_hash_1 = self::doCompare($img_hash_1);
$img_hash_2 = self::doCompare($img_hash_2);
}
?
if(strlen($img_hash_1) !== strlen($img_hash_2)) {
return false;
}
?
$count = 0;
$len = strlen($img_hash_1);
for ($i=0;$i<$len;$i++) {
if($img_hash_1[$i] === $img_hash_2[$i]) {
// 计算 有多少位是一样的
$count ++;
}
}
?
// 得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。
// 在理论上,这等同于计算"汉明距离"(Hamming distance)。
// 如果不相同的数据位不超过5*误差,就说明两张图片很相似;
// 如果大于10*误差,就说明这是两张不同的图片。
?
// return $count <= (5*(self::$rate)*(self::$rate))?true:false;
return $count/strlen($img_hash_1)*100;
}
?
public function getGray($rgb){
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
return (int)($r*0.3 + $g*0.59 + $b*0.11);
}
?
public function getHashValue($src) {
$info = getimagesize($src);
$w = 11; // 采样宽度
$h = $w-1; // 采样高度
$dst = imagecreatetruecolor($w, $h);
$img = $this->createImg($src);
// 缩放
imagecopyresized($dst, $img, 0, 0, 0, 0, $w, $h, $info[0], $info[1]);
// header('Content-type:image/png');
// imagepng($dst); //输出图形
$hash = '';
for ($y = 1; $y < $h-1; $y++) {
$pix =$this->getGray(imagecolorat($dst, 1, $y));
for ($x = 1; $x < $h-1; $x++) {
$_pix = $this->getGray(imagecolorat($dst, $x+1, $y));
$_pix > $pix ? $hash .= '1' : $hash .= '0';
$pix=$_pix;
}
}
return $hash;
}
?
/**
* 生成图片
*/
public function createImg($file) {
$info = getimagesize($file);
$suffix = false;
if($mime = $info['mime']){
$suffix = explode('/',$mime)[1];
}
$ext =$suffix?$suffix:self::getFileExt($file);
if ($ext === 'jpeg') $ext = 'jpg';
$img = null;
switch ($ext){
case 'png' : $img = imagecreatefrompng($file);break;
case 'jpg' : $img = imagecreatefromjpeg($file);break;
case 'gif' : $img = imagecreatefromgif($file);break;
default:break;
}
return $img;
}
?
/**
* 获取图片扩展名,通过getimagesize获取不到的时候用这个
* 这个不能防止修改后缀的情况
*/
public function getFileExt($file){
$infos = explode('.', $file);
$ext = strtolower($infos[count($infos) - 1]);
return $ext;
}
}
实际应用中,我们只需要每次上传图片获取对应的hash值保存到数据库,然后比较的时候用SQL语句(查询2个hash值字段的按位异或后的1的个数即为不同的个数)比较2个hash值的不同即可,而不必每次调用他的比较方法.