我希望创建一个图像基表,然后将任何新图像与之进行比较,以确定新图像是否与基表完全相同(或接近)。

例如:如果你想减少100次相同图像的存储,你可以存储它的一个副本,并提供它的参考链接。当输入一个新图像时,你想要与现有的图像进行比较,以确保它不是重复的…想法吗?

我的一个想法是缩小到一个小缩略图,然后随机选择100个像素位置并进行比较。


当前回答

我认为值得在此基础上添加我构建的phash解决方案,我们已经使用了一段时间:Image:: phash。它是一个Perl模块,但主要部分是用c语言编写的。它比phash.org快几倍,并且为基于dct的phash提供了一些额外的特性。

我们已经在MySQL数据库上建立了数以千万计的图像索引,所以我想要一些快速的东西,也想要一种使用MySQL索引的方法(这与汉明距离不工作),这导致我使用“减少”哈希进行直接匹配,模块文档讨论了这一点。

使用起来很简单:

use Image::PHash;

my $iph1 = Image::PHash->new('file1.jpg');
my $p1   = $iph1->pHash();

my $iph2 = Image::PHash->new('file2.jpg');
my $p2   = $iph2->pHash();

my $diff = Image::PHash::diff($p1, $p2);

其他回答

如果您有大量的图像,请查看Bloom过滤器,它使用多个散列来获得概率高但效率高的结果。如果图像的数量不是很大,那么像md5这样的加密散列应该足够了。

我所知道的最好的方法是使用感知哈希。似乎有一个很好的开源实现这样的散列可用:

http://phash.org/

其主要思想是,通过识别原始图像文件中的显著特征,并对这些特征进行哈希(而不是直接对图像数据进行哈希),将每张图像简化为一个小的哈希代码或“指纹”。这意味着,相比简单的方法,如将图像缩小到一个小的拇指指纹大小的图像,并比较拇指指纹,假阳性率大大降低。

Phash提供了几种类型的哈希,可用于图像、音频或视频。

几年前,我用PHP编写了一个非常简单的图像比较解决方案。它为每张图像计算一个简单的哈希值,然后找出差值。它的工作非常好裁剪或裁剪与翻译版本的同一图像。

首先,我将图像调整为较小的尺寸,如24x24或36x36。然后我取每一列的像素,并找出这一列的平均R,G,B值。

在每一列都有自己的三个数字之后,我进行两次传递:第一次是奇数列,第二次是偶数列。第一次传递将所有处理过的cols相加,然后除以它们的数([1]+ [2]+ [5]+ [N-1] / (N/2))。第二步以另一种方式进行:([3]-[4]+[6]-[8]…(n /2))。

现在我有两个数。正如我在实验中发现的,第一个是主要的:如果它与另一张图像的值相差甚远,那么从人类的角度来看,它们根本就不相似。

So, the first one represents the average brightness of the image (again, you can pay most attention to green channel, then the red one, etc, but the default R->G->B order works just fine). The second number can be compared if the first two are very close, and it in fact represents the overall contrast of the image: if we have some black/white pattern or any contrast scene (lighted buildings in the city at night, for example) and if we are lucky, we will get huge numbers here if out positive members of sum are mostly bright, and negative ones are mostly dark, or vice versa. As I want my values to be always positive, I divide by 2 and shift by 127 here.

我在2017年用PHP写的代码,似乎我丢失了代码。但我还有截图:

同样的图片:

黑白版:

裁剪版:

另一张图片,翻译版:

和第四色域一样,但另一个场景:

我调整了差异阈值,因此结果非常好。但是正如你所看到的,这个简单的算法对于简单的场景翻译并没有什么好处。

另一方面,我可以注意到,修改可以从两张图像中每一张以75- 80%的比例制作裁剪副本,角落4个,角落和边缘中间8个,然后以同样的方式将裁剪的变体与另一张完整的图像进行比较;如果其中一个相似度得分明显更高,那么就使用它的值而不是默认值)。

我认为值得在此基础上添加我构建的phash解决方案,我们已经使用了一段时间:Image:: phash。它是一个Perl模块,但主要部分是用c语言编写的。它比phash.org快几倍,并且为基于dct的phash提供了一些额外的特性。

我们已经在MySQL数据库上建立了数以千万计的图像索引,所以我想要一些快速的东西,也想要一种使用MySQL索引的方法(这与汉明距离不工作),这导致我使用“减少”哈希进行直接匹配,模块文档讨论了这一点。

使用起来很简单:

use Image::PHash;

my $iph1 = Image::PHash->new('file1.jpg');
my $p1   = $iph1->pHash();

my $iph2 = Image::PHash->new('file2.jpg');
my $p2   = $iph2->pHash();

my $diff = Image::PHash::diff($p1, $p2);

我们笼统地称之为副本的东西,算法很难识别。 你的副本可以是:

确切的副本 接近精确重复。(图像的轻微编辑等) 重复(相同的内容,但不同的视角,相机等)

第一个和第二个更容易解决。3号。是非常主观的,仍然是一个研究课题。 我可以提供1号和2号的解决方案。 这两个解决方案都使用了优秀的图像哈希-哈希库:https://github.com/JohannesBuchner/imagehash

确切的副本 使用感知哈希度量可以找到精确的重复项。 phash库在这方面做得很好。我经常用它来清洁 训练数据。 用法(来自github网站)简单如:

from PIL import Image
import imagehash

# image_fns : List of training image files
img_hashes = {}

for img_fn in sorted(image_fns):
    hash = imagehash.average_hash(Image.open(image_fn))
    if hash in img_hashes:
        print( '{} duplicate of {}'.format(image_fn, img_hashes[hash]) )
    else:
        img_hashes[hash] = image_fn

接近精确复制 在这种情况下,您必须设置一个阈值,并比较它们之间距离的哈希值 其他。这必须通过对图像内容的反复试验来完成。

from PIL import Image
import imagehash

# image_fns : List of training image files
img_hashes = {}
epsilon = 50

for img_fn1, img_fn2 in zip(image_fns, image_fns[::-1]):
    if image_fn1 == image_fn2:
        continue

    hash1 = imagehash.average_hash(Image.open(image_fn1))
    hash2 = imagehash.average_hash(Image.open(image_fn2))
    if hash1 - hash2 < epsilon:
        print( '{} is near duplicate of {}'.format(image_fn1, image_fn2) )