导读:本期聚焦于小伙伴创作的《PHP图像相似度计算方法详解:感知哈希、直方图与像素对比算法》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《PHP图像相似度计算方法详解:感知哈希、直方图与像素对比算法》有用,将其分享出去将是对创作者最好的鼓励。

PHP图像相似度计算方法详解

在图像处理相关开发中,经常需要判断两张图像是否相似,或者计算它们的相似程度。PHP作为常用的后端开发语言,提供了GD、Imagick等扩展支持图像处理,结合不同的算法可以实现图像相似度计算。本文将介绍三种常用的PHP图像相似度计算算法,并给出对应的实现示例。

一、感知哈希算法(pHash)

感知哈希算法是计算图像相似度的常用方法,核心思路是将图像缩小到固定尺寸,转换为灰度图后计算哈希值,最后通过汉明距离判断相似度。汉明距离越小,说明两张图像越相似。

实现步骤

  • 将图像缩放到固定尺寸(通常为32x32或64x64)

  • 转换为灰度图,计算每个像素的灰度值

  • 计算所有像素灰度值的平均值

  • 将每个像素的灰度值与平均值比较,大于平均值记为1,否则记为0,生成哈希字符串

  • 计算两张图像哈希值的汉明距离,转换为相似度百分比

PHP实现代码

<?php
/**
 * 计算图像的感知哈希值
 * @param string $imagePath 图像路径
 * @param int $size 缩放尺寸,默认32
 * @return string 哈希值字符串
 */
function getPerceptualHash($imagePath, $size = 32) {
    // 检查图像是否存在
    if (!file_exists($imagePath)) {
        return '';
    }
    // 获取图像信息
    $imageInfo = getimagesize($imagePath);
    if (!$imageInfo) {
        return '';
    }
    // 根据图像类型创建资源
    switch ($imageInfo[2]) {
        case IMAGETYPE_JPEG:
            $img = imagecreatefromjpeg($imagePath);
            break;
        case IMAGETYPE_PNG:
            $img = imagecreatefrompng($imagePath);
            break;
        case IMAGETYPE_GIF:
            $img = imagecreatefromgif($imagePath);
            break;
        default:
            return '';
    }
    if (!$img) {
        return '';
    }
    // 缩放图像
    $resizeImg = imagecreatetruecolor($size, $size);
    imagecopyresampled($resizeImg, $img, 0, 0, 0, 0, $size, $size, $imageInfo[0], $imageInfo[1]);
    // 转换为灰度图
    for ($i = 0; $i < $size; $i++) {
        for ($j = 0; $j < $size; $j++) {
            $rgb = imagecolorat($resizeImg, $i, $j);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            $gray = round(0.299 * $r + 0.587 * $g + 0.114 * $b);
            $grayColor = imagecolorallocate($resizeImg, $gray, $gray, $gray);
            imagesetpixel($resizeImg, $i, $j, $grayColor);
        }
    }
    // 计算平均灰度值
    $totalGray = 0;
    for ($i = 0; $i < $size; $i++) {
        for ($j = 0; $j < $size; $j++) {
            $rgb = imagecolorat($resizeImg, $i, $j);
            $gray = $rgb & 0xFF;
            $totalGray += $gray;
        }
    }
    $avgGray = $totalGray / ($size * $size);
    // 生成哈希值
    $hash = '';
    for ($i = 0; $i < $size; $i++) {
        for ($j = 0; $j < $size; $j++) {
            $rgb = imagecolorat($resizeImg, $i, $j);
            $gray = $rgb & 0xFF;
            $hash .= $gray >= $avgGray ? '1' : '0';
        }
    }
    // 释放资源
    imagedestroy($img);
    imagedestroy($resizeImg);
    return $hash;
}

/**
 * 计算汉明距离
 * @param string $hash1 哈希值1
 * @param string $hash2 哈希值2
 * @return int 汉明距离
 */
function hammingDistance($hash1, $hash2) {
    $len = strlen($hash1);
    if ($len != strlen($hash2)) {
        return -1;
    }
    $distance = 0;
    for ($i = 0; $i < $len; $i++) {
        if ($hash1[$i] != $hash2[$i]) {
            $distance++;
        }
    }
    return $distance;
}

/**
 * 计算两张图像的相似度百分比
 * @param string $image1 图像1路径
 * @param string $image2 图像2路径
 * @param int $size 哈希计算缩放尺寸
 * @return float 相似度百分比,0-100
 */
function calcPhashSimilarity($image1, $image2, $size = 32) {
    $hash1 = getPerceptualHash($image1, $size);
    $hash2 = getPerceptualHash($image2, $size);
    if (empty($hash1) || empty($hash2)) {
        return 0;
    }
    $distance = hammingDistance($hash1, $hash2);
    if ($distance == -1) {
        return 0;
    }
    $maxDistance = $size * $size;
    return round((1 - $distance / $maxDistance) * 100, 2);
}

