使用Python快速确定图像是否(模糊)在集合中

时间:2015-02-21 20:46:05

标签: python image data-structures

一些新图像X到达的图像,我想知道X是新的还是以前遇到的。我有下面的代码缩小图像,然后将其转换为哈希码。然后,我可以通过单个哈希查找查看是否已经遇到具有相同哈希码的图像,因此它非常快。

我的问题是,是否有一种有效的方法可以让我看到类似图像,但是已经看到了具有不同哈希码的图像?如果要将这个问题称为“数据结构,以便有效地确定是否已经包含类似的,不相同的项目”,但决定这将是the XY problem的实例。

当我说这个新图像是“相似的”时,我正在考虑一个可能经历过有损压缩的图像,因此看起来像原始的人眼但不完全相同。通常缩小图像消除了差异,但并非总是如此,如果我过度缩小图像,我会开始得到误报。

这是我目前的代码:

import PIL
seen_images = {} # This would really be a shelf or something

# From http://www.guguncube.com/1656/python-image-similarity-comparison-using-several-techniques
def image_pixel_hash_code(image):
    pixels = list(image.getdata())
    avg = sum(pixels) / len(pixels)
    bits = "".join(map(lambda pixel: '1' if pixel < avg else '0', pixels))  # '00010100...'
    hexadecimal = int(bits, 2).__format__('016x').upper()
    return hexadecimal

def process_image(filepath):
    thumb = PIL.Image.open(filepath).resize((128,128)).convert("L")
    code = image_pixel_hash_code(thumb)
    previous_image = seen_images.get(code, None)
    if code in seen_images:
        print "'{}' already seen as '{}'".format(filepath, previous_image)
    else:
        seen_images[code] = filepath

您可以将一堆图像文件的路径放入名为IMAGE_ROOT的变量中,然后尝试使用以下代码:

import os
for root, dirs, files in os.walk(IMAGE_ROOT):
    for filename in files:
        filepath = os.path.join(root, filename)
        try:                
            process_image(filepath)
        except IOError:
            pass

1 个答案:

答案 0 :(得分:0)

有很多方法可以比较图像,但是对于你给出的例子,我怀疑简单性和速度是关键因素(因此你为什么要尝试使用哈希作为第一遍)。以下是一些建议 - 在所有情况下,我都建议将图像缩小并裁剪为常规尺寸和形状。

  1. 在收缩前平滑图像(高斯模糊)以最大限度地减少人工制品的影响。然后应用哈希或其他比较。
  2. 相互减去图像(RGB)并检查剩余部分。相同的图像将返回零,压缩假象将导致小的微小变化。您可以对该值进行阈值,求和或平均值,并与截止值进行比较。
  3. 使用标准距离算法(参见scipy.spatial.distance)计算两幅图像之间的“距离”。例如,euclidean距离将有效地与减去的总和相同,而cosine将忽略敏感但匹配图像上的变化的轮廓,即相同图像的较暗版本将被认为是等同的。对于这些,您需要将图像展平为一维阵列。
  4. 最后两个需要在上传时将每个图像与每个其他图像进行比较,这对于大量图像而言计算成本非常高。