
本文介绍如何用 php 实现用户上传图片后,自动比对目录中所有图片并返回视觉相似(非完全相同)的结果,替代传统 md5 精确匹配,核心采用感知哈希(phash)算法提升鲁棒性。
本文介绍如何用 php 实现用户上传图片后,自动比对目录中所有图片并返回视觉相似(非完全相同)的结果,替代传统 md5 精确匹配,核心采用感知哈希(phash)算法提升鲁棒性。
在图像检索场景中,仅依赖 MD5 或 SHA-1 进行文件级哈希比对,只能识别字节完全一致的副本(如未修改的原始文件),无法应对常见的视觉相似情况:缩放、轻微裁剪、格式转换(JPG ↔ PNG)、亮度/对比度微调、水印添加等。此时需引入感知哈希(Perceptual Hashing)——它将图像内容抽象为紧凑的哈希值,使视觉相近的图像生成汉明距离(Hamming Distance)较小的哈希码。
推荐使用轻量、开源的 compareImages 类(源自 nvthaovn/CompareImage),其底层基于经典的 pHash 算法:先将图像灰度化、缩放至 32×32,再经离散余弦变换(DCT),保留低频系数,最后通过中值量化生成 64 位二进制指纹。两图哈希值间的汉明距离越小,视觉相似度越高。
✅ 完整可运行示例
首先,下载 compareImages.php 并置于项目根目录(或调整 include 路径):
<?php
// compareImages.php 已封装好 pHash 计算与汉明距离逻辑
include('compareImages.php');
if (isset($_POST['submit'])) {
// 1. 安全处理上传文件
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
die("文件上传失败:" . $file['error']);
}
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
die("仅支持 JPG、PNG、GIF 格式");
}
$iname = date('His') . '.' . $ext;
$uploadPath = 'upload/' . $iname;
// 创建 upload 目录(若不存在)
if (!is_dir('upload')) mkdir('upload', 0755, true);
if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
die("文件保存失败");
}
// 2. 初始化比对器(自动计算上传图的 pHash)
$comparator = new compareImages($uploadPath);
// 3. 扫描目标图库(建议限定格式,避免读取隐藏文件)
$targetImages = glob('img/*.{jpg,jpeg,png,gif}', GLOB_BRACE);
echo "<h3>相似图片结果(汉明距离 < 21):</h3>";
$results = [];
foreach ($targetImages as $imgPath) {
$distance = $comparator->compareWith($imgPath);
// 阈值说明:0=完全相同;≤10 高度相似;≤21 通常可接受为“相似”;>30 基本无关
if ($distance <= 21) {
$results[] = [
'path' => $imgPath,
'distance' => $distance
];
echo "<img src='{$imgPath}' style="max-width:90%" style="max-width:90%" style='margin:5px; border:2px solid #4CAF50;' alt='相似图(距离:{$distance})'>";
}
}
if (empty($results)) {
echo "<p>未找到视觉相似的图片。</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站"><img
src="https://img.php.cn/upload/skill/000/000/081/179040786932301.jpg" alt="btpanel phpsite 宝塔面板PHP网站" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站">btpanel phpsite 宝塔面板PHP网站</a>
<p>宝塔面板 PHP 网站管理:站点创建、删除、启停、PHP 版本切换、域名管理、SSL证书管理、伪静态管理、数据库管理</p>
</div>
<a href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/7fc7563c4182" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">PHP免费学习笔记(深入)</a>”;</p>";
}
}
?>配套 HTML 表单(增强用户体验):
<!DOCTYPE html>
<html>
<head><title>图像相似度搜索</title></head>
<body>
<h2>上传图片查找相似项</h2>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file" accept="image/*" required>
<br><br>
<button type="submit" name="submit">开始比对</button>
</form>
<!-- 显示上传原图预览 -->
<?php if (isset($uploadPath) && file_exists($uploadPath)): ?>
<h3>您上传的图片:</h3>
<img src="<?= htmlspecialchars($uploadPath) ? alt="如何在 PHP 中实现基于感知哈希的图像相似度匹配" >" width="120" style="max-width:90%" style="border:1px solid #ccc;">
<?php endif; ?>
</body>
</html>⚠️ 关键注意事项
-
性能优化:glob('img/*') 在图片量大(>500 张)时会变慢。生产环境建议:
- 预先计算并缓存所有图库图像的 pHash 到数据库(如 MySQL JSON 字段或 Redis);
- 使用异步队列(如 Redis + Worker)处理批量比对。
- 阈值调优:$diff
- 更严格(如
- 更宽松(如
- 始终校验 $_FILES['file']['type'] 和扩展名,防止恶意文件上传;
- 上传目录(upload/)禁止执行 PHP(通过 .htaccess 或 Nginx 配置限制);
- 对输出的 $imgPath 使用 htmlspecialchars() 防止 XSS(示例中已体现)。
通过此方案,你将获得一个鲁棒、易维护、面向真实视觉需求的图像相似搜索功能,远超简单哈希的局限性。


