// 使用示例
$image1 = 'test1.jpg';
$image2 = 'test2.jpg';
$similarity = calcPhashSimilarity($image1, $image2);
echo "两张图像的感知哈希相似度为:{$similarity}%";
?>

二、直方图相似度算法

直方图相似度算法的核心是统计图像的颜色分布,通过计算两张图像直方图的相似程度来判断图像相似性。该算法对颜色敏感,适合颜色特征明显的图像对比。

实现步骤

  • 将图像缩放为较小尺寸(如64x64),减少计算量

  • 分别统计红、绿、蓝三个通道的像素值分布,将0-255的像素值区间划分为若干等级(如16级)

  • 计算两张图像对应通道直方图的余弦相似度

  • 综合三个通道的相似度得到最终相似度

PHP实现代码

<?php
/**
 * 计算图像的颜色直方图
 * @param string $imagePath 图像路径
 * @param int $size 缩放尺寸,默认64
 * @param int $level 直方图等级数,默认16
 * @return array 包含r、g、b三个通道直方图数据的数组
 */
function getImageHistogram($imagePath, $size = 64, $level = 16) {
    if (!file_exists($imagePath)) {
        return [];
    }
    $imageInfo = getimagesize($imagePath);
    if (!$imageInfo) {
        return [];
    }
    switch ($imageInfo[2]) {
        case IMAGETYPE_JPEG:
            $img = imagecreatefromjpeg($imagePath);
            break;
        case IMAGETYPE_PNG:
            $img = imagecreatefrompng($imagePath);
            break;
        case IMAGETYPE_GIF:
            $img = imagecreatefromgif($imagePath);
            break;
        default:
            return [];
    }
    if (!$img) {
        return [];
    }
    // 缩放图像
    $resizeImg = imagecreatetruecolor($size, $size);
    imagecopyresampled($resizeImg, $img, 0, 0, 0, 0, $size, $size, $imageInfo[0], $imageInfo[1]);
    // 初始化直方图数组
    $rHist = array_fill(0, $level, 0);
    $gHist = array_fill(0, $level, 0);
    $bHist = array_fill(0, $level, 0);
    // 统计像素值
    for ($i = 0; $i < $size; $i++) {
        for ($j = 0; $j < $size; $j++) {
            $rgb = imagecolorat($resizeImg, $i, $j);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            // 计算所属的等级
            $rLevel = intval($r / (256 / $level));
            $gLevel = intval($g / (256 / $level));
            $bLevel = intval($b / (256 / $level));
            // 边界处理
            if ($rLevel >= $level) $rLevel = $level - 1;
            if ($gLevel >= $level) $gLevel = $level - 1;
            if ($bLevel >= $level) $bLevel = $level - 1;
            $rHist[$rLevel]++;
            $gHist[$gLevel]++;
            $bHist[$bLevel]++;
        }
    }
    imagedestroy($img);
    imagedestroy($resizeImg);
    return ['r' => $rHist, 'g' => $gHist, 'b' => $bHist];
}

/**
 * 计算两个直方图的余弦相似度
 * @param array $hist1 直方图1
 * @param array $hist2 直方图2
 * @return float 相似度,0-1之间
 */
function histogramCosineSimilarity($hist1, $hist2) {
    $len = count($hist1);
    if ($len != count($hist2)) {
        return 0;
    }
    $dotProduct = 0;
    $norm1 = 0;
    $norm2 = 0;
    for ($i = 0; $i < $len; $i++) {
        $dotProduct += $hist1[$i] * $hist2[$i];
        $norm1 += $hist1[$i] * $hist1[$i];
        $norm2 += $hist2[$i] * $hist2[$i];
    }
    if ($norm1 == 0 || $norm2 == 0) {
        return 0;
    }
    return $dotProduct / (sqrt($norm1) * sqrt($norm2));
}

/**
 * 计算两张图像的直方图相似度
 * @param string $image1 图像1路径
 * @param string $image2 图像2路径
 * @return float 相似度百分比,0-100
 */
function calcHistogramSimilarity($image1, $image2) {
    $hist1 = getImageHistogram($image1);
    $hist2 = getImageHistogram($image2);
    if (empty($hist1) || empty($hist2)) {
        return 0;
    }
    $rSim = histogramCosineSimilarity($hist1['r'], $hist2['r']);
    $gSim = histogramCosineSimilarity($hist1['g'], $hist2['g']);
    $bSim = histogramCosineSimilarity($hist1['b'], $hist2['b']);
    // 三个通道取平均,转换为百分比
    return round(($rSim + $gSim + $bSim) / 3 * 100, 2);
}

// 使用示例
$image1 = 'test1.jpg';
$image2 = 'test2.jpg';
$similarity = calcHistogramSimilarity($image1, $image2);
echo "两张图像的直方图相似度为:{$similarity}%";
?>

三、像素对比算法

