在 Python 中比 MSE 更好地比较图像的快速技术

问题描述

我一直在使用结构相似性指数(通过 tensorflow)来比较图像,但是它花费的时间太长。我想知道是否有一种不需要太多时间的替代技术。如果有人能指出比 Python 中的 tensorflow 更有效的 SSIM 实现也没关系。

我使用 SSIM 的意图是,给定一个参考图像 (A) 和一组 图像 (B),我需要了解 B 中的哪个图像与参考图像最相似A.

解决方法

更新 01-02-2021

我决定探索一些可用于图像比较的其他 Python 模块。我还想使用 concurrent.futures,我以前没有使用过。

我使用自己编写的代码创建了两个 GitGub Gist

skimage ssim image comparison

ImageHash aHash image comparison

ImageHash 模块能够在 0.29 秒内比较 100 张图像,而 skimage 模块在同一任务中花费 1.2 秒。


原帖

我没有测试这个答案中代码的速度,因为我只在我发布到 GitHub 的一些图像测试中使用了代码:

facial similarities

facial prediction

下面的代码将生成参考图像 (A) 和图像集 (B) 之间的相似度得分。

完整代码位于in my GitHub repository

import os
from os import walk
import numpy as np
from PIL import Image
from math import *


def get_image_files(directory_of_images):
    """
     This function is designed to traverse a directory tree and extract all
     the image names contained in the directory.
    :param directory_of_images: the name of the target directory containing
           the images to be trained on.
    :return: list of images to be processed.
    """
    images_to_process = []
    for (dirpath,dirnames,filenames) in walk(directory_of_images):
        for filename in filenames:
            accepted_extensions = ('.bmp','.gif','.jpg','.jpeg','.png','.svg','.tiff')
            if filename.endswith(accepted_extensions):
                images_to_process.append(os.path.join(dirpath,filename))
        return images_to_process


def pre_process_images(image_one,image_two,additional_resize=False,max_image_size=1000):
    """
     This function is designed to resize the images using the Pillow module.
    :param image_one: primary image to evaluate against a secondary image
    :param image_two: secondary image to evaluate against the primary image
    :param additional_resize:
    :param max_image_size: maximum allowable image size in pixels
    :return: resized images
    """
    lower_boundary_size = (min(image_one.size[0],image_two.size[0]),min(image_one.size[1],image_two.size[1]))
    # reference: https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize
    # reference: https://pillow.readthedocs.io/en/stable/handbook/concepts.html#PIL.Image.LANCZOS
    image_one = image_one.resize(lower_boundary_size,resample=Image.LANCZOS)
    image_two = image_two.resize(lower_boundary_size,resample=Image.LANCZOS)
    if max(image_one.size) > max_image_size and additional_resize:
        resize_factor = max_image_size / max(image_one.size)
        image_one = image_one.resize((int(lower_boundary_size[0] * resize_factor),int(lower_boundary_size[1] * resize_factor)),resample=Image.LANCZOS)

        image_two = image_two.resize((int(lower_boundary_size[0] * resize_factor),resample=Image.LANCZOS)
    return image_one,image_two


def get_ssim_similarity(image_one_name,image_two_name,window_size=7,dynamic_range=255):
    """
    The Structural Similarity Index (SSIM) is a method for measuring the similarity between two images.
    The SSIM index can be viewed as a quality measure of one of the images being compared,provided the
    other image is regarded as of perfect quality.
    :param image_one_name: primary image to evaluate against a secondary image
    :param image_two_name: secondary image to evaluate against the primary image
    :param window_size: The side-length of the sliding window used in comparison. Must be an odd value.
    :param dynamic_range: Dynamic range of the input image,specified as a positive scalar.
    The default dynamic range is 255 for images of data type uint8.
    :return: computational score and image names
    """
    image_one = Image.open(image_one_name)
    image_two = Image.open(image_two_name)

    if min(list(image_one.size) + list(image_two.size)) < 7:
        raise Exception("One of the images was too small to process using the SSIM approach")
    image_one,image_two = pre_process_images(image_one,True)
    image_one,image_two = image_one.convert('I'),image_two.convert('I')
    c1 = (dynamic_range * 0.01) ** 2
    c2 = (dynamic_range * 0.03) ** 2
    pixel_length = window_size ** 2
    ssim = 0.0
    adjusted_width = image_one.size[0] // window_size * window_size
    adjusted_height = image_one.size[1] // window_size * window_size
    for i in range(0,adjusted_width,window_size):
        for j in range(0,adjusted_height,window_size):
            crop_box = (i,j,i + window_size,j + window_size)
            crop_box_one = image_one.crop(crop_box)
            crop_box_two = image_two.crop(crop_box)
            np_array_one,np_array_two = np.array(crop_box_one).flatten(),np.array(crop_box_two).flatten()
            np_variable_one,np_variable_two = np.var(np_array_one),np.var(np_array_two)
            np_average_one,np_average_two = np.average(np_array_one),np.average(np_array_two)
            cov = (np.sum(np_array_one * np_array_two) - (np.sum(np_array_one) *
                                                          np.sum(crop_box_two) / pixel_length)) / pixel_length
            ssim += ((2.0 * np_average_one * np_average_two + c1) * (2.0 * cov + c2)) / \
                    ((np_average_one ** 2 + np_average_two ** 2 + c1) * (np_variable_one + np_variable_two + c2))
    similarity_percent = (ssim * pixel_length / (adjusted_height * adjusted_width)) * 100
    return round(similarity_percent,2)


target_image = 'a.jpg'
image_directory = 'b_images'

images = get_image_files(image_directory)

for image in images:
    ssim_result = get_ssim_similarity(target_image,image)

我还建议查看 Python 模块 ImageHash。我有多个代码示例和测试用例 published here

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...