当前位置:首页 > PHP

php实现相似图片

2026-02-16 22:17:52PHP

相似图片检测方法

使用感知哈希(pHash)

感知哈希通过计算图片的哈希值来比较相似度。常用方法包括平均哈希(aHash)、差异哈希(dHash)和感知哈希(pHash)。以下是使用PHP-GD库实现pHash的示例:

php实现相似图片

function calculatePHash($imagePath) {
    $size = 32;
    $smallerSize = 8;

    $image = imagecreatefromstring(file_get_contents($imagePath));
    list($width, $height) = getimagesize($imagePath);

    $resized = imagecreatetruecolor($size, $size);
    imagecopyresampled($resized, $image, 0, 0, 0, 0, $size, $size, $width, $height);
    imagedestroy($image);

    $grayscale = array();
    for ($y = 0; $y < $size; $y++) {
        for ($x = 0; $x < $size; $x++) {
            $rgb = imagecolorat($resized, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            $grayscale[$y][$x] = 0.299 * $r + 0.587 * $g + 0.114 * $b;
        }
    }
    imagedestroy($resized);

    $dct = array();
    for ($u = 0; $u < $smallerSize; $u++) {
        for ($v = 0; $v < $smallerSize; $v++) {
            $sum = 0;
            for ($x = 0; $x < $size; $x++) {
                for ($y = 0; $y < $size; $y++) {
                    $sum += $grayscale[$y][$x] * 
                           cos((2 * $x + 1) * $u * M_PI / (2 * $size)) * 
                           cos((2 * $y + 1) * $v * M_PI / (2 * $size));
                }
            }
            $dct[$u][$v] = $sum;
        }
    }

    $avg = array_sum(array_map('array_sum', $dct)) / ($smallerSize * $smallerSize);
    $hash = '';
    for ($u = 0; $u < $smallerSize; $u++) {
        for ($v = 0; $v < $smallerSize; $v++) {
            $hash .= ($dct[$u][$v] > $avg) ? '1' : '0';
        }
    }
    return $hash;
}

function hammingDistance($hash1, $hash2) {
    $distance = 0;
    $len = min(strlen($hash1), strlen($hash2));
    for ($i = 0; $i < $len; $i++) {
        if ($hash1[$i] != $hash2[$i]) {
            $distance++;
        }
    }
    return $distance;
}

使用颜色直方图比较

颜色直方图通过统计图片中颜色分布来比较相似度:

php实现相似图片

function compareHistograms($imagePath1, $imagePath2) {
    $bins = 8;
    $hist1 = calculateHistogram($imagePath1, $bins);
    $hist2 = calculateHistogram($imagePath2, $bins);

    $sum = 0;
    for ($i = 0; $i < $bins * $bins * $bins; $i++) {
        $sum += min($hist1[$i], $hist2[$i]);
    }
    return $sum;
}

function calculateHistogram($imagePath, $bins) {
    $image = imagecreatefromstring(file_get_contents($imagePath));
    $width = imagesx($image);
    $height = imagesy($image);

    $histogram = array_fill(0, $bins * $bins * $bins, 0);
    for ($x = 0; $x < $width; $x++) {
        for ($y = 0; $y < $height; $y++) {
            $rgb = imagecolorat($image, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;

            $rBin = floor($r / (256 / $bins));
            $gBin = floor($g / (256 / $bins));
            $bBin = floor($b / (256 / $bins));

            $index = $rBin * $bins * $bins + $gBin * $bins + $bBin;
            $histogram[$index]++;
        }
    }
    imagedestroy($image);

    $total = $width * $height;
    return array_map(function($val) use ($total) {
        return $val / $total;
    }, $histogram);
}

使用OpenCV扩展

PHP可通过OpenCV扩展实现更高级的相似度检测:

$image1 = cv\imread('image1.jpg', cv\IMREAD_COLOR);
$image2 = cv\imread('image2.jpg', cv\IMREAD_COLOR);

$orb = cv\ORB::create();
$keypoints1 = new cv\KeyPoint();
$keypoints2 = new cv\KeyPoint();
$descriptors1 = new cv\Mat();
$descriptors2 = new cv\Mat();

$orb->detectAndCompute($image1, null, $keypoints1, $descriptors1);
$orb->detectAndCompute($image2, null, $keypoints2, $descriptors2);

$matcher = cv\BFMatcher::create(cv\NORM_HAMMING, true);
$matches = new cv\DMatch();
$matcher->match($descriptors1, $descriptors2, $matches);

$similarity = 0;
foreach ($matches as $match) {
    $similarity += $match->distance;
}
$similarity = 1 - ($similarity / count($matches) / 256);

使用机器学习服务

对于大规模应用,可考虑集成云端API:

function compareWithCloudAPI($image1, $image2) {
    $client = new \GuzzleHttp\Client();
    $response = $client->post('https://api.cloudvision.com/v1/similarity', [
        'json' => [
            'image1' => base64_encode(file_get_contents($image1)),
            'image2' => base64_encode(file_get_contents($image2))
        ]
    ]);
    return json_decode($response->getBody(), true)['similarity'];
}

性能优化建议

  • 预处理哈希值并存入数据库
  • 对大型图集使用KD树或LSH索引
  • 考虑使用Redis缓存比较结果
  • 对批量处理使用队列系统

注意事项

  • 光照变化会影响颜色直方图方法
  • 几何变换会影响特征点匹配
  • pHash对内容变化敏感但对格式变化鲁棒
  • 商业应用需考虑版权问题

标签: 相似图片
分享给朋友:

相关文章

vue 实现图片

vue 实现图片

Vue 实现图片加载与展示的方法 在 Vue 中实现图片加载和展示可以通过多种方式完成,以下是一些常见的方法: 使用 v-bind 绑定图片路径 通过 v-bind(或简写为 :)动态绑定图片…

vue实现图片预览

vue实现图片预览

Vue 实现图片预览的方法 使用 Element UI 的 el-image 组件 Element UI 提供了 el-image 组件,支持图片预览功能。通过设置 preview-src-list…

css制作图片

css制作图片

CSS 制作图片的方法 使用 background-image 属性 通过 background-image 属性可以为元素设置背景图片。这种方法适用于将图片作为背景而非内容的一部分。 .eleme…

js实现图片轮播

js实现图片轮播

实现基础图片轮播 使用HTML、CSS和JavaScript创建一个简单的图片轮播。HTML部分定义轮播容器和图片,CSS设置样式和动画效果,JavaScript处理轮播逻辑。 <div cl…

H5图片实现地图

H5图片实现地图

实现H5图片地图的方法 在H5中实现图片地图功能,可以通过以下方式完成。图片地图允许用户在图片的特定区域点击,触发不同的交互效果。 使用HTML的<map>和<area>标签…

react如何渲染图片

react如何渲染图片

在React中渲染图片的方法 使用<img>标签直接引入本地图片 将图片文件放入项目目录(如src/assets),通过相对路径引入。需注意Webpack可能需要配置file-loader…