PHP-Laravel 以图搜图功能

该功能可能有些长,但是我会详细着讲解,若不想看文档的直接看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循环.!!!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值