该功能可能有些长,但是我会详细着讲解,若不想看文档的直接看demo就行啦
composer require jenssegers/imagehash
官方文档介绍如下:
该库附带4个内置哈希实现:
Jenssegers\ImageHash\Implementations\AverageHash-基于平均图像颜色的哈希
Jenssegers\ImageHash\Implementations\DifferenceHash-基于前一像素的哈希
Jenssegers\ImageHash\实现\BlockHash-基于BlockHash.io的哈希仍在开发中
Jenssegers\ImageHash\实现\感知哈希-原始pHash仍在开发中
选择其中一个实现。如果您不知道使用哪一个,请尝试DifferenceHash实现。有些实现允许一些配置,请务必检查构造函数。
use Jenssegers\ImageHash\ImageHash;
use Jenssegers\ImageHash\Implementations\DifferenceHash;
$hasher = new ImageHash(new DifferenceHash());
$hash = $hasher->hash('path/to/image.jpg');
echo $hash;
// or
echo $hash->toHex();
生成的Hash对象是一个十六进制图像指纹,一旦计算出来,就可以存储在数据库中。hamming距离用于比较两个图像指纹的相似性。低距离值将指示图像相似或相同,高距离值指示图像不同。使用以下方法检测图像是否相似:
$distance = $hasher->distance($hash1, $hash2);
// or
$distance = $hash1->distance($hash2);
相等图像的距离并不总是为0,因此您需要决定将图像评估为相等的距离。对于我测试的图像集,最大距离5是可以接受的。但这将取决于实现、图像和图像的数量。例如当比较一小组图像时,较低的最大距离应该是可以接受的,因为假阳性的几率非常低。然而,如果你正在比较大量的图像,5可能已经太多了。
Hash对象可以以几种不同的格式返回内部二进制哈希:
echo $hash->toHex(); // 7878787c7c707c3c
echo $hash->toBits(); // 0111100001111000011110000111110001111100011100000111110000111100
echo $hash->toInt(); // 8680820757815655484
echo $hash->toBytes(); // "\x0F\x07ƒƒ\x03\x0F\x07\x00"
选择在数据库中存储哈希的首选项。如果要根据以前计算的值重新构建哈希对象,请使用:
$hash = Hash::fromHex('7878787c7c707c3c');
$hash = Hash::fromBin('0111100001111000011110000111110001111100011100000111110000111100');
$hash = Hash::fromInt('8680820757815655484');
保存数据库中这里要说明下,扩展中$hasher->hash('path/to/image.jpg');
这里是生成的object数据无法直接存数据库,扩展中利用$hash->toBits()
;转为Sting格式入库.
之后调用
$hasher->distance($hash1, $hash2);
才不会报错!!!请注意.
DEMO
控制器层
<?php
namespace App\Http\Controllers\Wap;
use App\Http\Controllers\Controller;
use App\Libs\SearchImg;
use App\Models\Misspeople;
use App\Tools\Apireponse;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Intervention\Image\Facades\Image;
use Jenssegers\ImageHash\ImageHash;
use Jenssegers\ImageHash\Implementations\DifferenceHash;
use Illuminate\Support\Facades\File;
class ImgController extends Controller
{
/**
* 搜索图片库
* @param Request $request
*/
public function searchImg(Request $request)
{
if ($request->ajax())
{
$file = $request->file("files");
if (!empty($file))
{
$validator = Validator::make($request->file(),[
'file' => 'file|max:20000|mimes:jpeg,png,jpg',
],[
//验证是否为文件
'file.file' => '请确认你的图片格式',
//验证文件上传大小
'file.max' => '头像最大上传大小为20M',
//验证上传文件格式
'file.mimes' => '请确认上传为jpg或jpeg,png的格式图片',
]);
if ($validator->fails()) {//如果有错误
return Apireponse::response($validator->errors(),400);
}
$ext=$file->getClientOriginalExtension();
$imageName = date("Ymd").rand(1111,9999).'.'.$ext;
$filepath = 'upload/miss/' . date('Ymd') . '/';
if (!file_exists($filepath)) {
@mkdir($filepath);
}
$image = Image::make($file);
// 尺寸等比压缩,最大宽度800
if (($width = $image->getWidth()) > 800) {
// 等比缩放,需要计算宽度缩放的比例,再计算出缩放后的图片高度
$proportion = $width / 800;
$height = ceil($image->getHeight() / $proportion);
$image = $image->resize(800, $height);
}
// 文件绝对路径且用save保存
// 保存图片,并设置质量压缩为60
$imageSrc= 'upload/miss/' . date('Ymd') ."/". $imageName;
$image->save($imageSrc, 60);
//第一个参图片地址,第二个图片库(必须转成bits格式数据库中)
$res = SearchImg::CompareImg($imageSrc,["78113396"=>"0110110101101101000101110001011100010111000101111100100100011101","78113395"=>"0110110100011111000101110001011100010111000101111100111100011001"]);
//无论成功与否删除上传的图片
File::delete($imageSrc);
//若不为空则取出相应数据
if (!empty($res))
{
$results = Misspeople::whereIn("id",$res)->orderBy("id","DESC")->get();
}else{
$results =[];
}
return Apireponse::response($results,200);
}else{
return Apireponse::response("未选择图片",400);
}
}
return Apireponse::response("非法访问",400);
}
}
Lib\SearchImg类
<?php
namespace App\Libs;
use Jenssegers\ImageHash\Hash;
use Jenssegers\ImageHash\ImageHash;
use Jenssegers\ImageHash\Implementations\DifferenceHash;
class SearchImg
{
/**
* 匹配相似的图片地址方法
* $img_list 图片地址
* $img_hash 散列值的数组
*/
static function CompareImg($img_path, $img_hash = [],$smilarnum=5){
try{
$hasher = new ImageHash(new DifferenceHash());
$value1_sh = $hasher->hash($img_path);//生成的是object数据
$img_list= [];
foreach ($img_hash as $k=>$v)
{
$hash = Hash::fromBits($v);//将Sting格式转成object的hash格式.要不然会报错!!!!!
$sh = $hasher->distance($value1_sh,$hash);//进行相似比较
if($sh <= $smilarnum) {
$img_list[] = $k;
}
}
}catch(\Exception $e){
throw new \Exception($e->getMessage());
}
return $img_list;
}
}
图库最好走脚本生成hash指针数据入库,之后在查询遍历可以进行查找,目前该代码只是参考,若存在成千上万条图片库最好不要进行foreach循环.!!!