在 Python 中比 MSE 更好地比较图像的快速技术
Quick technique for comparing images better than MSE in Python
我一直在使用结构相似性指数(通过tensorflow)来比较图像,但是它花费的时间太长了。我想知道是否有一种不需要那么多时间的替代技术。如果有人能在 Python.
中指出比 tensorflow 更有效的 SSIM 实现,那也没关系
我使用 SSIM 的目的是,给定参考图像 (A) 和 组 图像 (B),我需要了解 B 中的哪个图像最多类似于参考图片A.
更新 01-02-2021
我决定探索其他一些可用于图像比较的 Python 模块。我也想用concurrent.futures,以前没用过
我用我写的代码创建了两个 GitGub Gists。
ImageHash aHash image comparison
ImageHash 模块能够在 0.29 秒内比较 100 张图像,而 skimage 模块用了 1.2 秒来完成相同的任务。
原版POST
我没有测试这个答案中代码的速度,因为我只在我发布到 GitHub:
的一些图像测试中使用了代码
下面的代码将生成参考图像 (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),
int(lower_boundary_size[1] * 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, image_two, 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. I have multiple code examples and test cases published here。
我一直在使用结构相似性指数(通过tensorflow)来比较图像,但是它花费的时间太长了。我想知道是否有一种不需要那么多时间的替代技术。如果有人能在 Python.
中指出比 tensorflow 更有效的 SSIM 实现,那也没关系我使用 SSIM 的目的是,给定参考图像 (A) 和 组 图像 (B),我需要了解 B 中的哪个图像最多类似于参考图片A.
更新 01-02-2021
我决定探索其他一些可用于图像比较的 Python 模块。我也想用concurrent.futures,以前没用过
我用我写的代码创建了两个 GitGub Gists。
ImageHash aHash image comparison
ImageHash 模块能够在 0.29 秒内比较 100 张图像,而 skimage 模块用了 1.2 秒来完成相同的任务。
原版POST
我没有测试这个答案中代码的速度,因为我只在我发布到 GitHub:
的一些图像测试中使用了代码下面的代码将生成参考图像 (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),
int(lower_boundary_size[1] * 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, image_two, 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. I have multiple code examples and test cases published here。