You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP如何通过RGB比对实现上传图与目录图片相似匹配

PHP实现相似图片匹配功能

你当前使用的MD5校验方案仅能识别文件字节完全一致的图片,无法匹配经过压缩、尺寸调整、轻微编辑的同内容图片。下面给出基于RGB值降维比对(平均哈希算法)的实现方案,遍历目录比对的性能远高于逐像素全量RGB比对,可直接替换原有逻辑。

注意:运行前请确认PHP环境已开启GD扩展,绝大多数PHP运行环境默认已开启该扩展。

实现逻辑

  • 将待比对的两张图片统一缩放到8*8的固定小尺寸,消除分辨率、尺寸差异的干扰
  • 将缩放后的图片转为灰度图,基于每个像素的RGB值计算对应的灰度值
  • 计算64个像素的平均灰度值,每个像素灰度大于平均值记为1、小于记为0,生成64位长度的图片特征指纹
  • 计算两个指纹的汉明距离(即取值不同的位的数量),距离越小代表图片相似度越高,通常距离小于5即可判定为内容高度相似

完整实现代码

PHP后端逻辑

<?php
/**
 * 计算图片的特征指纹
 * @param string $imgPath 图片路径
 * @return string 64位二进制指纹
 */
function getImageFingerprint(string $imgPath): string {
    // 获取图片基础信息
    $imgInfo = getimagesize($imgPath);
    if (!$imgInfo) return '';
    list($width, $height, $type) = $imgInfo;

    // 根据图片格式创建图像资源
    switch ($type) {
        case IMAGETYPE_JPEG:
            $imgRes = imagecreatefromjpeg($imgPath);
            break;
        case IMAGETYPE_PNG:
            $imgRes = imagecreatefrompng($imgPath);
            break;
        case IMAGETYPE_GIF:
            $imgRes = imagecreatefromgif($imgPath);
            break;
        default:
            return '';
    }

    // 缩放到8*8尺寸
    $sampleSize = 8;
    $sampleRes = imagecreatetruecolor($sampleSize, $sampleSize);
    imagecopyresampled($sampleRes, $imgRes, 0, 0, 0, 0, $sampleSize, $sampleSize, $width, $height);

    // 计算所有像素的灰度值总和
    $graySum = 0;
    $grayArr = [];
    for ($y = 0; $y < $sampleSize; $y++) {
        for ($x = 0; $x < $sampleSize; $x++) {
            // 获取像素RGB值
            $rgb = imagecolorat($sampleRes, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            // 转灰度值
            $gray = intval(0.299 * $r + 0.587 * $g + 0.114 * $b);
            $grayArr[$y][$x] = $gray;
            $graySum += $gray;
        }
    }

    // 计算平均灰度,生成指纹
    $avgGray = $graySum / ($sampleSize * $sampleSize);
    $fingerprint = '';
    for ($y = 0; $y < $sampleSize; $y++) {
        for ($x = 0; $x < $sampleSize; $x++) {
            $fingerprint .= $grayArr[$y][$x] >= $avgGray ? '1' : '0';
        }
    }

    // 释放资源
    imagedestroy($imgRes);
    imagedestroy($sampleRes);
    return $fingerprint;
}

/**
 * 计算两个指纹的汉明距离
 * @param string $fp1 图片1指纹
 * @param string $fp2 图片2指纹
 * @return int 汉明距离,值越小相似度越高
 */
function hammingDistance(string $fp1, string $fp2): int {
    if (strlen($fp1) != strlen($fp2)) return 999;
    $distance = 0;
    for ($i = 0; $i < strlen($fp1); $i++) {
        if ($fp1[$i] != $fp2[$i]) $distance++;
    }
    return $distance;
}

if(isset($_POST['submit'])){
    $filepath = pathinfo($_FILES['file']['name']);
    $extension = strtolower($filepath['extension']);
    // 校验上传文件格式
    $allowExt = ['jpg','jpeg','png','gif'];
    if (!in_array($extension, $allowExt)) {
        exit('仅支持jpg/png/gif格式图片');
    }

    $iname = date('H-i-s').'.'.$extension;
    $path = 'upload/'.$iname;
    if(move_uploaded_file($_FILES['file']['tmp_name'], $path)){
        echo '上传图片路径:' . $path . '<br>';
        echo '匹配到的相似图片:<br>';
        // 计算上传图片的指纹
        $uploadFp = getImageFingerprint($path);
        if (!$uploadFp) exit('上传图片解析失败');

        $images = glob("img/*");
        // 相似度阈值,可自行调整,越小匹配越严格
        $similarThreshold = 5;
        foreach($images as $image){
            $targetFp = getImageFingerprint($image);
            if (!$targetFp) continue;
            $distance = hammingDistance($uploadFp, $targetFp);
            if($distance <= $similarThreshold){
                echo "<img height='70px' width='70px' src='".$image."' style='margin:5px;border:1px solid #ccc;'/>";
                echo "<span>相似度距离:".$distance."</span><br>";
            }
        }
    }
}
?>

前端HTML代码

<html>
<body> 
<form method="post" enctype="multipart/form-data">
    <input type="file" name="file" accept="image/*"><br>
    <input type="submit" name="submit" value="提交查找相似图">
</form>
</body>
</html>

参数调整说明

  • 采样尺寸:代码默认用88采样,需要更高匹配精度可以调整到1616,对应指纹长度变为256位,比对耗时会小幅上升
  • 相似度阈值:默认汉明距离≤5判定为相似,需要严格匹配可以把阈值调到≤2,需要覆盖更多近似编辑的图片可以调到≤8,距离超过10的图片基本不存在内容相似性
  • 格式支持:默认支持jpg/png/gif格式,需要兼容webp可以在getImageFingerprint函数的格式判断分支中添加webp对应的处理逻辑,使用imagecreatefromwebp读取资源即可

内容的提问来源于stack exchange,提问作者user17767322

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 21:42:20