如何在PHP中检测相似的图像?

3

我有很多相同图片的不同分辨率文件,适用于各种设备,如手机、电脑、PSP等。现在我想在页面上仅显示唯一的图片,但我不知道怎么做。如果一开始就维护了数据库,我本可以避免这个问题,但是我没有。我需要你的帮助来检测最大的独特图片。


2
名字都没有相似之处吗?否则,最终你会得到一个N:M的比较情况(如果你找到了一种适合的算法)。或许这个链接可以帮到你:https://dev59.com/cnI-5IYBdhLWcg3wCz3y,但请记住,如果有1000张图片,那么就需要进行999999次比较操作。 - Hannes
2
如果你一开始没有维护数据库,那么现在就要开始了。如果过去犯了错误,并不意味着你必须继续下去并围绕这个错误扭曲所有的代码/逻辑。 - Poelinca Dorin
2
哇,从CPU周期的角度来看,这将非常昂贵。你需要使用与第一次相同的算法缩小每个图像A(A是两者中较大的图像)。如果缩小后的A和B是等价的,请以某种方式存储这些信息并继续处理下一对。这可能是O(N²),所以如果你处理大量数据,你应该三思而行。我认为你应该修复你的数据库。无论如何。 - jwueller
1
@elusive,我以前没有维护过任何数据库,但我正在尝试,因此我需要独特且最大的图像... - mrN
2
@mrNepal:每次比较只有10毫秒:30000*30000*10/1000/60/60/24 = 104.17。你需要超过一百天才能完成这项任务。好耶! - jwueller
显示剩余3条评论
4个回答

15

安装gd2和lib puzzle到您的服务器。

Lib puzzle非常惊人且易于使用。查看这个片段:

<?php
# Compute signatures for two images
$cvec1 = puzzle_fill_cvec_from_file('img1.jpg');
$cvec2 = puzzle_fill_cvec_from_file('img2.jpg');

# Compute the distance between both signatures
$d = puzzle_vector_normalized_distance($cvec1, $cvec2);

# Are pictures similar?
if ($d < PUZZLE_CVEC_SIMILARITY_LOWER_THRESHOLD) {
  echo "Pictures are looking similar\n";
} else {
  echo "Pictures are different, distance=$d\n";
}

# Compress the signatures for database storage
$compress_cvec1 = puzzle_compress_cvec($cvec1);
$compress_cvec2 = puzzle_compress_cvec($cvec2);

2

虽然有很多算法可以做到这一点,但我认为手动操作仍然会更快。下载所有图片并将它们输入到类似于Windows Live照片库或其他能够匹配相似图像的软件中。这可能需要几个小时,但实施图像匹配算法可能需要更长时间。之后,您可以花费额外的时间来修改当前系统以将所有内容存储在数据库中。 修复问题的原因,而不是其症状。


问题不在于“为什么你应该或不应该在PHP中检测相似的图像” - 你不可能知道人们需要在PHP中比较图像的所有原因的排列组合。说要手动完成,不是对实际问题的好答案。 - Dave Hilditch

0
首先,您的问题与PHP几乎没有任何关系,因此我已删除了该标签并添加了更相关的标签。

聪明地做这件事不需要NxN比较。你可以使用很多启发式方法,但首先我想问你:

  1. 所有图像的副本是否完全调整大小(是否进行了一些裁剪-将裁剪后的图像与原始图像匹配可能更加困难和耗时)?

  2. 所有生成的图像(调整大小)是否使用相同的工具?

  3. 关于您用于调整大小的参数如何?例如,所有用于在PSP上显示的图片分辨率相同吗?

  4. 您估计有多少个唯一的图像(即每张图片可能有多少个副本-平均而言)?

  5. 您是否已经完成任何分类?例如,所有移动图像是否在单独的文件夹中(或者分辨率与PC图像不同)?仅此就可以大大减少比较的数量,即使您以其他方式进行暴力搜索。

一个关于为什么不需要NxN比较的高层次提示:你可以设计许多不同的近似哈希(例如,高/低频JPEG系数的分布),并将“可能”相似的图像分组在一起。这可以将所需的比较次数减少10-100倍甚至更多,具体取决于所使用的启发式质量和数据集。哈希甚至可以针对图像的部分进行。如果使用正确的技术,30000并不是非常大的数字。

是的,它们已经被裁剪和调整大小,图像分别为480x272、800x600、1024x768、1280x1024、1600x1200、1600x1080、1920x1080、1920x1200、2560x1600。大约有3500张独特的图像,每个图像会制作9个完全相同的副本。至于分类...我将这些图像放置在大约30个文件夹中,每个文件夹包含1000张图片,在超过大小限制后将创建并放置新的文件夹,文件名是随机的以获得不同的图像。 - mrN
然后我从每个文件夹中随机选择大约20张图片,并创建一个文件列表。接着,我将它们通过一个函数进行处理,按照大小排序,并在它们存在的情况下自动复制到我的相应设备上。 - mrN
上传后,裁剪算法会自动进行......我将图像调整为指定高度,然后居中到特定分辨率,通常提供2560 x 1600的图像尺寸。如果我先上传了更大的图像,则会选择2560 x 1600的图像,并且源图像将被丢弃。 - mrN
我认为,像C++这样的语言或者像ImageMagick这样的工具在图像处理方面会快很多。如果你需要一个在线界面和/或不是一次性任务,那么你应该使用PHP来做某些事情。当然,尝试一下PHP的GD库也没有任何伤害(但我怀疑它是否有任何比较快的替代功能)。 - JP19
@mrNepal:当你说9个完全相同的副本时,我认为这些是你想要匹配的副本。我的意思是,将一张图像与其裁剪版本进行匹配将会很困难。如果所有的副本都是从原始图像裁剪出来的,但是它们是完全相同的,那就不应该有问题。我支持伊万的建议。 - JP19
显示剩余2条评论

-1

你应该检查哪个图像是最小的,取其大小,然后仅比较矩形大小内的像素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接