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

check if there is Exactly the same image as input image

我想知道如何在海量数据中查找图像(文件夹中有很多图像)并且我想查找正好[=的图像21=] 与输入图像相同(给定来自另一个不在数据文件夹中的文件夹的输入图像)并将输入图像与所有海量数据进行比较,如果发现完全相同的图像,则显示其名称作为输出(文件夹中相同图像的名称,而不是输入名称)(例如:dafs.jpg

使用python

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

但我不知道如何在 python

中做到这一点

比较 RGB 像素值

您可以使用 pillow module to get access to the pixel data of a particular image. Keep in mind that pillow supports these image formats.

如果我们根据您的描述对两张图片相同意味着什么做出一些假设,则两张图片必须:

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

那么如果我们有 2 张图像使用 pillow 模块

from PIL import Image

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

下面的代码将能够比较 2 个图像以查看它们是否相同

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)

注意上面的实现只会找到第一个重复的,和return那个。如果没有找到重复项,None 将被 returned。

要记住的一件事是,像这样对每个像素执行比较的成本可能很高。我使用了 this image and ran compare_images using this as the input and the output 100 times using the timeit 模块,并取了所有这些运行的平均值

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 像素的图像上完成的。如果您使用一组 "massive" 可能的重复图像执行此操作,我将 "massive" 表示至少 100 万张相似尺寸的图像,这可能需要大约 15 天(1,000,000 * 1.28s / 60秒/60 分钟/24 小时)遍历并将每个输出图像与输入进行比较,这并不理想。

另请记住,这些指标会因您使用的机器和操作系统而异。我提供的数字更多是为了说明目的。

替代实施

虽然我自己还没有完全探索这个实现,但您可以尝试的一种方法是使用 [=26= 预先计算 collection 中每个图像的像素数据的哈希值].如果您将这些存储在数据库中,每个散列包含原始图像或图像名称的 link,那么您所要做的就是使用相同的散列函数计算输入图像的散列并比较散列反而。这将花费相同的大量计算时间,并且会产生更高效的算法。

This blog post 描述了一种实现方式。

更新 - 2018-08-06

根据 OP 的要求,如果您获得了可能重复图像的目录而不是显式图像路径本身,那么您可以使用 osntpath 模块,例如所以

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))

如果有重复,上面只会打印重复图像的名称,否则什么也不会打印。