像素对比算法是最直接的相似度计算方式,将两张图像缩放到相同尺寸后,逐个像素比较RGB值的差异,计算平均差异后转换为相似度。该方法精度较高,但计算量相对较大,适合小尺寸图像对比。

实现步骤

  • 将两张图像缩放到相同的固定尺寸(如32x32)

  • 逐个像素对比两张图像的R、G、B值,计算每个通道的差值绝对值

  • 计算所有像素差值的均值,转换为相似度百分比

PHP实现代码

<?php
/**
 * 计算两张图像的像素对比相似度
 * @param string $image1 图像1路径
 * @param string $image2 图像2路径
 * @param int $size 缩放尺寸,默认32
 * @return float 相似度百分比,0-100
 */
function calcPixelSimilarity($image1, $image2, $size = 32) {
    if (!file_exists($image1) || !file_exists($image2)) {
        return 0;
    }
    $info1 = getimagesize($image1);
    $info2 = getimagesize($image2);
    if (!$info1 || !$info2) {
        return 0;
    }
    // 创建图像资源
    switch ($info1[2]) {
        case IMAGETYPE_JPEG:
            $img1 = imagecreatefromjpeg($image1);
            break;
        case IMAGETYPE_PNG:
            $img1 = imagecreatefrompng($image1);
            break;
        case IMAGETYPE_GIF:
            $img1 = imagecreatefromgif($image1);
            break;
        default:
            return 0;
    }
    switch ($info2[2]) {
        case IMAGETYPE_JPEG:
            $img2 = imagecreatefromjpeg($image2);
            break;
        case IMAGETYPE_PNG:
            $img2 = imagecreatefrompng($image2);
            break;
        case IMAGETYPE_GIF:
            $img2 = imagecreatefromgif($image2);
            break;
        default:
            return 0;
    }
    if (!$img1 || !$img2) {
        return 0;
    }
    // 缩放图像到相同尺寸
    $resize1 = imagecreatetruecolor($size, $size);
    $resize2 = imagecreatetruecolor($size, $size);
    imagecopyresampled($resize1, $img1, 0, 0, 0, 0, $size, $size, $info1[0], $info1[1]);
    imagecopyresampled($resize2, $img2, 0, 0, 0, 0, $size, $size, $info2[0], $info2[1]);
    // 计算像素差异
    $totalDiff = 0;
    $pixelCount = $size * $size;
    for ($i = 0; $i < $size; $i++) {
        for ($j = 0; $j < $size; $j++) {
            $rgb1 = imagecolorat($resize1, $i, $j);
            $rgb2 = imagecolorat($resize2, $i, $j);
            $r1 = ($rgb1 >> 16) & 0xFF;
            $g1 = ($rgb1 >> 8) & 0xFF;
            $b1 = $rgb1 & 0xFF;
            $r2 = ($rgb2 >> 16) & 0xFF;
            $g2 = ($rgb2 >> 8) & 0xFF;
            $b2 = $rgb2 & 0xFF;
            // 每个通道的差值绝对值之和,最大差值为255*3
            $diff = abs($r1 - $r2) + abs($g1 - $g2) + abs($b1 - $b2);
            $totalDiff += $diff;
        }
    }
    // 释放资源
    imagedestroy($img1);
    imagedestroy($img2);
    imagedestroy($resize1);
    imagedestroy($resize2);
    // 最大总差值为 $pixelCount * 255 * 3
    $maxDiff = $pixelCount * 255 * 3;
    $similarity = round((1 - $totalDiff / $maxDiff) * 100, 2);
    return $similarity;
}

// 使用示例
$image1 = 'test1.jpg';
$image2 = 'test2.jpg';
$similarity = calcPixelSimilarity($image1, $image2);
echo "两张图像的像素对比相似度为:{$similarity}%";
?>

四、算法对比与选择建议

三种算法的特点和使用场景各不相同,开发者可以根据实际需求选择:

算法类型计算速度精度适用场景
感知哈希算法中等需要快速判断图像是否相似,对轻微修改(如缩放、压缩)不敏感的场景
直方图相似度算法中等中等偏上颜色特征明显的图像对比,如风景、物品类图像
像素对比算法小尺寸图像,需要高精度对比的场景

如果需要更高精度的图像相似度计算,也可以结合多种算法的结果进行综合判断,比如在感知哈希相似度高于阈值后再使用像素对比算法进一步验证。

注意事项

  • 使用GD扩展前需要确保PHP已开启GD扩展,可以通过phpinfo()函数查看扩展状态

  • 处理大尺寸图像时建议先缩放,避免占用过多内存

  • 不同算法的阈值需要根据实际测试调整,例如感知哈希的汉明距离小于5可以认为图像高度相似

  • 如果图像存在旋转、裁剪等大幅修改,上述算法可能不适用,需要结合图像特征点匹配等更复杂的方案

PHP图像相似度感知哈希算法直方图相似度像素对比图像处理

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。