检查是否存在与输入图像完全相同的图像

时间:2018-08-04 17:47:37

标签: python compare subtraction

我想知道如何在海量数据中查找图像(文件夹中有很多图像),并且我想查找 完全 的图像与输入图像相同(给出来自不在数据文件夹中的另一个文件夹的输入图像),并将输入图像与所有海量数据进行比较(如果找到了“完全相同”图像),则将其名称显示为output(文件夹中的图像相同,但未输入名称)(例如:dafs.jpg

使用python

我正在考虑比较RGB像素的确切值,并从文件夹中的每个图像中减去输入图像的像素

但是我不知道如何在python中做到这一点

1 个答案:

答案 0 :(得分:0)

比较RGB像素值

您可以使用pillow模块来访问特定图像的像素数据。请记住,pillow支持these image formats

如果我们根据您的描述对两张图片相同的含义作一些假设,则两张图片必须:

  • 具有相同的尺寸(高度和宽度)
  • 具有相同的RGB像素值(输入图像中像素[x,y]的RGB值必须与输出图像中像素[x,y]的RGB值相同)
  • 方向相同(与先前的假设有关,与旋转90度的同一图像相比,该图像被视为不相同)

然后如果我们使用pillow模块获得2张图片

from PIL import Image

original = Image.open("input.jpg")
possible_duplicate = Image.open("output.jpg")

以下代码将能够比较两张图片,看它们是否相同

def compare_images(input_image, output_image):
  # compare image dimensions (assumption 1)
  if input_image.size != output_image.size:
    return False

  rows, cols = input_image.size

  # compare image pixels (assumption 2 and 3)
  for row in range(rows):
    for col in range(cols):
      input_pixel = input_image.getpixel((row, col))
      output_pixel = output_image.getpixel((row, col))
      if input_pixel != output_pixel:
        return False

  return True

通过致电

compare_images(original, possible_duplicate)

使用此功能,我们可以浏览一组图像

from PIL import Image

def find_duplicate_image(input_image, output_images):
  # only open the input image once
  input_image = Image.open(input_image)

  for image in output_images:
    if compare_images(input_image, Image.open(image)):
      return image

将它们放在一起,我们可以简单地调用

original = "input.jpg"
possible_duplicates = ["output.jpg", "output2.jpg", ...]

duplicate = find_duplicate_image(original, possible_duplicates)

请注意,上述实现只会找到 first 重复项,然后将其返回。如果找不到重复项,将返回None

要记住的一件事是,像这样对每个像素执行比较可能会很昂贵。我使用this image并使用timeit模块将compare_images用作输入和输出100次,并取了所有这些运行的平均值

num_trials = 100
trials = timeit.repeat(
    repeat=num_trials,
    number=1,
    stmt="compare_images(Image.open('input.jpg'), Image.open('input.jpg'))",
    setup="from __main__ import compare_images; from PIL import Image"
)
avg = sum(trials) / num_trials

print("Average time taken per comparison was:", avg, "seconds")

# Average time taken per comparison was 1.3337286046380177 seconds

请注意,这是在只有600 x 600像素的图像上完成的。如果您使用一组“大量”的可能重复图像进行此操作,而我将“大量”表示至少100万张类似尺寸的图像,则这可能需要约15天的时间(1,000,000 * 1.28s / 60秒/ 60分钟/ 24小时),将每个输出图像与输入图像进行比较,这并不理想。

还请记住,这些指标将根据您使用的计算机和操作系统而有所不同。我提供的数字仅供参考。

替代实现

虽然我本人还没有完全研究过此实现,但是您可以尝试的一种方法是使用hash function预计算集合中每个图像的像素数据的哈希值。如果将它们存储在数据库中,并且每个散列都包含指向原始图像或图像名称的链接,那么您要做的就是使用相同的散列函数计算输入图像的散列,然后比较散列。这将花费大量的计算时间,并使算法效率更高。

This blog post描述了一种实现此目的的方法。

更新-2018-08-06

根据OP的要求,如果为您提供了可能的重复图像的目录,而不是明确的图像路径本身,则可以像这样使用osntpath模块< / p>

import ntpath
import os

def get_all_images(directory):
  image_paths = []

  for filename in os.listdir(directory):
    # to be as careful as possible, you might check to make sure that
    # the file is in fact an image, for instance using
    # filename.endswith(".jpg") to check for .jpg files for instance
    image_paths.append("{}/{}".format(directory, filename))

  return image_paths

def get_filename(path):
  return ntpath.basename(path)

使用这些功能,更新后的程序可能看起来像

possible_duplicates = get_all_images("/path/to/images")
duplicate_path = find_duplicate_image("/path/to/input.jpg", possible_duplicates)
if duplicate_path:
  print(get_filename(duplicate_path))

以上仅在存在重复图像的情况下打印名称,否则将不打印任何内容。